fix: Removes scale speed by dex for monsters, fixes NPC movement/thinking speed (#1019)
* Removes scaled speed by dex for monsters * Changes scaled speed by dex for pets (HS+ expansion) to be 400ms -> 100ms between 50 -> 200 dex * Removes speed changes that were broken for various mobs * Combines "Legacy" speed and renames the class to `NPCSpeeds` * Creates speed "classes" (slow, medium, fast, very fast) * Introduces a new overridable property `SpeedClass`. Register a new speed class using `NPCSpeeds.Register()` and then set the speed class to bulk/mass apply speeds. Order of speed determination: 1. SpeedMod 2. SpeedClass property (not null) 3. SpeedClass entry in Data\npc-speeds.json for that type 4. "Fast" (200ms Active, 400ms Passive)
This commit is contained in:
parent
6ec84b3c01
commit
eee8494558
74 changed files with 477 additions and 472 deletions
|
|
@ -338,12 +338,7 @@ namespace Server.Mobiles
|
|||
|
||||
FightMode = mode;
|
||||
|
||||
if (LegacySpeedInfo.Enabled && LegacySpeedInfo.GetSpeeds(GetType(), out var activeSpeed, out var passiveSpeed))
|
||||
{
|
||||
ActiveSpeed = activeSpeed;
|
||||
PassiveSpeed = passiveSpeed;
|
||||
CurrentSpeed = passiveSpeed;
|
||||
}
|
||||
ResetSpeeds();
|
||||
|
||||
m_Team = 0;
|
||||
|
||||
|
|
@ -879,6 +874,8 @@ namespace Server.Mobiles
|
|||
public virtual bool ReturnsToHome =>
|
||||
SeeksHome && Home != Point3D.Zero && !m_ReturnQueued && !Controlled && !Summoned;
|
||||
|
||||
public virtual bool ScaleSpeedByDex => NPCSpeeds.ScaleSpeedByDex && !IsMonster;
|
||||
|
||||
// used for deleting untamed creatures [in houses]
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool RemoveIfUntamed { get; set; }
|
||||
|
|
@ -1363,7 +1360,8 @@ namespace Server.Mobiles
|
|||
|
||||
public override void OnRawDexChange(int oldValue)
|
||||
{
|
||||
if (oldValue != RawDex && ActiveSpeed <= 0 && PassiveSpeed <= 0)
|
||||
// This only really happens for pets or when a GM modifies a mob.
|
||||
if (oldValue != RawDex && ScaleSpeedByDex)
|
||||
{
|
||||
ResetSpeeds();
|
||||
}
|
||||
|
|
@ -1627,23 +1625,35 @@ namespace Server.Mobiles
|
|||
switch (sc)
|
||||
{
|
||||
case ScaleType.Red:
|
||||
corpse.AddCarvedItem(new RedScales(scales), from);
|
||||
break;
|
||||
{
|
||||
corpse.AddCarvedItem(new RedScales(scales), from);
|
||||
break;
|
||||
}
|
||||
case ScaleType.Yellow:
|
||||
corpse.AddCarvedItem(new YellowScales(scales), from);
|
||||
break;
|
||||
{
|
||||
corpse.AddCarvedItem(new YellowScales(scales), from);
|
||||
break;
|
||||
}
|
||||
case ScaleType.Black:
|
||||
corpse.AddCarvedItem(new BlackScales(scales), from);
|
||||
break;
|
||||
{
|
||||
corpse.AddCarvedItem(new BlackScales(scales), from);
|
||||
break;
|
||||
}
|
||||
case ScaleType.Green:
|
||||
corpse.AddCarvedItem(new GreenScales(scales), from);
|
||||
break;
|
||||
{
|
||||
corpse.AddCarvedItem(new GreenScales(scales), from);
|
||||
break;
|
||||
}
|
||||
case ScaleType.White:
|
||||
corpse.AddCarvedItem(new WhiteScales(scales), from);
|
||||
break;
|
||||
{
|
||||
corpse.AddCarvedItem(new WhiteScales(scales), from);
|
||||
break;
|
||||
}
|
||||
case ScaleType.Blue:
|
||||
corpse.AddCarvedItem(new BlueScales(scales), from);
|
||||
break;
|
||||
{
|
||||
corpse.AddCarvedItem(new BlueScales(scales), from);
|
||||
break;
|
||||
}
|
||||
case ScaleType.All:
|
||||
{
|
||||
corpse.AddCarvedItem(new RedScales(scales), from);
|
||||
|
|
@ -2567,18 +2577,23 @@ namespace Server.Mobiles
|
|||
return false; // not idling, but don't want to enter idle state
|
||||
}
|
||||
|
||||
m_IdleReleaseTime = Core.Now + TimeSpan.FromSeconds(Utility.RandomMinMax(15, 25));
|
||||
var idleSeconds = Utility.RandomMinMax(NPCSpeeds.MinIdleSeconds, NPCSpeeds.MaxIdleSeconds);
|
||||
m_IdleReleaseTime = Core.Now + TimeSpan.FromSeconds(idleSeconds);
|
||||
|
||||
if (Body.IsHuman)
|
||||
{
|
||||
switch (Utility.Random(2))
|
||||
{
|
||||
case 0:
|
||||
CheckedAnimate(5, 5, 1, true, true, 1);
|
||||
break;
|
||||
{
|
||||
CheckedAnimate(5, 5, 1, true, true, 1);
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
CheckedAnimate(6, 5, 1, true, false, 1);
|
||||
break;
|
||||
{
|
||||
CheckedAnimate(6, 5, 1, true, false, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Body.IsAnimal)
|
||||
|
|
@ -2586,14 +2601,20 @@ namespace Server.Mobiles
|
|||
switch (Utility.Random(3))
|
||||
{
|
||||
case 0:
|
||||
CheckedAnimate(3, 3, 1, true, false, 1);
|
||||
break;
|
||||
{
|
||||
CheckedAnimate(3, 3, 1, true, false, 1);
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
CheckedAnimate(9, 5, 1, true, false, 1);
|
||||
break;
|
||||
{
|
||||
CheckedAnimate(9, 5, 1, true, false, 1);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
CheckedAnimate(10, 5, 1, true, false, 1);
|
||||
break;
|
||||
{
|
||||
CheckedAnimate(10, 5, 1, true, false, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Body.IsMonster)
|
||||
|
|
@ -2601,11 +2622,15 @@ namespace Server.Mobiles
|
|||
switch (Utility.Random(2))
|
||||
{
|
||||
case 0:
|
||||
CheckedAnimate(17, 5, 1, true, false, 1);
|
||||
break;
|
||||
{
|
||||
CheckedAnimate(17, 5, 1, true, false, 1);
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
CheckedAnimate(18, 5, 1, true, false, 1);
|
||||
break;
|
||||
{
|
||||
CheckedAnimate(18, 5, 1, true, false, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2862,17 +2887,25 @@ namespace Server.Mobiles
|
|||
switch (Utility.Random(4))
|
||||
{
|
||||
case 0:
|
||||
PackItem(new CocoaButter());
|
||||
break;
|
||||
{
|
||||
PackItem(new CocoaButter());
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
PackItem(new CocoaLiquor());
|
||||
break;
|
||||
{
|
||||
PackItem(new CocoaLiquor());
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
PackItem(new SackOfSugar());
|
||||
break;
|
||||
{
|
||||
PackItem(new SackOfSugar());
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
PackItem(new Vanilla());
|
||||
break;
|
||||
{
|
||||
PackItem(new Vanilla());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3323,11 +3356,6 @@ namespace Server.Mobiles
|
|||
Controlled = false;
|
||||
ControlTarget = null;
|
||||
ControlOrder = OrderType.None;
|
||||
Guild = null;
|
||||
|
||||
ResetSpeeds();
|
||||
|
||||
Delta(MobileDelta.Noto);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -3351,19 +3379,20 @@ namespace Server.Mobiles
|
|||
Controlled = true;
|
||||
ControlTarget = null;
|
||||
ControlOrder = OrderType.Come;
|
||||
Guild = null;
|
||||
|
||||
|
||||
if (m_DeleteTimer != null)
|
||||
{
|
||||
m_DeleteTimer.Stop();
|
||||
m_DeleteTimer = null;
|
||||
}
|
||||
|
||||
ResetSpeeds(true);
|
||||
|
||||
Delta(MobileDelta.Noto);
|
||||
}
|
||||
|
||||
Guild = null;
|
||||
ResetSpeeds();
|
||||
|
||||
Delta(MobileDelta.Noto);
|
||||
|
||||
InvalidateProperties();
|
||||
|
||||
return true;
|
||||
|
|
@ -3953,20 +3982,30 @@ namespace Server.Mobiles
|
|||
switch (Utility.Random(5))
|
||||
{
|
||||
case 0:
|
||||
physDamage += BreathChaosDamage;
|
||||
break;
|
||||
{
|
||||
physDamage += BreathChaosDamage;
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
fireDamage += BreathChaosDamage;
|
||||
break;
|
||||
{
|
||||
fireDamage += BreathChaosDamage;
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
coldDamage += BreathChaosDamage;
|
||||
break;
|
||||
{
|
||||
coldDamage += BreathChaosDamage;
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
poisDamage += BreathChaosDamage;
|
||||
break;
|
||||
{
|
||||
poisDamage += BreathChaosDamage;
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
nrgyDamage += BreathChaosDamage;
|
||||
break;
|
||||
{
|
||||
nrgyDamage += BreathChaosDamage;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4620,20 +4659,30 @@ namespace Server.Mobiles
|
|||
switch (type)
|
||||
{
|
||||
case ResistanceType.Physical:
|
||||
PhysicalDamage = val;
|
||||
break;
|
||||
{
|
||||
PhysicalDamage = val;
|
||||
break;
|
||||
}
|
||||
case ResistanceType.Fire:
|
||||
FireDamage = val;
|
||||
break;
|
||||
{
|
||||
FireDamage = val;
|
||||
break;
|
||||
}
|
||||
case ResistanceType.Cold:
|
||||
ColdDamage = val;
|
||||
break;
|
||||
{
|
||||
ColdDamage = val;
|
||||
break;
|
||||
}
|
||||
case ResistanceType.Poison:
|
||||
PoisonDamage = val;
|
||||
break;
|
||||
{
|
||||
PoisonDamage = val;
|
||||
break;
|
||||
}
|
||||
case ResistanceType.Energy:
|
||||
EnergyDamage = val;
|
||||
break;
|
||||
{
|
||||
EnergyDamage = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4647,20 +4696,30 @@ namespace Server.Mobiles
|
|||
switch (type)
|
||||
{
|
||||
case ResistanceType.Physical:
|
||||
m_PhysicalResistance = val;
|
||||
break;
|
||||
{
|
||||
m_PhysicalResistance = val;
|
||||
break;
|
||||
}
|
||||
case ResistanceType.Fire:
|
||||
m_FireResistance = val;
|
||||
break;
|
||||
{
|
||||
m_FireResistance = val;
|
||||
break;
|
||||
}
|
||||
case ResistanceType.Cold:
|
||||
m_ColdResistance = val;
|
||||
break;
|
||||
{
|
||||
m_ColdResistance = val;
|
||||
break;
|
||||
}
|
||||
case ResistanceType.Poison:
|
||||
m_PoisonResistance = val;
|
||||
break;
|
||||
{
|
||||
m_PoisonResistance = val;
|
||||
break;
|
||||
}
|
||||
case ResistanceType.Energy:
|
||||
m_EnergyResistance = val;
|
||||
break;
|
||||
{
|
||||
m_EnergyResistance = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateResistances();
|
||||
|
|
@ -4794,9 +4853,17 @@ namespace Server.Mobiles
|
|||
}
|
||||
}
|
||||
|
||||
public virtual void ResetSpeeds(bool currentUseActive = false)
|
||||
// If this needs to be serialized, recommend creating a hash or registry id. Don't serialize strings.
|
||||
public virtual string SpeedClass => null;
|
||||
|
||||
public virtual void GetSpeeds(out double activeSpeed, out double passiveSpeed)
|
||||
{
|
||||
SpeedInfo.GetSpeeds(this, out var activeSpeed, out var passiveSpeed);
|
||||
NPCSpeeds.GetSpeeds(this, out activeSpeed, out passiveSpeed);
|
||||
}
|
||||
|
||||
public void ResetSpeeds(bool currentUseActive = false)
|
||||
{
|
||||
GetSpeeds(out var activeSpeed, out var passiveSpeed);
|
||||
|
||||
ActiveSpeed = activeSpeed;
|
||||
PassiveSpeed = passiveSpeed;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue