Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Source/ACE.Server/Command/Handlers/DeveloperCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2663,5 +2663,19 @@ public static void HandleRemoveVitae(Session session, params string[] parameters
if (player != session.Player)
session.Network.EnqueueSend(new GameMessageSystemChat("Removed vitae for {player.Name}", ChatMessageType.Broadcast));
}

[CommandHandler("fast", AccessLevel.Developer, CommandHandlerFlag.RequiresWorld)]
public static void HandleFast(Session session, params string[] parameters)
{
var spell = new Spell(SpellId.QuicknessSelf8);
session.Player.CreateEnchantment(session.Player, session.Player, spell);
}

[CommandHandler("slow", AccessLevel.Developer, CommandHandlerFlag.RequiresWorld)]
public static void HandleSlow(Session session, params string[] parameters)
{
var spell = new Spell(SpellId.SlownessSelf8);
session.Player.CreateEnchantment(session.Player, session.Player, spell);
}
}
}
44 changes: 36 additions & 8 deletions Source/ACE.Server/Entity/Spell.cs
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,33 @@ public bool HasItemCategory
}
}

/// <summary>
/// Returns TRUE for any spells which could potentially affect the run rate,
/// such as spells which alter run / quickness / strength
/// </summary>
public bool UpdatesRunRate
{
get
{
if (_spell == null)
return false;

// this is commented out as below in UpdatesMaxVitals
// i forget the exact reasoning, are all the proper hooks in places for each vitae %,
// and not just add/remove?
/*if (_spell.Id == 666) // vitae
return true;*/

if (StatModType.HasFlag(EnchantmentTypeFlags.Attribute) && (StatModKey == (uint)PropertyAttribute.Strength || StatModKey == (uint)PropertyAttribute.Quickness))
return true;

if (StatModType.HasFlag(EnchantmentTypeFlags.Skill) && StatModKey == (uint)Skill.Run)
return true;

return false;
}
}

/// <summary>
/// Returns a list of MaxVitals affected by this spell
/// </summary>
Expand All @@ -279,6 +306,15 @@ public List<PropertyAttribute2nd> UpdatesMaxVitals
if (_spell == null)
return maxVitals;

/*if (_spell.Id == 666) // Vitae
{
maxVitals.Add(PropertyAttribute2nd.MaxHealth);
maxVitals.Add(PropertyAttribute2nd.MaxStamina);
maxVitals.Add(PropertyAttribute2nd.MaxMana);

return maxVitals;
}*/

if (StatModType.HasFlag(EnchantmentTypeFlags.SecondAtt) && StatModKey != 0)
maxVitals.Add((PropertyAttribute2nd)StatModKey);

Expand All @@ -296,14 +332,6 @@ public List<PropertyAttribute2nd> UpdatesMaxVitals
break;
}
}

//if (_spell.Id == 666) // Vitae
//{
// maxVitals.Add(PropertyAttribute2nd.MaxHealth);
// maxVitals.Add(PropertyAttribute2nd.MaxStamina);
// maxVitals.Add(PropertyAttribute2nd.MaxMana);
//}

return maxVitals;
}
}
Expand Down
1 change: 1 addition & 0 deletions Source/ACE.Server/Managers/PropertyManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,7 @@ public static void LoadDefaultProperties()
("pk_server_safe_training_academy", new Property<bool>(false, "set this to TRUE to disable pk fighting in training academy and time to exit starter town safely")),
("pkl_server", new Property<bool>(false, "set this to TRUE for pink servers")),
("quest_info_enabled", new Property<bool>(false, "toggles the /myquests player command")),
("runrate_add_hooks", new Property<bool>(false, "if TRUE, adds some runrate hooks that were missing from retail (exhaustion done, raise skill/attribute")),
("require_spell_comps", new Property<bool>(true, "if FALSE spell components are no longer required to be in inventory to cast spells. defaults to enabled, as in retail")),
("salvage_handle_overages", new Property<bool>(false, "in retail, if 2 salvage bags were combined beyond 100 structure, the overages would be lost")),
("show_dot_messages", new Property<bool>(false, "enabled, shows combat messages for DoT damage ticks. defaults to disabled, as in retail")),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public static class GameActionMoveToState
public static void Handle(ClientMessage message, Session session)
{
var moveToState = new MoveToState(session.Player, message.Payload);
session.Player.CurrentMoveToState = moveToState;

session.Player.SetRequestedLocation(moveToState.Position);

Expand Down
5 changes: 5 additions & 0 deletions Source/ACE.Server/Network/Motion/InterpretedMotionState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ public MovementStateFlag BuildMovementFlags()

return flags;
}

public bool HasMovement()
{
return (ForwardCommand != MotionCommand.Invalid && ForwardCommand != MotionCommand.Ready) || TurnCommand != MotionCommand.Invalid || SidestepCommand != MotionCommand.Invalid;
}
}

public static class InterpretedMotionStateExtensions
Expand Down
2 changes: 2 additions & 0 deletions Source/ACE.Server/Network/Motion/MoveToState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ public class MoveToState
public bool Contact; // verify: contact (indicates if player is on ground), or sticky bit?
public bool StandingLongJump;

public MoveToState() { }

public MoveToState(WorldObject wo, BinaryReader reader)
{
WorldObject = wo;
Expand Down
4 changes: 3 additions & 1 deletion Source/ACE.Server/Network/Motion/MovementData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ public class MovementData
public TurnToObject TurnToObject;
public TurnToHeading TurnToHeading;

public MovementData() { }

public MovementData(WorldObject wo)
{
WorldObject = wo;
Expand All @@ -37,7 +39,7 @@ public MovementData(WorldObject wo)
public MovementData(WorldObject wo, Motion motion)
{
WorldObject = wo;
var sequence = wo.Sequences;
//var sequence = wo.Sequences;

// do this here, or in network writer?
IsAutonomous = motion.IsAutonomous;
Expand Down
11 changes: 6 additions & 5 deletions Source/ACE.Server/Physics/Animation/MotionTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ public class MotionTable
public Dictionary<uint, Dictionary<uint, MotionData>> Links;
public uint DefaultStyle;

public static Dictionary<uint, float> WalkSpeed;
public static Dictionary<uint, float> RunSpeed;
public static Dictionary<uint, float> TurnSpeed;
// TODO: use proper ConcurrentDictionary
public static Dictionary<uint, float> WalkSpeed { get; set; }
public static Dictionary<uint, float> RunSpeed { get; set; }
public static Dictionary<uint, float> TurnSpeed { get; set; }

static MotionTable()
{
Expand Down Expand Up @@ -499,7 +500,7 @@ public static float GetRunSpeed(uint motionTableID)
return 0.0f;

var speed = GetAnimDist(motionData);
RunSpeed.Add(motionTableID, speed);
RunSpeed[motionTableID] = speed;
return speed;
}

Expand All @@ -517,7 +518,7 @@ public static float GetTurnSpeed(uint motionTableID)
return 0.0f;

var speed = Math.Abs(motionData.Omega.Z);
TurnSpeed.Add(motionTableID, speed);
TurnSpeed[motionTableID] = speed;
return speed;
}

Expand Down
6 changes: 4 additions & 2 deletions Source/ACE.Server/WorldObjects/Creature_Vitals.cs
Original file line number Diff line number Diff line change
Expand Up @@ -197,11 +197,13 @@ public float GetStanceMod(CreatureVital vital)
// does not apply for mana?
if (vital.Vital == PropertyAttribute2nd.MaxMana) return 1.0f;

var forwardCommand = CurrentMovementData.MovementType == MovementType.Invalid ? CurrentMovementData.Invalid.State.ForwardCommand : MotionCommand.Invalid;

// combat mode / running
if (CombatMode != CombatMode.NonCombat || CurrentMotionCommand == MotionCommand.RunForward)
if (CombatMode != CombatMode.NonCombat || forwardCommand == MotionCommand.RunForward)
return 0.5f;

switch (CurrentMotionCommand)
switch (forwardCommand)
{
// TODO: verify multipliers
default:
Expand Down
17 changes: 0 additions & 17 deletions Source/ACE.Server/WorldObjects/Managers/EnchantmentManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -319,12 +319,6 @@ public virtual void Remove(BiotaPropertiesEnchantmentRegistry entry, bool sound

if (sound && entry.SpellCategory != SpellCategory_Cooldown)
Player.Session.Network.EnqueueSend(new GameMessageSound(Player.Guid, Sound.SpellExpire, 1.0f));

if (entry.SpellCategory != SpellCategory_Cooldown)
{
var spell = new Spell(spellID);
Player.HandleMaxVitalUpdate(spell);
}
}
else
{
Expand Down Expand Up @@ -472,12 +466,7 @@ public virtual void Dispel(BiotaPropertiesEnchantmentRegistry entry)
WorldObject.ChangesDetected = true;

if (Player != null)
{
Player.Session.Network.EnqueueSend(new GameEventMagicDispelEnchantment(Player.Session, (ushort)entry.SpellId, entry.LayerId));

var spell = new Spell(spellID);
Player.HandleMaxVitalUpdate(spell);
}
}

/// <summary>
Expand All @@ -492,12 +481,6 @@ public virtual void Dispel(List<BiotaPropertiesEnchantmentRegistry> entries)
{
if (WorldObject.Biota.TryRemoveEnchantment(entry, out _, WorldObject.BiotaDatabaseLock))
WorldObject.ChangesDetected = true;

if (Player != null)
{
var spell = new Spell(entry.SpellId);
Player.HandleMaxVitalUpdate(spell);
}
}
if (Player != null)
Player.Session.Network.EnqueueSend(new GameEventMagicDispelMultipleEnchantments(Player.Session, entries));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ public override void Remove(BiotaPropertiesEnchantmentRegistry entry, bool sound
base.Remove(entry, sound);

ClearCache();

if (entry.SpellCategory != SpellCategory_Cooldown)
{
var spell = new Spell(entry.SpellId);
Player.HandleSpellHooks(spell);
}
}

/// <summary>
Expand Down Expand Up @@ -99,6 +105,12 @@ public override void Dispel(BiotaPropertiesEnchantmentRegistry entry)
base.Dispel(entry);

ClearCache();

if (Player != null)
{
var spell = new Spell(entry.SpellId);
Player.HandleSpellHooks(spell);
}
}

/// <summary>
Expand All @@ -109,6 +121,15 @@ public override void Dispel(List<BiotaPropertiesEnchantmentRegistry> entries)
base.Dispel(entries);

ClearCache();

if (Player != null)
{
foreach (var entry in entries)
{
var spell = new Spell(entry.SpellId);
Player.HandleSpellHooks(spell);
}
}
}


Expand Down
18 changes: 17 additions & 1 deletion Source/ACE.Server/WorldObjects/Monster_Navigation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -349,8 +349,24 @@ public void GetMovementSpeed()
/// </summary>
public float GetRunRate()
{
var burden = 0.0f;

// assuming burden only applies to players...
if (this is Player player)
{
var strength = Strength.Current;

var capacity = EncumbranceSystem.EncumbranceCapacity((int)strength, player.AugmentationIncreasedCarryingCapacity);
burden = EncumbranceSystem.GetBurden(capacity, EncumbranceVal ?? 0);

// TODO: find this exact formula in client
// technically this would be based on when the player releases / presses the movement key after stamina > 0
if (player.IsExhausted)
burden = 3.0f;
}

var runSkill = GetCreatureSkill(Skill.Run).Current;
var runRate = MovementSystem.GetRunRate(0.0f, (int)runSkill, 1.0f);
var runRate = MovementSystem.GetRunRate(burden, (int)runSkill, 1.0f);

return (float)runRate;
}
Expand Down
56 changes: 44 additions & 12 deletions Source/ACE.Server/WorldObjects/Player.cs
Original file line number Diff line number Diff line change
Expand Up @@ -753,22 +753,54 @@ public void HandleActionJump(JumpPack jump)
/// </summary>
public void OnExhausted()
{
// adjust player speed if running
if (CurrentMotionCommand == MotionCommand.RunForward && !IsJumping)
{
// verify - forced commands from server should be non-autonomous, but could have been sent as autonomous in retail?
// if set to autonomous here, the desired effect doesn't happen
// motion.IsAutonomous = true;
var motion = new Motion(this, MotionCommand.RunForward);

CurrentMotionState = motion;
// adjust player speed if they are currently pressing movement keys
HandleRunRateUpdate();

if (CurrentLandblock != null)
EnqueueBroadcastMotion(motion);
}
Session.Network.EnqueueSend(new GameEventCommunicationTransientString(Session, "You're Exhausted!"));
}

/// <summary>
/// Detects changes in the player's RunRate --
/// If there are changes, re-broadcasts player movement packet
/// </summary>
public bool HandleRunRateUpdate()
{
//Console.WriteLine($"{Name}.HandleRunRateUpdates()");

if (CurrentMovementData.MovementType != MovementType.Invalid)
return false;

var prevState = CurrentMovementData.Invalid.State;

var movementData = new MovementData(this, CurrentMoveToState);
var currentState = movementData.Invalid.State;

var changed = currentState.ForwardSpeed != prevState.ForwardSpeed ||
currentState.TurnSpeed != prevState.TurnSpeed ||
currentState.SidestepSpeed != prevState.SidestepSpeed;

if (!changed)
return false;

//Console.WriteLine($"Old: {prevState.ForwardSpeed}, New: {currentState.ForwardSpeed}");

if (!CurrentMovementData.Invalid.State.HasMovement() || IsJumping)
return false;

//Console.WriteLine($"{Name}.OnRunRateChanged()");

CurrentMovementData = new MovementData(this, CurrentMoveToState);

// verify - forced commands from server should be non-autonomous, but could have been sent as autonomous in retail?
// if set to autonomous here, the desired effect doesn't happen
CurrentMovementData.IsAutonomous = false;

var movementEvent = new GameMessageUpdateMotion(this, CurrentMovementData);
EnqueueBroadcast(movementEvent); // broadcast to all players, including self

return true;
}

/// <summary>
/// Returns a modifier for a player's Run, Jump, Melee Defense, and Missile Defense skills if they are overburdened
/// </summary>
Expand Down
5 changes: 5 additions & 0 deletions Source/ACE.Server/WorldObjects/Player_Attributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using ACE.DatLoader;
using ACE.Entity.Enum;
using ACE.Entity.Enum.Properties;
using ACE.Server.Managers;
using ACE.Server.Network;
using ACE.Server.Network.GameMessages;
using ACE.Server.Network.GameMessages.Messages;
Expand Down Expand Up @@ -55,6 +56,10 @@ public void RaiseAttributeGameAction(PropertyAttribute attribute, uint amount)
{
Session.Network.EnqueueSend(abilityUpdate, soundEvent, message);
}

// retail was missing the 'raise attribute' runrate hook here
if ((attribute == PropertyAttribute.Strength || attribute == PropertyAttribute.Quickness) && PropertyManager.GetBool("runrate_add_hooks").Item)
HandleRunRateUpdate();
}
else
{
Expand Down
Loading