Here is the code, if you have any thoughts or suggestions, let me know. I want to wrap this up in the next week and try to push it to base build, so I can use it in my mods on next release.
Code: Select all
/// <summary>
/// Get LiveSpeed adjusted for swimming, walking, crouching or riding
/// </summary>
/// <returns>Speed based on player.Stats.LiveSpeed</returns>
public float GetBaseSpeed()
{
Entity.PlayerEntity player = GameManager.Instance.PlayerEntity;
float baseSpeed = 0;
float playerSpeed = player.Stats.LiveSpeed;
if (playerMotor == null) // fixes null reference bug.
playerMotor = GameManager.Instance.PlayerMotor;
// crouching speed penalty doesn't apply if swimming.
if (playerMotor.IsCrouching && !levitateMotor.IsSwimming)
baseSpeed = (playerSpeed + dfCrouchBase) / classicToUnitySpeedUnitRatio;
else if (playerMotor.IsRiding)
{
float rideSpeed = (GameManager.Instance.TransportManager.TransportMode == TransportModes.Cart) ? dfCartBase : dfRideBase;
baseSpeed = (playerSpeed + rideSpeed) / classicToUnitySpeedUnitRatio;
}
else
{
baseSpeed = walkSpeedOverride;
}
return baseSpeed;
}
/// <summary>
/// Add custom walk speed modifier to speed modifer dictionary. Returns unique ID for referencing of custom speedModifier for future manipulation.
/// </summary>
/// <param name="speedModifier">the amount to change players base walk speed by percentages. AKA, .75 will lower player movement by 25%. Using 0 or negatives will do nothing but return null.
/// <param name="refreshWalkSpeed">will cause routine to also update the player speed using the list to sequentially multiply the current base value by the list modifier values.</param>
/// <returns></returns>
public string AddWalkSpeedMod(float speedModifier = 0, bool refreshWalkSpeed = true)
{
string UUID = null;
//if they set a speed modifier, grab the list index using count, and add item (which will be at the lastID index spot).
if (speedModifier > 0)
{
UUID = System.Guid.NewGuid().ToString();
walkSpeedModifier.Add(UUID, speedModifier);
}
if(refreshWalkSpeed)
RefreshWalkSpeed();
return UUID;
}
/// <summary>
/// remove custom walk speed modifier from speed modifer dictionary using stored UID. Returns true if removed, false if not found.
/// </summary>
/// <param name="UUID">The Unique Universal ID created and provided when original value was added to dictionary.
/// <param name="refreshWalkSpeed">will cause routine to also update the player speed using the list to sequentially multiply the current base value by the list modifier values.</param>
/// <returns></returns>
public bool RemoveSpeedMod(string UUID, bool refreshWalkSpeed = true)
{
bool removed = false;
if (UUID == "" || UUID == null)
return removed;
if (walkSpeedModifier.ContainsKey(UUID))
{
walkSpeedModifier.Remove(UUID);
removed = true;
Debug.Log("removed: " + UUID);
}
if (refreshWalkSpeed)
RefreshWalkSpeed();
return removed;
}
/// <summary>
/// Updates the players walk speed using for loop and dictionary values to ensure proper sequential processing to get proper end speed.
/// Processing of modifiers is processed by their addition order. First added by modder is multiplied first, and so on.
/// </summary>
public void RefreshWalkSpeed()
{
float baseWalkSpeed = GetWalkSpeed(GameManager.Instance.PlayerEntity);
float overrideSpeed = 0;
if(walkSpeedModifier.Count == 0)
{
walkSpeedOverride = baseWalkSpeed;
return;
}
using (var modifierValue = walkSpeedModifier.GetEnumerator())
{
if (modifierValue.MoveNext())
{
overrideSpeed = baseWalkSpeed * modifierValue.Current.Value;
Debug.Log("First Modified: " + overrideSpeed);
while (modifierValue.MoveNext())
{
Debug.Log(modifierValue.Current.Key.ToString() + " Modified: " + overrideSpeed);
overrideSpeed = overrideSpeed * modifierValue.Current.Value;
}
}
}
walkSpeedOverride = overrideSpeed;
}
Here is how I use it between my two mods.
Interactive tile updates it on tile change. It has a string property to store the most recent unique ID number for the value it is shoving into the dictionary. Anytime a tile changes, it tries to remove the previous tile speed change by using the stored UID in the string property. If it's not made any changes yet, it will just return false and do nothing on remove. If it has pushed in a change with provided UID through the mod, SpeedChanger will remove it from the list and the new modifier is then added and UID is stored again by the mod for future manipulation.
Code: Select all
// Update is called once per frame
void Update()
{
if (OnTileChange())
{
List<float> TileProperties = TileProperty(lastTile);
movementModifier(TileProperties[0]);
Debug.Log("New Ground Tile: " + lastTile.ToString() + " | " + TileProperties[0].ToString());
}
}
void movementModifier(float moveModifier)
{
Debug.Log(playerSpeedChanger.RemoveSpeedMod(modiferValueID).ToString());
modiferValueID = playerSpeedChanger.AddWalkSpeedMod(moveModifier);
}
bool OnTileChange()
{
int currentTile = GameManager.Instance.StreamingWorld.PlayerTileMapIndex;
if (currentTile != lastTile)
{
lastTile = currentTile;
return true;
}
return false;
}
For ambidexterity mod, I use the same add, store UID in private mod string, and remove method. The only difference is since this is tied to player states, I had to throw in some quick, sloppy bool triggers to ensure it triggers once and doesn't keep adding and removing from the dictionary.
Code: Select all
//sets players current movement using overrides and override float values. Ensures triggered only once when setting values to save update cycles.
void movementModifier()
{
//the player isn't sheathed, idle, and player unsheathed override don't match current unsheathed movement calculated number, set unsheathed movement speed.
if(!GameManager.Instance.WeaponManager.Sheathed && AttackState == 0 && !restoreUnsheathed)
{
Debug.Log(playerSpeedChanger.RemoveSpeedMod(modiferValueID).ToString());
modiferValueID = playerSpeedChanger.AddWalkSpeedMod(.5f);
restoreUnsheathed = true;
restoredWalk = false;
return;
}
//if the player is attacking, and has unsheathed movement speed already set in override, set to attack movement speed.
if (AttackState != 0 && !GameManager.Instance.WeaponManager.Sheathed && !attackApplied)
{
Debug.Log(playerSpeedChanger.RemoveSpeedMod(modiferValueID).ToString());
modiferValueID = playerSpeedChanger.AddWalkSpeedMod(.25f);
attackApplied = true;
restoreUnsheathed = false;
return;
}
//if using override speeds and player is sheathed, flip off override and return to default/classic speeds.
if (GameManager.Instance.WeaponManager.Sheathed && !restoredWalk)
{
Debug.Log(playerSpeedChanger.RemoveSpeedMod(modiferValueID).ToString());
restoredWalk = true;
restoreUnsheathed = false;
return;
}
}