1
Fork 0
mirror of https://bitbucket.org/Ioncannon/project-meteor-server.git synced 2025-04-23 13:17:45 +00:00

added a status effect container

- added status effect container to mobs and player objects (maybe should add to all Characters?)
- todo: handle gain/tick/lose in lua, send packets, everything else
This commit is contained in:
Tahir Akhlaq 2017-06-15 21:00:51 +01:00
parent 637f7f3d95
commit 6b023ceb3c
7 changed files with 178 additions and 5 deletions

View file

@ -23,6 +23,7 @@ using FFXIVClassic_Map_Server.packets.WorldPackets.Send.Group;
using System.Threading; using System.Threading;
using System.Diagnostics; using System.Diagnostics;
using FFXIVClassic_Map_Server.actors.director; using FFXIVClassic_Map_Server.actors.director;
using FFXIVClassic_Map_Server.actors.chara.ai;
namespace FFXIVClassic_Map_Server namespace FFXIVClassic_Map_Server
{ {
@ -35,6 +36,7 @@ namespace FFXIVClassic_Map_Server
private Dictionary<uint, ZoneEntrance> zoneEntranceList; private Dictionary<uint, ZoneEntrance> zoneEntranceList;
private Dictionary<uint, ActorClass> actorClasses = new Dictionary<uint,ActorClass>(); private Dictionary<uint, ActorClass> actorClasses = new Dictionary<uint,ActorClass>();
private Dictionary<ulong, Party> currentPlayerParties = new Dictionary<ulong, Party>(); //GroupId, Party object private Dictionary<ulong, Party> currentPlayerParties = new Dictionary<ulong, Party>(); //GroupId, Party object
private Dictionary<uint, StatusEffect> effectList = new Dictionary<uint, StatusEffect>(); // todo: load these in from a db table
private Server mServer; private Server mServer;

View file

@ -44,8 +44,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
// todo: trigger listeners // todo: trigger listeners
// todo: action queues // todo: action queues
controller.Update(tick);
} }
public void InterruptStates() public void InterruptStates()

View file

@ -5,6 +5,7 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using FFXIVClassic_Map_Server.Actors; using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.lua; using FFXIVClassic_Map_Server.lua;
using FFXIVClassic_Map_Server.actors.area;
namespace FFXIVClassic_Map_Server.actors.chara.ai namespace FFXIVClassic_Map_Server.actors.chara.ai
{ {
@ -322,6 +323,31 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
// custom effects here // custom effects here
} }
[Flags]
enum StatusEffectFlags
{
None = 0x00,
Silent = 0x01, // dont display effect loss message
LoseOnDeath = 0x02, // effects removed on death
LoseOnZoning = 0x04, // effects removed on zoning
LoseOnEsuna = 0x08, // effects which can be removed with esuna (debuffs)
LoseOnDispel = 0x10, // some buffs which player might be able to dispel from mob
LoseOnLogout = 0x20, // effects removed on logging out
LoseOnAttacking = 0x40, // effects removed when owner attacks another entity
LoseOnCasting = 0x80, // effects removed when owner starts casting
LoseOnDamageTaken = 0x100, // effects removed when owner takes damage
PreventAction = 0x200, // effects which prevent actions such as sleep/paralyze/petrify
}
enum StatusEffectOverwrite : byte
{
None,
Always,
GreaterOrEqualTo,
GreaterOnly,
}
class StatusEffect class StatusEffect
{ {
// todo: probably use get;set; // todo: probably use get;set;
@ -336,9 +362,12 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
private int magnitude; // a value specified by scripter which is guaranteed to be used by all effects private int 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 byte tier; // same effect with higher tier overwrites this
private Dictionary<string, UInt64> variables; // list of variables which belong to this effect, to be set/retrieved with GetVariable(key), SetVariable(key, val) private Dictionary<string, UInt64> variables; // list of variables which belong to this effect, to be set/retrieved with GetVariable(key), SetVariable(key, val)
private StatusEffectFlags flags; // death/erase/dispel etc
private StatusEffectOverwrite overwrite; //
public StatusEffect(uint id, int magnitude, uint tickMs, uint durationMs, byte tier = 0) public StatusEffect(Character owner, uint id, int magnitude, uint tickMs, uint durationMs, byte tier = 0)
{ {
this.owner = owner;
this.id = (StatusEffectId)id; this.id = (StatusEffectId)id;
this.magnitude = magnitude; this.magnitude = magnitude;
this.tickMs = tickMs; this.tickMs = tickMs;
@ -353,6 +382,24 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
// name = WorldManager.GetEffectInfo(id).Name; // name = WorldManager.GetEffectInfo(id).Name;
// todo: check if can gain effect // todo: check if can gain effect
// todo: call effect's onGain // todo: call effect's onGain
// todo: broadcast effect gain packet
}
public StatusEffect(Character owner, StatusEffect effect)
{
this.owner = owner;
this.id = effect.id;
this.magnitude = effect.magnitude;
this.tickMs = effect.tickMs;
this.durationMs = effect.durationMs;
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.variables = effect.variables;
} }
// return true when duration has elapsed // return true when duration has elapsed
@ -365,14 +412,21 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
// todo: maybe keep a global lua object instead of creating a new one each time we wanna call a script // todo: maybe keep a global lua object instead of creating a new one each time we wanna call a script
lastTick = tick; lastTick = tick;
} }
if (startTime.Millisecond + durationMs >= tick.Millisecond) // todo: handle infinite duration effects?
if (durationMs != 0 && startTime.Millisecond + durationMs >= tick.Millisecond)
{ {
// todo: call effect's onLose // todo: call effect's onLose
// todo: broadcast effect lost packet
return true; return true;
} }
return false; return false;
} }
public Character GetOwner()
{
return owner;
}
public uint GetEffectId() public uint GetEffectId()
{ {
return (uint)id; return (uint)id;
@ -408,6 +462,21 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
return variables?[key] ?? 0; return variables?[key] ?? 0;
} }
public uint GetFlags()
{
return (uint)flags;
}
public byte GetOverwritable()
{
return (byte)overwrite;
}
public void SetOwner(Character owner)
{
this.owner = owner;
}
public void SetName(string name) public void SetName(string name)
{ {
this.name = name; this.name = name;
@ -440,5 +509,98 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
variables[key] = val; variables[key] = val;
} }
} }
public void SetFlags(uint flags)
{
this.flags = (StatusEffectFlags)flags;
}
public void SetOverwritable(byte overwrite)
{
this.overwrite = (StatusEffectOverwrite)overwrite;
}
}
class StatusEffects
{
private Character owner;
private List<StatusEffect> effects;
public StatusEffects(Character owner)
{
this.owner = owner;
this.effects = new List<StatusEffect>();
}
public void Update(DateTime tick)
{
// list of effects to remove
var removeEffects = new List<StatusEffect>();
foreach (var effect in effects)
{
// effect's update function returns true if effect has completed
if (effect.Update(tick))
removeEffects.Add(effect);
}
// remove effects from this list
foreach (var effect in removeEffects)
effects.Remove(effect);
}
public bool AddStatusEffect(StatusEffect effect)
{
// todo: check flags/overwritable and add effect to list
effects.Add(effect);
return true;
}
public StatusEffect CopyEffect(StatusEffect effect)
{
var newEffect = new StatusEffect(this.owner, effect);
newEffect.SetOwner(this.owner);
return AddStatusEffect(newEffect) ? newEffect : null;
}
public bool RemoveStatusEffectsByFlags(uint flags)
{
// build list of effects to remove
var removeEffects = new List<StatusEffect>();
foreach (var effect in effects)
if ((effect.GetFlags() & flags) > 0)
removeEffects.Add(effect);
// remove effects from main list
foreach (var effect in removeEffects)
effects.Remove(effect);
// removed an effect with one of these flags
return removeEffects.Count > 0;
}
public StatusEffect GetStatusEffectById(uint id, uint tier = 0xFF)
{
foreach (var effect in effects)
{
if (effect.GetEffectId() == id && (tier != 0xFF ? effect.GetTier() == tier : true))
return effect;
}
return null;
}
public List<StatusEffect> GetStatusEffectsByFlag(uint flag)
{
var list = new List<StatusEffect>();
foreach (var effect in effects)
{
if ((effect.GetFlags() & flag) > 0)
{
list.Add(effect);
}
}
return list;
}
} }
} }

