project-meteor-server/FFXIVClassic Map Server/actors/chara/ai/StatusEffect.cs
yogurt b8d6a943aa Combat changes and bug fixes
Added the combo and proc systems
Added scripts for most weaponskill and spells as well as some abilities and status effects
Added support for multihit attacks
Added AbilityState for abilities
Added hiteffects that change based on an attack's parameters
Added positionals

Changed how targeting works for battlecommands

Fixed bug that occurred when moving or swapping hotbar commands
Fixed bug that occurred when losing status effects
2018-02-15 13:20:46 -06:00

628 lines
18 KiB
C#

using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.lua;
using FFXIVClassic_Map_Server.packets.send.actor;
using FFXIVClassic_Map_Server.packets.send.actor.battle;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MoonSharp.Interpreter;
namespace FFXIVClassic_Map_Server.actors.chara.ai
{
enum StatusEffectId : uint
{
RageofHalone = 221021,
Quick = 223001,
Haste = 223002,
Slow = 223003,
Petrification = 223004,
Paralysis = 223005,
Silence = 223006,
Blind = 223007,
Mute = 223008,
Slowcast = 223009,
Glare = 223010,
Poison = 223011,
Transfixion = 223012,
Pacification = 223013,
Amnesia = 223014,
Stun = 223015,
Daze = 223016,
ExposedFront = 223017,
ExposedRight = 223018,
ExposedRear = 223019,
ExposedLeft = 223020,
Incapacitation = 223021,
Incapacitation2 = 223022,
Incapacitation3 = 223023,
Incapacitation4 = 223024,
Incapacitation5 = 223025,
Incapacitation6 = 223026,
Incapacitation7 = 223027,
Incapacitation8 = 223028,
HPBoost = 223029,
HPPenalty = 223030,
MPBoost = 223031,
MPPenalty = 223032,
AttackUp = 223033,
AttackDown = 223034,
AccuracyUp = 223035,
AccuracyDown = 223036,
DefenseUp = 223037,
DefenseDown = 223038,
EvasionUp = 223039,
EvasionDown = 223040,
MagicPotencyUp = 223041,
MagicPotencyDown = 223042,
MagicAccuracyUp = 223043,
MagicAccuracyDown = 223044,
MagicDefenseUp = 223045,
MagicDefenseDown = 223046,
MagicResistanceUp = 223047,
MagicResistanceDown = 223048,
CombatFinesse = 223049,
CombatHindrance = 223050,
MagicFinesse = 223051,
MagicHindrance = 223052,
CombatResilience = 223053,
CombatVulnerability = 223054,
MagicVulnerability = 223055,
MagicResilience = 223056,
Inhibited = 223057,
AegisBoon = 223058,
Deflection = 223059,
Outmaneuver = 223060,
Provoked = 223061,
Sentinel = 223062,
Cover = 223063,
Rampart = 223064,
StillPrecision = 223065,
Cadence = 223066,
DiscerningEye = 223067,
TemperedWill = 223068,
Obsess = 223069,
Ambidexterity = 223070,
BattleCalm = 223071,
MasterofArms = 223072,
Taunted = 223073,
Blindside = 223074,
Featherfoot = 223075,
PresenceofMind = 223076,
CoeurlStep = 223077,
EnduringMarch = 223078,
MurderousIntent = 223079,
Entrench = 223080,
Bloodbath = 223081,
Retaliation = 223082,
Foresight = 223083,
Defender = 223084,
Rampage = 223085,
Enraged = 223086,
Warmonger = 223087,
Disorientx1 = 223088,
Disorientx2 = 223089,
Disorientx3 = 223090,
KeenFlurry = 223091,
ComradeinArms = 223092,
Ferocity = 223093,
Invigorate = 223094,
LineofFire = 223095,
Jump = 223096,
Collusion = 223097,
Diversion = 223098,
SpeedSurge = 223099,
LifeSurge = 223100,
SpeedSap = 223101,
LifeSap = 223102,
Farshot = 223103,
QuellingStrike = 223104,
RagingStrike = 223105,
HawksEye = 223106,
SubtleRelease = 223107,
Decoy = 223108,
Profundity = 223109,
TranceChant = 223110,
RoamingSoul = 223111,
Purge = 223112,
Spiritsong = 223113,
Resonance = 223114,
Soughspeak = 223115,
PresenceofMind2 = 223116,
SanguineRite = 223117,
PunishingBarbs = 223118,
DarkSeal = 223119,
Emulate = 223120,
ParadigmShift = 223121,
ConcussiveBlowx1 = 223123,
ConcussiveBlowx2 = 223124,
ConcussiveBlowx3 = 223125,
SkullSunder = 223126,
Bloodletter = 223127,
Levinbolt = 223128,
Protect = 223129,
Shell = 223130,
Reraise = 223131,
ShockSpikes = 223132,
Stoneskin = 223133,
Scourge = 223134,
Bio = 223135,
Dia = 223136,
Banish = 223137,
StygianSpikes = 223138,
ATKAbsorbed = 223139,
DEFAbsorbed = 223140,
ACCAbsorbed = 223141,
EVAAbsorbed = 223142,
AbsorbATK = 223143,
AbsorbDEF = 223144,
AbsorbACC = 223145,
AbsorbEVA = 223146,
SoulWard = 223147,
Burn = 223148,
Frost = 223149,
Shock = 223150,
Drown = 223151,
Choke = 223152,
Rasp = 223153,
Flare = 223154,
Freeze = 223155,
Burst = 223156,
Flood = 223157,
Tornado = 223158,
Quake = 223159,
Berserk = 223160,
RegimenofRuin = 223161,
RegimenofTrauma = 223162,
RegimenofDespair = 223163,
RegimenofConstraint = 223164,
Weakness = 223165,
Scavenge = 223166,
Fastcast = 223167,
MidnightHowl = 223168,
Outlast = 223169,
Steadfast = 223170,
DoubleNock = 223171,
TripleNock = 223172,
Covered = 223173,
PerfectDodge = 223174,
ExpertMining = 223175,
ExpertLogging = 223176,
ExpertHarvesting = 223177,
ExpertFishing = 223178,
ExpertSpearfishing = 223179,
Regen = 223180,
Refresh = 223181,
Regain = 223182,
TPBleed = 223183,
Empowered = 223184,
Imperiled = 223185,
Adept = 223186,
Inept = 223187,
Quick2 = 223188,
Quick3 = 223189,
WristFlick = 223190,
Glossolalia = 223191,
SonorousBlast = 223192,
Comradery = 223193,
StrengthinNumbers = 223194,
BrinkofDeath = 223197,
CraftersGrace = 223198,
GatherersGrace = 223199,
Rebirth = 223200,
Stealth = 223201,
StealthII = 223202,
StealthIII = 223203,
StealthIV = 223204,
Combo = 223205,
GoringBlade = 223206,
Berserk2 = 223207,
Rampage2 = 223208,
FistsofFire = 223209,
FistsofEarth = 223210,
FistsofWind = 223211,
PowerSurgeI = 223212,
PowerSurgeII = 223213,
PowerSurgeIII = 223214,
LifeSurgeI = 223215,
LifeSurgeII = 223216,
LifeSurgeIII = 223217,
DreadSpike = 223218,
BloodforBlood = 223219,
Barrage = 223220,
RagingStrike2 = 223221,
Swiftsong = 223224,
SacredPrism = 223225,
ShroudofSaints = 223226,
ClericStance = 223227,
BlissfulMind = 223228,
DarkSeal2 = 223229,
Resonance2 = 223230,
Excruciate = 223231,
Necrogenesis = 223232,
Parsimony = 223233,
SanguineRite2 = 223234,
Aero = 223235,
Outmaneuver2 = 223236,
Blindside2 = 223237,
Decoy2 = 223238,
Protect2 = 223239,
SanguineRite3 = 223240,
Bloodletter2 = 223241,
FullyBlissfulMind = 223242,
MagicEvasionDown = 223243,
HundredFists = 223244,
SpinningHeel = 223245,
DivineVeil = 223248,
HallowedGround = 223249,
Vengeance = 223250,
Antagonize = 223251,
MightyStrikes = 223252,
BattleVoice = 223253,
BalladofMagi = 223254,
PaeonofWar = 223255,
MinuetofRigor = 223256,
GoldLung = 223258,
Goldbile = 223259,
AurumVeil = 223260,
AurumVeilII = 223261,
Flare2 = 223262,
Resting = 223263,
DivineRegen = 223264,
DefenseAndEvasionUp = 223265,
MagicDefenseAndEvasionUp = 223266,
AttackUp2 = 223267,
MagicPotencyUp2 = 223268,
DefenseAndEvasionDown = 223269,
MagicDefenseAndEvasionDown = 223270,
Poison2 = 223271,
DeepBurn = 223272,
LunarCurtain = 223273,
DefenseUp2 = 223274,
AttackDown2 = 223275,
Sanction = 223992,
IntactPodlingToting = 223993,
RedRidingHooded = 223994,
Medicated = 223998,
WellFed = 223999,
Sleep = 228001,
Bind = 228011,
Fixation = 228012,
Bind2 = 228013,
Heavy = 228021,
Charm = 228031,
Flee = 228041,
Doom = 228051,
SynthesisSupport = 230001,
WoodyardAccess = 230002,
SmithsForgeAccess = 230003,
ArmorersForgeAccess = 230004,
GemmaryAccess = 230005,
TanneryAccess = 230006,
ClothshopAccess = 230007,
LaboratoryAccess = 230008,
CookeryAccess = 230009,
MinersSupport = 230010,
BotanistsSupport = 230011,
FishersSupport = 230012,
GearChange = 230013,
GearDamage = 230014,
HeavyGearDamage = 230015,
Lamed = 230016,
Lamed2 = 230017,
Lamed3 = 230018,
Poison3 = 231002,
Envenom = 231003,
Berserk4 = 231004,
GuardiansAspect = 253002,
// custom effects here
// status for having procs fall off
EvadeProc = 253003,
BlockProc = 253004,
ParryProc = 253005,
MissProc = 253006
}
[Flags]
enum StatusEffectFlags : uint
{
None = 0,
Silent = 1 << 0, // dont display effect loss message
//Loss flags
LoseOnDeath = 1 << 1, // effects removed on death
LoseOnZoning = 1 << 2, // effects removed on zoning
LoseOnEsuna = 1 << 3, // effects which can be removed with esuna (debuffs)
LoseOnDispel = 1 << 4, // some buffs which player might be able to dispel from mob
LoseOnLogout = 1 << 5, // effects removed on logging out
LoseOnAttacking = 1 << 6, // effects removed when owner attacks another entity
LoseOnCasting = 1 << 7, // effects removed when owner starts casting
LoseOnDamageTaken = 1 << 8, // effects removed when owner takes damage
LoseOnParry = 1 << 9, // effects removed when owner parries an attack (foresight)
LoseOnEvade = 1 << 10, // effects removed when owner evades an attack (decoy)
LoseOnCrit = 1 << 11, // effects removed when owner deals a critical hit (excruciate)
LoseOnAggro = 1 << 12, // effects removed when owner gains enmity (swiftsong)
//Activate flags, do we need the LoseOn flags if we have these? could just remove itself in the activate function
ActivateOnAttack = 1 << 13,
ActivateOnSpell = 1 << 14,
ActivateOnDamageTaken = 1 << 15,
ActivateOnBlock = 1 << 16,
ActivateOnMiss = 1 << 17,
//Prevent flags. Sleep/stun/petrify/etc combine these
PreventSpell= 1 << 18, // effects which prevent using spells, such as silence
PreventWeaponSkill = 1 << 19, // effects which prevent using weaponskills, such as pacification
PreventAbility = 1 << 20, // effects which prevent using abilities, such as amnesia
PreventAttack = 1 << 21, // effects which prevent basic attacks
PreventMovement = 1 << 22, // effects which prevent movement such as bind, still allows turning in place
PreventTurn = 1 << 23, // effects which prevent turning such as fixation, still allows movement and actions
Stealth = 1 << 24, // sneak/invis
Stance = 1 << 25, // effects that do not have a timer
}
enum StatusEffectOverwrite : byte
{
None,
Always,
GreaterOrEqualTo,
GreaterOnly,
}
class StatusEffect
{
// todo: probably use get;set;
private Character owner;
private Character source;
private StatusEffectId id;
private string name; // name of this effect
private DateTime startTime; // when was this effect added
private DateTime lastTick; // when did this effect last tick
private uint duration; // how long should this effect last in seconds
private uint tickMs; // how often should this effect proc
private UInt64 magnitude; // a value specified by scripter which is guaranteed to be used by all effects
private byte tier; // same effect with higher tier overwrites this
private UInt64 extra; // optional value
private StatusEffectFlags flags; // death/erase/dispel etc
private StatusEffectOverwrite overwrite; // how to handle adding an effect with same id (see StatusEfectOverwrite)
private bool silent = false; // do i send a message on losing effect
private bool hidden = false;
public LuaScript script;
HitEffect animationEffect;
public StatusEffect(Character owner, uint id, UInt64 magnitude, uint tickMs, uint duration, byte tier = 0)
{
this.owner = owner;
this.source = owner;
this.id = (StatusEffectId)id;
this.magnitude = magnitude;
this.tickMs = tickMs;
this.duration = duration;
this.tier = tier;
this.startTime = DateTime.Now;
this.lastTick = startTime;
}
public StatusEffect(Character owner, StatusEffect effect)
{
this.owner = owner;
this.source = owner;
this.id = effect.id;
this.magnitude = effect.magnitude;
this.tickMs = effect.tickMs;
this.duration = effect.duration;
this.tier = effect.tier;
this.startTime = effect.startTime;
this.lastTick = effect.lastTick;
this.name = effect.name;
this.flags = effect.flags;
this.overwrite = effect.overwrite;
this.extra = effect.extra;
this.script = effect.script;
}
public StatusEffect(uint id, string name, uint flags, uint overwrite, uint tickMs)
{
this.id = (StatusEffectId)id;
this.name = name;
this.flags = (StatusEffectFlags)flags;
this.overwrite = (StatusEffectOverwrite)overwrite;
this.tickMs = tickMs;
}
// return true when duration has elapsed
public bool Update(DateTime tick)
{
if (tickMs != 0 && (tick - lastTick).TotalMilliseconds >= tickMs)
{
lastTick = tick;
LuaEngine.CallLuaStatusEffectFunction(this.owner, this, "onTick", this.owner, this);
}
if (duration != 0xFFFFFFFF && (tick - startTime).TotalSeconds >= duration)
{
return true;
}
return false;
}
public int CallLuaFunction(Character chara, string functionName, params object[] args)
{
DynValue res = new DynValue();
if (!script.Globals.Get(functionName).IsNil())
{
res = script.Call(script.Globals.Get(functionName), args);
if (res != null)
return (int)res.Number;
}
return -1;
}
public Character GetOwner()
{
return owner;
}
public Character GetSource()
{
return source ?? owner;
}
public uint GetStatusEffectId()
{
return (uint)id;
}
public ushort GetStatusId()
{
return (ushort)(id - 200000);
}
public DateTime GetStartTime()
{
return startTime;
}
public string GetName()
{
return name;
}
public uint GetDuration()
{
return duration;
}
public uint GetTickMs()
{
return tickMs;
}
public UInt64 GetMagnitude()
{
return magnitude;
}
public byte GetTier()
{
return tier;
}
public UInt64 GetExtra()
{
return extra;
}
public uint GetFlags()
{
return (uint)flags;
}
public byte GetOverwritable()
{
return (byte)overwrite;
}
public bool GetSilent()
{
return silent;
}
public bool GetHidden()
{
return hidden;
}
public void SetStartTime(DateTime time)
{
this.startTime = time;
this.lastTick = time;
}
public void SetOwner(Character owner)
{
this.owner = owner;
}
public void SetSource(Character source)
{
this.source = source;
}
public void SetName(string name)
{
this.name = name;
}
public void SetMagnitude(UInt64 magnitude)
{
this.magnitude = magnitude;
}
public void SetDuration(uint duration)
{
this.duration = duration;
}
public void SetTickMs(uint tickMs)
{
this.tickMs = tickMs;
}
public void SetTier(byte tier)
{
this.tier = tier;
}
public void SetExtra(UInt64 val)
{
this.extra = val;
}
public void SetFlags(uint flags)
{
this.flags = (StatusEffectFlags)flags;
}
public void SetOverwritable(byte overwrite)
{
this.overwrite = (StatusEffectOverwrite)overwrite;
}
public void SetSilent(bool silent)
{
this.silent = silent;
}
public void SetHidden(bool hidden)
{
this.hidden = hidden;
}
public void SetAnimation(uint hitEffect)
{
animationEffect = (HitEffect)hitEffect;
}
public uint GetAnimation()
{
return (uint)animationEffect;
}
}
}