ModernUO/Projects/UOContent/Mobiles/Animals/Mounts/Kirin.cs
Kamron Batman 0f2870e94a
feat: Adds Stamina System to overhaul overweight. (#1465)
## Overhaul to Stamina (Overweight) System

### Added configurations

```json
{
  "settings": {
    "stamina.enableMountStamina": "True",
    "stamina.cannotMoveWhenFatigued": "True",
    "stamina.stonesPerOverweightLoss": "25",
    "stamina.stonesOverweightAllowance": "4",
    "stamina.baseOverweightLoss": "5",
    "stamina.additionalLossWhenBelow": "0.1",
    "stamina.mountLastMoveStepsReset": "01:00:00:00",
    "stamina.enableMountStamina": "True",
    "stamina.useMountStaminaOnlyWhenOverloaded": "False",
  },
}
```
- `stamina.cannotMoveWhenFatigued` - By default, Pre-AOS expansions will outright block a player if they are fatigued. A player is fatigued when they run out of stamina by any mechanism.
- `stamina.stonesPerOverweightLoss` - The amount of stamina lost for every X stones above overweight. Example, if a person is overweight 28 stones overweight, then there there is 1 additional stamina. 28 / 25 = 1 (no decimals, no rounding)
- `stamina.stonesOverweightAllowance` - The number of stones allowed before overweight penalties take affect. This _does not_ substract from the overweight stones calculation.
- `stamina.baseOverweightLoss` - The base amount of stamina loss for being overweight. While running, the final amount is multiplied by 2. If mount stamina is turned off, then the final amount is divided by 3 while mounted. 

### Mount stamina

Mounts have a new property `StepsMax` to determine the maximum steps they can take before being fatigued. To regain steps, the player _must stay on the mount and not move_ (per OSI). The gain rates are configurable. If a mount is dismounted, or the player logs off, the mount is considered inactive and mounts regain all of their steps after _24 hours_.

### Changes to player stamina

Players now have a proper inactivity time reset for their steps. If a player is idle for 16 seconds (including logging off, or the server being offline), then the steps counter is rest.

### Developer Notes

- `StepsTaken` - This field has been removed. It was not serialized and could not be used reliably. If a developer was using it, then the recommendation is to build a mechanism to track total steps another way.
- `IHasStamina` - This new interface was added and currently `IMount` and `PlayerMobile` are valid types.

Important: Entities that are sent to the StaminaSystem for tracking (mounts, players, or something else), must be an `ISerializable` to be serialized properly. If they are not, then the serialization system will record a null, and nothing will be deserialized upon world load. No errors will be given.
2023-09-16 17:52:54 -07:00

115 lines
3.9 KiB
C#

using ModernUO.Serialization;
using System;
using Server.Items;
namespace Server.Mobiles
{
[SerializationGenerator(0, false)]
public partial class Kirin : BaseMount
{
public override string DefaultName => "a ki-rin";
[Constructible]
public Kirin() : base(132, 0x3EAD, AIType.AI_Mage, FightMode.Evil)
{
BaseSoundID = 0x3C5;
SetStr(296, 325);
SetDex(86, 105);
SetInt(186, 225);
SetHits(191, 210);
SetDamage(16, 22);
SetDamageType(ResistanceType.Physical, 70);
SetDamageType(ResistanceType.Fire, 10);
SetDamageType(ResistanceType.Cold, 10);
SetDamageType(ResistanceType.Energy, 10);
SetResistance(ResistanceType.Physical, 55, 65);
SetResistance(ResistanceType.Fire, 35, 45);
SetResistance(ResistanceType.Cold, 25, 35);
SetResistance(ResistanceType.Poison, 25, 35);
SetResistance(ResistanceType.Energy, 25, 35);
SetSkill(SkillName.EvalInt, 80.1, 90.0);
SetSkill(SkillName.Magery, 60.4, 100.0);
SetSkill(SkillName.Meditation, 90.1, 100.0);
SetSkill(SkillName.MagicResist, 85.3, 100.0);
SetSkill(SkillName.Tactics, 20.1, 22.5);
SetSkill(SkillName.Wrestling, 80.5, 92.5);
Fame = 9000;
Karma = 9000;
Tamable = true;
ControlSlots = 2;
MinTameSkill = 95.1;
}
public override int StepsMax => 4480;
public override string CorpseName => "a ki-rin corpse";
public override bool AllowFemaleRider => false;
public override bool AllowFemaleTamer => false;
public override bool InitialInnocent => true;
public override TimeSpan MountAbilityDelay => TimeSpan.FromHours(1.0);
public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead;
public override int Meat => 3;
public override int Hides => 10;
public override HideType HideType => HideType.Horned;
public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay;
public override void OnDisallowedRider(Mobile m)
{
m.SendLocalizedMessage(1042319); // The Ki-Rin refuses your attempts to mount it.
}
public override bool DoMountAbility(int damage, Mobile attacker)
{
if (Rider == null || attacker == null) // sanity
{
return false;
}
// Range and map checked here instead of other base function because of abilities that don't need to check this
if (Rider.Hits - damage < 30 && Rider.Map == attacker.Map && Rider.InRange(attacker, 18))
{
attacker.BoltEffect(0);
// 35~100 damage, unresistable, by the Ki-rin.
// Don't inform mount about this damage, Still unsure whether or not it's flagged as the mount doing damage or the player.
// If changed to player, without the extra bool it'd be an infinite loop
attacker.Damage(Utility.RandomMinMax(35, 100), this, false);
// Your mount calls down the forces of nature on your opponent.
Rider.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1042534);
Rider.FixedParticles(0, 0, 0, 0x13A7, EffectLayer.Waist);
Rider.PlaySound(0xA9); // Ki-rin's whinny.
return true;
}
return false;
}
public override void GenerateLoot()
{
AddLoot(LootPack.Rich);
AddLoot(LootPack.LowScrolls);
AddLoot(LootPack.Potions);
}
public override void OnDeath(Container c)
{
base.OnDeath(c);
if (Utility.RandomDouble() < 0.35)
{
c.DropItem(new KirinBrains());
}
}
}
}