View file

@ -17,7 +17,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
public override void Update(DateTime tick) public override void Update(DateTime tick)
{ {
// todo: handle aggro/deaggro and other shit here
((Mob)this.owner).statusEffects.Update(tick);
} }
public override bool Engage(Character target) public override bool Engage(Character target)

View file

@ -17,7 +17,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
public override void Update(DateTime tick) public override void Update(DateTime tick)
{ {
// todo: handle player stuff on tick
((Player)this.owner).statusEffects.Update(tick);
} }
public override void ChangeTarget(Character target) public override void ChangeTarget(Character target)

View file

@ -16,6 +16,8 @@ namespace FFXIVClassic_Map_Server.Actors
class Mob : Npc class Mob : Npc
{ {
public HateContainer hateContainer; public HateContainer hateContainer;
public StatusEffects statusEffects;
public Mob(int actorNumber, ActorClass actorClass, string uniqueId, Area spawnedArea, float posX, float posY, float posZ, float rot, public Mob(int actorNumber, ActorClass actorClass, string uniqueId, Area spawnedArea, float posX, float posY, float posZ, float rot,
ushort actorState, uint animationId, string customDisplayName) ushort actorState, uint animationId, string customDisplayName)
: base(actorNumber, actorClass, uniqueId, spawnedArea, posX, posY, posZ, rot, actorState, animationId, customDisplayName) : base(actorNumber, actorClass, uniqueId, spawnedArea, posX, posY, posZ, rot, actorState, animationId, customDisplayName)
@ -23,6 +25,7 @@ namespace FFXIVClassic_Map_Server.Actors
this.aiContainer = new AIContainer(this, new MobController(this), new PathFind(this), new TargetFind(this)); this.aiContainer = new AIContainer(this, new MobController(this), new PathFind(this), new TargetFind(this));
this.currentSubState = SetActorStatePacket.SUB_STATE_MONSTER; this.currentSubState = SetActorStatePacket.SUB_STATE_MONSTER;
this.hateContainer = new HateContainer(this); this.hateContainer = new HateContainer(this);
this.statusEffects = new StatusEffects(this);
} }
} }
} }

View file

@ -141,6 +141,8 @@ namespace FFXIVClassic_Map_Server.Actors
public Session playerSession; public Session playerSession;
public StatusEffects statusEffects;
public Player(Session cp, uint actorID) : base(actorID) public Player(Session cp, uint actorID) : base(actorID)
{ {
playerSession = cp; playerSession = cp;
@ -249,7 +251,9 @@ namespace FFXIVClassic_Map_Server.Actors
Database.LoadPlayerCharacter(this); Database.LoadPlayerCharacter(this);
lastPlayTimeUpdate = Utils.UnixTimeStampUTC(); lastPlayTimeUpdate = Utils.UnixTimeStampUTC();
this.aiContainer = new AIContainer(this, new PlayerController(this), null, new TargetFind(this)); this.aiContainer = new AIContainer(this, new PlayerController(this), null, new TargetFind(this));
this.statusEffects = new StatusEffects(this);
} }
public List<SubPacket> Create0x132Packets(uint playerActorId) public List<SubPacket> Create0x132Packets(uint playerActorId)