mirror of
https://bitbucket.org/Ioncannon/project-meteor-server.git
synced 2025-05-20 08:26:59 -04:00
Refactor StatusEffectContainer to better handle messages using
CommandResultContainer. Alter Modifiers to be the same as ParamNames. Add LoseOnClassChange flag for status effects. Add a few missing status effects. Fix EndTime for stance status effects to stop icon from blinking.
This commit is contained in:
@@ -336,17 +336,17 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
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
|
||||
LoseOnCastStart = 1 << 7, // effects removed when owner starts casting
|
||||
LoseOnAggro = 1 << 8, // effects removed when owner gains enmity (swiftsong)
|
||||
//Loss flags - Do we need loseonattacking/caststart? Could just be done with activate flags
|
||||
LoseOnDeath = 1 << 0, // effects removed on death
|
||||
LoseOnZoning = 1 << 1, // effects removed on zoning
|
||||
LoseOnEsuna = 1 << 2, // effects which can be removed with esuna (debuffs)
|
||||
LoseOnDispel = 1 << 3, // some buffs which player might be able to dispel from mob
|
||||
LoseOnLogout = 1 << 4, // effects removed on logging out
|
||||
LoseOnAttacking = 1 << 5, // effects removed when owner attacks another entity
|
||||
LoseOnCastStart = 1 << 6, // effects removed when owner starts casting
|
||||
LoseOnAggro = 1 << 7, // effects removed when owner gains enmity (swiftsong)
|
||||
LoseOnClassChange = 1 << 8, //Effect falls off whhen changing class
|
||||
|
||||
//Activate flags
|
||||
ActivateOnCastStart = 1 << 9, //Activates when a cast starts.
|
||||
@@ -373,9 +373,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
PreventMovement = 1 << 26, // effects which prevent movement such as bind, still allows turning in place
|
||||
PreventTurn = 1 << 27, // effects which prevent turning, such as stun
|
||||
PreventUntarget = 1 << 28, // effects which prevent changing targets, such as fixation
|
||||
|
||||
Stealth = 1 << 29, // sneak/invis
|
||||
Stance = 1 << 30, // effects that do not have a timer
|
||||
Stance = 1 << 29 // effects that do not have a timer
|
||||
}
|
||||
|
||||
enum StatusEffectOverwrite : byte
|
||||
@@ -392,19 +390,22 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
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 endTime; // when this status falls off
|
||||
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 double 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 double 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;
|
||||
private string name; // name of this effect
|
||||
private DateTime startTime; // when was this effect added
|
||||
private DateTime endTime; // when this status falls off
|
||||
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 double 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 double 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 silentOnGain = false; //Whether a message is sent when the status is gained
|
||||
private bool silentOnLoss = false; //Whether a message is sent when the status is lost
|
||||
private bool hidden = false; //Whether this status is shown. Used for things that aren't really status effects like exp chains and procs
|
||||
private ushort statusGainTextId; //The text id used when the status is gained
|
||||
private ushort statusLossTextId; //The text id used when the status effect falls off when its time runs out
|
||||
public LuaScript script;
|
||||
|
||||
HitEffect animationEffect;
|
||||
@@ -438,26 +439,34 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
this.name = effect.name;
|
||||
this.flags = effect.flags;
|
||||
this.overwrite = effect.overwrite;
|
||||
this.statusGainTextId = effect.statusGainTextId;
|
||||
this.statusLossTextId = effect.statusLossTextId;
|
||||
this.extra = effect.extra;
|
||||
this.script = effect.script;
|
||||
this.silentOnGain = effect.silentOnGain;
|
||||
this.silentOnLoss = effect.silentOnLoss;
|
||||
this.hidden = effect.hidden;
|
||||
}
|
||||
|
||||
public StatusEffect(uint id, string name, uint flags, uint overwrite, uint tickMs)
|
||||
public StatusEffect(uint id, string name, uint flags, uint overwrite, uint tickMs, bool hidden, bool silentOnGain, bool silentOnLoss)
|
||||
{
|
||||
this.id = (StatusEffectId)id;
|
||||
this.name = name;
|
||||
this.flags = (StatusEffectFlags)flags;
|
||||
this.overwrite = (StatusEffectOverwrite)overwrite;
|
||||
this.tickMs = tickMs;
|
||||
this.hidden = hidden;
|
||||
this.silentOnGain = silentOnGain;
|
||||
this.silentOnLoss = silentOnLoss;
|
||||
}
|
||||
|
||||
// return true when duration has elapsed
|
||||
public bool Update(DateTime tick)
|
||||
public bool Update(DateTime tick, CommandResultContainer resultContainer = null)
|
||||
{
|
||||
if (tickMs != 0 && (tick - lastTick).TotalMilliseconds >= tickMs)
|
||||
{
|
||||
lastTick = tick;
|
||||
if (LuaEngine.CallLuaStatusEffectFunction(this.owner, this, "onTick", this.owner, this) > 0)
|
||||
if (LuaEngine.CallLuaStatusEffectFunction(this.owner, this, "onTick", this.owner, this, resultContainer) > 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -553,9 +562,14 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
return (byte)overwrite;
|
||||
}
|
||||
|
||||
public bool GetSilent()
|
||||
public bool GetSilentOnGain()
|
||||
{
|
||||
return silent;
|
||||
return silentOnGain;
|
||||
}
|
||||
|
||||
public bool GetSilentOnLoss()
|
||||
{
|
||||
return silentOnLoss;
|
||||
}
|
||||
|
||||
public bool GetHidden()
|
||||
@@ -563,6 +577,17 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
return hidden;
|
||||
}
|
||||
|
||||
public ushort GetStatusGainTextId()
|
||||
{
|
||||
return 30328;
|
||||
return statusGainTextId;
|
||||
}
|
||||
|
||||
public ushort GetStatusLossTextId()
|
||||
{
|
||||
return statusLossTextId;
|
||||
}
|
||||
|
||||
public void SetStartTime(DateTime time)
|
||||
{
|
||||
this.startTime = time;
|
||||
@@ -571,7 +596,15 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
|
||||
public void SetEndTime(DateTime time)
|
||||
{
|
||||
endTime = time;
|
||||
//If it's a stance, just set endtime to highest number possible for XIV
|
||||
if ((flags & StatusEffectFlags.Stance) != 0)
|
||||
{
|
||||
endTime = Utils.UnixTimeStampToDateTime(4294967295);
|
||||
}
|
||||
else
|
||||
{
|
||||
endTime = time;
|
||||
}
|
||||
}
|
||||
|
||||
//Refresh the status, updating the end time based on the duration of the status and broadcasts the new time
|
||||
@@ -634,9 +667,14 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
this.overwrite = (StatusEffectOverwrite)overwrite;
|
||||
}
|
||||
|
||||
public void SetSilent(bool silent)
|
||||
public void SetSilentOnGain(bool silent)
|
||||
{
|
||||
this.silent = silent;
|
||||
this.silentOnGain = silent;
|
||||
}
|
||||
|
||||
public void SetSilentOnLoss(bool silent)
|
||||
{
|
||||
this.silentOnLoss = silent;
|
||||
}
|
||||
|
||||
public void SetHidden(bool hidden)
|
||||
@@ -644,6 +682,17 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
this.hidden = hidden;
|
||||
}
|
||||
|
||||
public void SetStatusGainTextId(ushort textId)
|
||||
{
|
||||
this.statusGainTextId = textId;
|
||||
}
|
||||
|
||||
public void SetStatusLossTextId(ushort textId)
|
||||
{
|
||||
this.statusLossTextId = textId;
|
||||
}
|
||||
|
||||
|
||||
public void SetAnimation(uint hitEffect)
|
||||
{
|
||||
animationEffect = (HitEffect)hitEffect;
|
||||
|
@@ -109,55 +109,44 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
return effects.ContainsKey((uint)id);
|
||||
}
|
||||
|
||||
public CommandResult AddStatusForCommandResult(uint id, byte tier = 1, ulong magnitude = 0, uint duration = 0)
|
||||
{
|
||||
CommandResult action = null;
|
||||
|
||||
if (AddStatusEffect(id, tier, magnitude, duration))
|
||||
action = new CommandResult(owner.actorId, 30328, id | (uint)HitEffect.StatusEffectType);
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
public bool AddStatusEffect(uint id)
|
||||
public bool AddStatusEffect(uint id, CommandResultContainer actionContainer = null, ushort worldmasterTextId = 30328)
|
||||
{
|
||||
var se = Server.GetWorldManager().GetStatusEffect(id);
|
||||
|
||||
return AddStatusEffect(se, owner);
|
||||
return AddStatusEffect(se, owner, actionContainer, worldmasterTextId);
|
||||
}
|
||||
|
||||
public bool AddStatusEffect(uint id, byte tier)
|
||||
public bool AddStatusEffect(uint id, byte tier, CommandResultContainer actionContainer = null, ushort worldmasterTextId = 30328)
|
||||
{
|
||||
var se = Server.GetWorldManager().GetStatusEffect(id);
|
||||
|
||||
se.SetTier(tier);
|
||||
|
||||
return AddStatusEffect(se, owner);
|
||||
return AddStatusEffect(se, owner, actionContainer, worldmasterTextId);
|
||||
}
|
||||
|
||||
public bool AddStatusEffect(uint id, byte tier, double magnitude)
|
||||
public bool AddStatusEffect(uint id, byte tier, double magnitude, CommandResultContainer actionContainer = null, ushort worldmasterTextId = 30328)
|
||||
{
|
||||
var se = Server.GetWorldManager().GetStatusEffect(id);
|
||||
|
||||
se.SetMagnitude(magnitude);
|
||||
se.SetTier(tier);
|
||||
|
||||
return AddStatusEffect(se, owner);
|
||||
return AddStatusEffect(se, owner, actionContainer, worldmasterTextId);
|
||||
}
|
||||
|
||||
public bool AddStatusEffect(uint id, byte tier, double magnitude, uint duration, int tickMs = 3000)
|
||||
public bool AddStatusEffect(uint id, byte tier, double magnitude, uint duration, int tickMs, CommandResultContainer actionContainer = null, ushort worldmasterTextId = 30328)
|
||||
{
|
||||
var se = Server.GetWorldManager().GetStatusEffect(id);
|
||||
if (se != null)
|
||||
{
|
||||
se.SetDuration(duration);
|
||||
se.SetStartTime(DateTime.Now);
|
||||
se.SetOwner(owner);
|
||||
}
|
||||
return AddStatusEffect(se ?? new StatusEffect(this.owner, id, magnitude, 3000, duration, tier), owner);
|
||||
return AddStatusEffect(se ?? new StatusEffect(this.owner, id, magnitude, 3000, duration, tier), owner, actionContainer, worldmasterTextId);
|
||||
}
|
||||
|
||||
public bool AddStatusEffect(StatusEffect newEffect, Character source, bool silent = false, bool hidden = false)
|
||||
public bool AddStatusEffect(StatusEffect newEffect, Character source, CommandResultContainer actionContainer = null, ushort worldmasterTextId = 30328)
|
||||
{
|
||||
/*
|
||||
worldMasterTextId
|
||||
@@ -179,9 +168,10 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
if (canOverwrite || effect == null)
|
||||
{
|
||||
// send packet to client with effect added message
|
||||
if (effect != null && (!silent || !effect.GetSilent() || (effect.GetFlags() & (uint)StatusEffectFlags.Silent) == 0))
|
||||
if (newEffect != null && !newEffect.GetSilentOnGain())
|
||||
{
|
||||
// todo: send packet to client with effect added message
|
||||
if (actionContainer != null)
|
||||
actionContainer.AddAction(new CommandResult(owner.actorId, worldmasterTextId, newEffect.GetStatusEffectId() | (uint)HitEffect.StatusEffectType));
|
||||
}
|
||||
|
||||
// wont send a message about losing effect here
|
||||
@@ -194,13 +184,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
|
||||
if (effects.Count < MAX_EFFECTS)
|
||||
{
|
||||
if(newEffect.script != null)
|
||||
newEffect.CallLuaFunction(this.owner, "onGain", this.owner, newEffect);
|
||||
else
|
||||
LuaEngine.CallLuaStatusEffectFunction(this.owner, newEffect, "onGain", this.owner, newEffect);
|
||||
newEffect.CallLuaFunction(this.owner, "onGain", this.owner, newEffect, actionContainer);
|
||||
|
||||
effects.Add(newEffect.GetStatusEffectId(), newEffect);
|
||||
//newEffect.SetSilent(silent);
|
||||
newEffect.SetHidden(hidden);
|
||||
|
||||
if (!newEffect.GetHidden())
|
||||
{
|
||||
@@ -225,15 +211,19 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool RemoveStatusEffect(StatusEffect effect, bool silent = false)
|
||||
//playEffect determines whether the effect of the animation that's going to play with actionContainer is going to play on owner
|
||||
//Generally, for abilities removing an effect, this is true and for effects removing themselves it's false.
|
||||
public bool RemoveStatusEffect(StatusEffect effect, CommandResultContainer actionContainer = null, ushort worldmasterTextId = 30331, bool playEffect = true)
|
||||
{
|
||||
bool removedEffect = false;
|
||||
if (effect != null && effects.ContainsKey(effect.GetStatusEffectId()))
|
||||
{
|
||||
// send packet to client with effect remove message
|
||||
if (!silent && !effect.GetSilent() && (effect.GetFlags() & (uint)StatusEffectFlags.Silent) == 0)
|
||||
if (!effect.GetSilentOnLoss())
|
||||
{
|
||||
owner.DoBattleAction(0, 0, new CommandResult(owner.actorId, 30331, effect.GetStatusEffectId()));
|
||||
//Only send a message if we're using an actioncontainer and the effect normally sends a message when it's lost
|
||||
if (actionContainer != null)
|
||||
actionContainer.AddAction(new CommandResult(owner.actorId, worldmasterTextId, effect.GetStatusEffectId() | (playEffect ? 0 : (uint)HitEffect.StatusLossType)));
|
||||
}
|
||||
|
||||
//hidden effects not in charawork
|
||||
@@ -243,54 +233,20 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
SetStatusAtIndex(index, 0);
|
||||
SetTimeAtIndex(index, 0);
|
||||
}
|
||||
|
||||
// function onLose(actor, effect)
|
||||
effects.Remove(effect.GetStatusEffectId());
|
||||
if(effect.script != null)
|
||||
effect.CallLuaFunction(owner, "onLose", owner, effect);
|
||||
else
|
||||
LuaEngine.CallLuaStatusEffectFunction(this.owner, effect, "onLose", this.owner, effect);
|
||||
effect.CallLuaFunction(owner, "onLose", owner, effect, actionContainer);
|
||||
owner.RecalculateStats();
|
||||
sendUpdate = true;
|
||||
removedEffect = true;
|
||||
}
|
||||
|
||||
return removedEffect;
|
||||
}
|
||||
|
||||
public bool RemoveStatusEffect(uint effectId, bool silent = false)
|
||||
public bool RemoveStatusEffect(uint effectId, CommandResultContainer resultContainer = null, ushort worldmasterTextId = 30331, bool playEffect = true)
|
||||
{
|
||||
bool removedEffect = false;
|
||||
foreach (var effect in effects.Values)
|
||||
{
|
||||
if (effect.GetStatusEffectId() == effectId)
|
||||
{
|
||||
RemoveStatusEffect(effect, effect.GetSilent() || silent);
|
||||
removedEffect = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return removedEffect;
|
||||
}
|
||||
|
||||
|
||||
//Remove status effect and return the CommandResult message instead of sending it immediately
|
||||
public CommandResult RemoveStatusEffectForCommandResult(uint effectId, ushort worldMasterTextId = 30331)
|
||||
{
|
||||
CommandResult action = null;
|
||||
if (RemoveStatusEffect(effectId, true))
|
||||
action = new CommandResult(owner.actorId, worldMasterTextId, effectId);
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
//Remove status effect and return the CommandResult message instead of sending it immediately
|
||||
public CommandResult RemoveStatusEffectForCommandResult(StatusEffect effect, ushort worldMasterTextId = 30331)
|
||||
{
|
||||
CommandResult action = null;
|
||||
if (RemoveStatusEffect(effect, true))
|
||||
action = new CommandResult(owner.actorId, worldMasterTextId, effect.GetStatusEffectId());
|
||||
return action;
|
||||
return RemoveStatusEffect(GetStatusEffectById(effectId), resultContainer, worldmasterTextId, playEffect);
|
||||
}
|
||||
|
||||
public StatusEffect CopyEffect(StatusEffect effect)
|
||||
@@ -301,14 +257,14 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
return AddStatusEffect(newEffect, effect.GetSource()) ? newEffect : null;
|
||||
}
|
||||
|
||||
public bool RemoveStatusEffectsByFlags(uint flags, bool silent = false)
|
||||
public bool RemoveStatusEffectsByFlags(uint flags, CommandResultContainer resultContainer = null)
|
||||
{
|
||||
// build list of effects to remove
|
||||
var removeEffects = GetStatusEffectsByFlag(flags);
|
||||
|
||||
// remove effects from main list
|
||||
foreach (var effect in removeEffects)
|
||||
RemoveStatusEffect(effect, silent);
|
||||
RemoveStatusEffect(effect, resultContainer, effect.GetStatusLossTextId(), true);
|
||||
|
||||
// removed an effect with one of these flags
|
||||
return removeEffects.Count > 0;
|
||||
@@ -334,6 +290,16 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
return list;
|
||||
}
|
||||
|
||||
public StatusEffect GetRandomEffectByFlag(uint flag)
|
||||
{
|
||||
var list = GetStatusEffectsByFlag(flag);
|
||||
|
||||
if (list.Count > 0)
|
||||
return list[Program.Random.Next(list.Count)];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// todo: why the fuck cant c# convert enums/
|
||||
public bool HasStatusEffectsByFlag(StatusEffectFlags flags)
|
||||
{
|
||||
@@ -442,7 +408,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
SetStatusAtIndex(index, (ushort) (newEffectId - 200000));
|
||||
SetTimeAtIndex(index, time);
|
||||
|
||||
return new CommandResult(owner.actorId, 30328, (uint) HitEffect.StatusEffectType | newEffectId);
|
||||
return new CommandResult(owner.actorId, 30330, (uint) HitEffect.StatusEffectType | newEffectId);
|
||||
}
|
||||
}
|
||||
}
|
@@ -210,7 +210,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
||||
Disengage();
|
||||
return;
|
||||
}
|
||||
owner.SetMod((uint)Modifier.Speed, 5);
|
||||
owner.SetMod((uint)Modifier.MovementSpeed, 5);
|
||||
if ((tick - lastCombatTickScript).TotalSeconds > 3)
|
||||
{
|
||||
Move();
|
||||
@@ -363,7 +363,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
||||
|
||||
// todo: seems ffxiv doesnt even differentiate between sneak/invis?
|
||||
{
|
||||
hasSneak = target.statusEffects.HasStatusEffectsByFlag((uint)StatusEffectFlags.Stealth);
|
||||
hasSneak = target.GetMod(Modifier.Stealth) > 0;
|
||||
hasInvisible = hasSneak;
|
||||
}
|
||||
|
||||
|
@@ -16,7 +16,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
||||
{
|
||||
owner.Disengage();
|
||||
owner.ChangeState(SetActorStatePacket.MAIN_STATE_DEAD);
|
||||
owner.statusEffects.RemoveStatusEffectsByFlags((uint)StatusEffectFlags.LoseOnDeath, true);
|
||||
owner.statusEffects.RemoveStatusEffectsByFlags((uint)StatusEffectFlags.LoseOnDeath);
|
||||
//var deathStatePacket = SetActorStatePacket.BuildPacket(owner.actorId, SetActorStatePacket.MAIN_STATE_DEAD2, owner.currentSubState);
|
||||
//owner.zone.BroadcastPacketAroundActor(owner, deathStatePacket);
|
||||
canInterrupt = false;
|
||||
|
@@ -303,7 +303,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.utils
|
||||
public static double GetParryRate(Character attacker, Character defender, BattleCommand skill, CommandResult action)
|
||||
{
|
||||
//Can't parry with shield, can't parry rear attacks
|
||||
if (defender.GetMod((uint)Modifier.HasShield) != 0 || action.param == (byte) HitDirection.Rear)
|
||||
if (defender.GetMod((uint)Modifier.CanBlock) != 0 || action.param == (byte) HitDirection.Rear)
|
||||
return 0;
|
||||
|
||||
double parryRate = 10.0;
|
||||
@@ -348,7 +348,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.utils
|
||||
public static double GetBlockRate(Character attacker, Character defender, BattleCommand skill, CommandResult action)
|
||||
{
|
||||
//Shields are required to block and can't block from rear.
|
||||
if (defender.GetMod((uint)Modifier.HasShield) == 0 || action.param == (byte)HitDirection.Rear)
|
||||
if (defender.GetMod((uint)Modifier.CanBlock) == 0 || action.param == (byte)HitDirection.Rear)
|
||||
return 0;
|
||||
|
||||
short dlvl = (short)(defender.GetLevel() - attacker.GetLevel());
|
||||
@@ -894,10 +894,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.utils
|
||||
totalBonus += GetChainBonus(expChainNumber);
|
||||
|
||||
StatusEffect newChain = Server.GetWorldManager().GetStatusEffect((uint)StatusEffectId.EXPChain);
|
||||
newChain.SetSilent(true);
|
||||
newChain.SetDuration(timeLimit);
|
||||
newChain.SetTier((byte)(Math.Min(expChainNumber + 1, 255)));
|
||||
attacker.statusEffects.AddStatusEffect(newChain, attacker, true, true);
|
||||
attacker.statusEffects.AddStatusEffect(newChain, attacker);
|
||||
|
||||
actionContainer?.AddEXPActions(attacker.AddExp(baseExp, (byte)attacker.GetClass(), (byte)(totalBonus.Min(255))));
|
||||
}
|
||||
|
Reference in New Issue
Block a user