1
Fork 0
mirror of https://bitbucket.org/Ioncannon/project-meteor-server.git synced 2025-04-22 04:37:47 +00:00

fixed death/despawning kinda (need to figure out why hp wont tick down after respawning)

This commit is contained in:
Tahir Akhlaq 2017-09-03 01:01:19 +01:00
parent c5cc7c2f00
commit 4978813c27
16 changed files with 251 additions and 106 deletions

View file

@ -401,6 +401,16 @@ namespace FFXIVClassic_Map_Server.Actors
return GetAllActors<Actor>(); return GetAllActors<Actor>();
} }
public virtual List<Player> GetPlayers()
{
return GetAllActors<Player>();
}
public virtual List<BattleNpc> GetMonsters()
{
return GetAllActors<BattleNpc>();
}
public void BroadcastPacketsAroundActor(Actor actor, List<SubPacket> packets) public void BroadcastPacketsAroundActor(Actor actor, List<SubPacket> packets)
{ {
foreach (SubPacket packet in packets) foreach (SubPacket packet in packets)
@ -635,7 +645,7 @@ namespace FFXIVClassic_Map_Server.Actors
a.Update(tick); a.Update(tick);
var deltaTime = (tick - Program.LastTick).TotalMilliseconds; var deltaTime = (tick - Program.LastTick).TotalMilliseconds;
LuaEngine.GetInstance().CallLuaFunction(null, this, "onUpdate", true, deltaTime); LuaEngine.GetInstance().CallLuaFunction(null, this, "onUpdate", true, deltaTime, this);
} }
} }

View file

@ -288,7 +288,7 @@ namespace FFXIVClassic_Map_Server.Actors
public virtual void OnPath(Vector3 point) public virtual void OnPath(Vector3 point)
{ {
lua.LuaEngine.CallLuaBattleAction(this, "onPath", this, point); lua.LuaEngine.CallLuaBattleFunction(this, "onPath", this, point);
updateFlags |= ActorUpdateFlags.Position; updateFlags |= ActorUpdateFlags.Position;
this.isAtSpawn = false; this.isAtSpawn = false;
@ -428,6 +428,7 @@ namespace FFXIVClassic_Map_Server.Actors
public virtual void Spawn(DateTime tick) public virtual void Spawn(DateTime tick)
{ {
aiContainer.Reset();
// todo: reset hp/mp/tp etc here // todo: reset hp/mp/tp etc here
ChangeState(SetActorStatePacket.MAIN_STATE_PASSIVE); ChangeState(SetActorStatePacket.MAIN_STATE_PASSIVE);
charaWork.parameterSave.hp = charaWork.parameterSave.hpMax; charaWork.parameterSave.hp = charaWork.parameterSave.hpMax;
@ -448,23 +449,23 @@ namespace FFXIVClassic_Map_Server.Actors
public bool IsDead() public bool IsDead()
{ {
return currentMainState == SetActorStatePacket.MAIN_STATE_DEAD || currentMainState == SetActorStatePacket.MAIN_STATE_DEAD2; return aiContainer.IsDead();
} }
public bool IsAlive() public bool IsAlive()
{ {
return !IsDead(); return !aiContainer.IsDead();
} }
public short GetHP() public short GetHP()
{ {
// todo: // todo:
return charaWork.parameterSave.hp[currentJob]; return charaWork.parameterSave.hp[0];
} }
public short GetMaxHP() public short GetMaxHP()
{ {
return charaWork.parameterSave.hpMax[currentJob]; return charaWork.parameterSave.hpMax[0];
} }
public short GetMP() public short GetMP()
@ -500,16 +501,20 @@ namespace FFXIVClassic_Map_Server.Actors
// todo: the following functions are virtuals since we want to check hidden item bonuses etc on player for certain conditions // todo: the following functions are virtuals since we want to check hidden item bonuses etc on player for certain conditions
public virtual void AddHP(int hp) public virtual void AddHP(int hp)
{ {
// todo: +/- hp and die // dont wanna die ded
// todo: battlenpcs probably have way more hp? if (IsAlive())
var addHp = charaWork.parameterSave.hp[currentJob] + hp; {
addHp = addHp.Clamp(ushort.MinValue, charaWork.parameterSave.hpMax[currentJob]); // todo: +/- hp and die
charaWork.parameterSave.hp[currentJob] = (short)addHp; // todo: battlenpcs probably have way more hp?
var addHp = charaWork.parameterSave.hp[0] + hp;
addHp = addHp.Clamp(ushort.MinValue, charaWork.parameterSave.hpMax[0]);
charaWork.parameterSave.hp[0] = (short)addHp;
if (charaWork.parameterSave.hp[currentJob] < 1) if (charaWork.parameterSave.hp[0] < 1)
Die(Program.Tick); Die(Program.Tick);
updateFlags |= ActorUpdateFlags.HpTpMp; updateFlags |= ActorUpdateFlags.HpTpMp;
}
} }
public void AddMP(int mp) public void AddMP(int mp)
@ -580,21 +585,47 @@ namespace FFXIVClassic_Map_Server.Actors
// todo: call onAttack/onDamageTaken // todo: call onAttack/onDamageTaken
target.DelHP(action.amount); target.DelHP(action.amount);
if (target is BattleNpc)
((BattleNpc)target).lastAttacker = this;
} }
public virtual void OnCast(State state, BattleAction[] actions, ref BattleAction[] errors) public virtual void OnCast(State state, BattleAction[] actions, ref BattleAction[] errors)
{ {
var spell = ((MagicState)state).GetSpell(); var spell = ((MagicState)state).GetSpell();
// damage is handled in script
this.DelMP(spell.mpCost); // mpCost can be set in script e.g. if caster has something for free spells this.DelMP(spell.mpCost); // mpCost can be set in script e.g. if caster has something for free spells
if (target is BattleNpc)
((BattleNpc)target).lastAttacker = this;
} }
public virtual void OnWeaponSkill(State state, BattleAction[] actions, ref BattleAction[] errors) public virtual void OnWeaponSkill(State state, BattleAction[] actions, ref BattleAction[] errors)
{ {
var skill = ((WeaponSkillState)state).GetWeaponSkill(); var skill = ((WeaponSkillState)state).GetWeaponSkill();
// damage is handled in script
this.DelTP(skill.tpCost); this.DelTP(skill.tpCost);
if (target is BattleNpc)
((BattleNpc)target).lastAttacker = this;
} }
public virtual void OnAbility(State state, BattleAction[] actions, ref BattleAction[] errors) public virtual void OnAbility(State state, BattleAction[] actions, ref BattleAction[] errors)
{
if (target is BattleNpc)
((BattleNpc)target).lastAttacker = this;
}
public virtual void OnSpawn()
{
}
public virtual void OnDeath()
{
}
public virtual void OnDespawn()
{ {
} }

View file

@ -50,6 +50,8 @@ namespace FFXIVClassic_Map_Server.actors.chara
HarvestPotency = 38, HarvestPotency = 38,
HarvestLimit = 39, HarvestLimit = 39,
HarvestRate = 40 HarvestRate = 40,
Raise = 41,
} }
} }

View file

@ -203,7 +203,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
public bool IsDead() public bool IsDead()
{ {
return owner.currentMainState == SetActorStatePacket.MAIN_STATE_DEAD || return owner.currentMainState == SetActorStatePacket.MAIN_STATE_DEAD ||
owner.currentMainState == SetActorStatePacket.MAIN_STATE_DEAD2 || owner.GetHP() == 0; owner.currentMainState == SetActorStatePacket.MAIN_STATE_DEAD2;
} }
public bool IsRoaming() public bool IsRoaming()
@ -262,8 +262,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
public void InternalChangeTarget(Character target) public void InternalChangeTarget(Character target)
{ {
// todo: use invalid target id // targets are changed in the controller
// todo: this is retarded, call entity's changetarget function
if (IsEngaged() || target == null) if (IsEngaged() || target == null)
{ {
@ -288,7 +287,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
if (CanChangeState() || (GetCurrentState() != null && GetCurrentState().IsCompleted())) if (CanChangeState() || (GetCurrentState() != null && GetCurrentState().IsCompleted()))
{ {
ForceChangeState(new AttackState(this.owner, target)); ForceChangeState(new AttackState(owner, target));
return true; return true;
} }
return false; return false;
@ -301,7 +300,10 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
owner.updateFlags |= ActorUpdateFlags.HpTpMp; owner.updateFlags |= ActorUpdateFlags.HpTpMp;
ChangeTarget(null); ChangeTarget(null);
owner.ChangeState(SetActorStatePacket.MAIN_STATE_PASSIVE);
if (owner.currentMainState == SetActorStatePacket.MAIN_STATE_ACTIVE)
owner.ChangeState(SetActorStatePacket.MAIN_STATE_PASSIVE);
ClearStates(); ClearStates();
} }
@ -337,11 +339,18 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
} }
} }
public void InternalDie(DateTime tick, uint timeToFadeout) public void InternalDie(DateTime tick, uint fadeoutTimerSeconds)
{
pathFind?.Clear();
ClearStates();
ForceChangeState(new DeathState(owner, tick, fadeoutTimerSeconds));
}
public void InternalDespawn(DateTime tick, uint respawnTimerSeconds)
{ {
ClearStates(); ClearStates();
Disengage(); Disengage();
ForceChangeState(new DeathState(owner, tick, timeToFadeout)); ForceChangeState(new DespawnState(owner, respawnTimerSeconds));
} }
public void InternalRaise(Character target) public void InternalRaise(Character target)

View file

@ -384,12 +384,6 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
// todo: use tick instead of now? // todo: use tick instead of now?
this.startTime = DateTime.Now; this.startTime = DateTime.Now;
this.lastTick = startTime; this.lastTick = startTime;
// todo: set the effect name to be called by scripts or just lookup effects in db
// name = WorldManager.GetEffectInfo(id).Name;
// todo: check if can gain effect
// todo: call effect's onGain
// todo: broadcast effect gain packet
} }
public StatusEffect(Character owner, StatusEffect effect) public StatusEffect(Character owner, StatusEffect effect)

View file

@ -96,6 +96,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
{ {
var target = owner.target; var target = owner.target;
base.Disengage(); base.Disengage();
owner.statusEffects.RemoveStatusEffectsByFlags((uint)StatusEffectFlags.LoseOnDeath, true);
// todo: // todo:
lastActionTime = lastUpdate.AddSeconds(5); lastActionTime = lastUpdate.AddSeconds(5);
owner.isMovingToSpawn = true; owner.isMovingToSpawn = true;
@ -104,7 +105,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
neutralTime = lastActionTime; neutralTime = lastActionTime;
owner.hateContainer.ClearHate(); owner.hateContainer.ClearHate();
owner.moveState = 1; owner.moveState = 1;
lua.LuaEngine.CallLuaBattleAction(owner, "onDisengage", owner, target, Utils.UnixTimeStampUTC(battleStartTime)); lua.LuaEngine.CallLuaBattleFunction(owner, "onDisengage", owner, target, Utils.UnixTimeStampUTC(battleStartTime));
} }
public override void Cast(Character target, uint spellId) public override void Cast(Character target, uint spellId)
@ -203,7 +204,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
} }
Move(); Move();
lua.LuaEngine.CallLuaBattleAction(owner, "onCombatTick", owner, owner.target, Utils.UnixTimeStampUTC()); lua.LuaEngine.CallLuaBattleFunction(owner, "onCombatTick", owner, owner.target, Utils.UnixTimeStampUTC(tick));
} }
private void Move() private void Move()
@ -308,6 +309,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
public bool CanDetectTarget(Character target, bool forceSight = false) public bool CanDetectTarget(Character target, bool forceSight = false)
{ {
if (owner.IsDead())
return false;
// todo: this should probably be changed to only allow detection at end of path? // todo: this should probably be changed to only allow detection at end of path?
if (owner.aiContainer.pathFind.IsFollowingScriptedPath() || owner.aiContainer.pathFind.IsFollowingPath() && !owner.aiContainer.pathFind.AtPoint()) if (owner.aiContainer.pathFind.IsFollowingScriptedPath() || owner.aiContainer.pathFind.IsFollowingPath() && !owner.aiContainer.pathFind.AtPoint())
{ {

View file

@ -33,15 +33,6 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
public override bool Update(DateTime tick) public override bool Update(DateTime tick)
{ {
/*
TryInterrupt();
if (interrupt)
{
OnInterrupt();
return true;
}
*/
if ((target == null || owner.target != target || owner.target?.actorId != owner.currentLockedTarget) && owner.isAutoAttackEnabled) if ((target == null || owner.target != target || owner.target?.actorId != owner.currentLockedTarget) && owner.isAutoAttackEnabled)
owner.aiContainer.ChangeTarget(target = owner.zone.FindActorInArea<Character>(owner.currentLockedTarget)); owner.aiContainer.ChangeTarget(target = owner.zone.FindActorInArea<Character>(owner.currentLockedTarget));
@ -159,7 +150,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
// todo: shouldnt need to check if owner is dead since all states would be cleared // todo: shouldnt need to check if owner is dead since all states would be cleared
if (owner.aiContainer.IsDead() || target.aiContainer.IsDead()) if (owner.aiContainer.IsDead() || target.aiContainer.IsDead())
{ {
target = null; owner.aiContainer.ChangeTarget(null);
return false; return false;
} }
else if (!owner.aiContainer.GetTargetFind().CanTarget(target, false, true)) else if (!owner.aiContainer.GetTargetFind().CanTarget(target, false, true))

View file

@ -14,8 +14,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
public DeathState(Character owner, DateTime tick, uint timeToFadeOut) public DeathState(Character owner, DateTime tick, uint timeToFadeOut)
: base(owner, null) : base(owner, null)
{ {
owner.ChangeState(SetActorStatePacket.MAIN_STATE_DEAD);
owner.Disengage(); owner.Disengage();
owner.ChangeState(SetActorStatePacket.MAIN_STATE_DEAD);
canInterrupt = false; canInterrupt = false;
startTime = tick; startTime = tick;
despawnTime = startTime.AddSeconds(timeToFadeOut); despawnTime = startTime.AddSeconds(timeToFadeOut);
@ -23,17 +23,18 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
public override bool Update(DateTime tick) public override bool Update(DateTime tick)
{ {
// todo: set a flag on chara for accept raise, play animation and spawn
if (owner.GetMod((uint)Modifier.Raise) > 0)
{
owner.Spawn(tick);
return true;
}
// todo: handle raise etc // todo: handle raise etc
if (tick >= despawnTime) if (tick >= despawnTime)
{ {
if (owner is BattleNpc) // todo: for players, return them to homepoint
{ owner.Despawn(tick);
owner.Despawn(tick);
}
else
{
// todo: queue a warp for the player
}
return true; return true;
} }
return false; return false;

View file

@ -10,22 +10,21 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
{ {
class DespawnState : State class DespawnState : State
{ {
private DateTime endTime; private DateTime respawnTime;
public DespawnState(Character owner, Character target, uint despawnTimeSeconds) : public DespawnState(Character owner, uint respawnTimeSeconds) :
base(owner, null) base(owner, null)
{ {
startTime = Program.Tick; startTime = Program.Tick;
endTime = startTime.AddSeconds(despawnTimeSeconds); respawnTime = startTime.AddSeconds(respawnTimeSeconds);
owner.ChangeState(SetActorStatePacket.MAIN_STATE_DEAD2);
owner.OnDespawn();
} }
public override bool Update(DateTime tick) public override bool Update(DateTime tick)
{ {
if (tick >= endTime) if (tick >= respawnTime)
{ {
// todo: send packet to despawn the npc, set it so npc is despawned when requesting spawn packets owner.Spawn(tick);
owner.zone.BroadcastPacketAroundActor(owner, RemoveActorPacket.BuildPacket(owner.actorId));
owner.QueuePositionUpdate(owner.spawnX, owner.spawnY, owner.spawnZ);
lua.LuaEngine.CallLuaBattleAction(owner, "onDespawn", owner);
return true; return true;
} }
return false; return false;

View file

@ -15,6 +15,8 @@ using FFXIVClassic_Map_Server.actors.chara.ai.state;
using FFXIVClassic_Map_Server.utils; using FFXIVClassic_Map_Server.utils;
using FFXIVClassic_Map_Server.packets.send.actor.battle; using FFXIVClassic_Map_Server.packets.send.actor.battle;
using FFXIVClassic_Map_Server.actors.chara.ai.utils; using FFXIVClassic_Map_Server.actors.chara.ai.utils;
using FFXIVClassic_Map_Server.actors.group;
using FFXIVClassic_Map_Server.packets.send;
namespace FFXIVClassic_Map_Server.Actors namespace FFXIVClassic_Map_Server.Actors
{ {
@ -34,8 +36,10 @@ namespace FFXIVClassic_Map_Server.Actors
public AggroType aggroType; public AggroType aggroType;
public bool neutral; public bool neutral;
private uint despawnTime; private uint despawnTime;
private uint respawnTime;
private uint spawnDistance; private uint spawnDistance;
public Character lastAttacker;
public BattleNpc(int actorNumber, ActorClass actorClass, string uniqueId, Area spawnedArea, float posX, float posY, float posZ, float rot, public BattleNpc(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)
@ -56,15 +60,38 @@ namespace FFXIVClassic_Map_Server.Actors
spawnY = posY; spawnY = posY;
spawnZ = posZ; spawnZ = posZ;
// todo: read this from db // todo: read these from db also
aggroType = AggroType.Sight; aggroType = AggroType.Sight;
this.moveState = 2; this.moveState = 2;
ResetMoveSpeeds(); ResetMoveSpeeds();
despawnTime = 10; despawnTime = 10;
respawnTime = 30;
CalculateBaseStats(); CalculateBaseStats();
} }
public override List<SubPacket> GetSpawnPackets(Player player, ushort spawnType)
{
List<SubPacket> subpackets = new List<SubPacket>();
if (IsAlive())
{
subpackets.Add(CreateAddActorPacket());
subpackets.AddRange(GetEventConditionPackets());
subpackets.Add(CreateSpeedPacket());
subpackets.Add(CreateSpawnPositonPacket(0x0));
subpackets.Add(CreateAppearancePacket());
subpackets.Add(CreateNamePacket());
subpackets.Add(CreateStatePacket());
subpackets.Add(CreateIdleAnimationPacket());
subpackets.Add(CreateInitStatusPacket());
subpackets.Add(CreateSetActorIconPacket());
subpackets.Add(CreateIsZoneingPacket());
subpackets.Add(CreateScriptBindPacket(player));
}
return subpackets;
}
public uint GetAggroType() public uint GetAggroType()
{ {
return (uint)aggroType; return (uint)aggroType;
@ -135,6 +162,16 @@ namespace FFXIVClassic_Map_Server.Actors
despawnTime = seconds; despawnTime = seconds;
} }
public uint GetRespawnTime()
{
return respawnTime;
}
public void SetRespawnTime(uint seconds)
{
respawnTime = seconds;
}
///<summary> // todo: create an action object? </summary> ///<summary> // todo: create an action object? </summary>
public bool OnAttack(AttackState state) public bool OnAttack(AttackState state)
{ {
@ -143,32 +180,61 @@ namespace FFXIVClassic_Map_Server.Actors
public override void Spawn(DateTime tick) public override void Spawn(DateTime tick)
{ {
base.Spawn(tick); if (respawnTime > 0)
{
base.Spawn(tick);
this.isMovingToSpawn = false; this.isMovingToSpawn = false;
this.ResetMoveSpeeds(); this.ResetMoveSpeeds();
this.hateContainer.ClearHate(); this.hateContainer.ClearHate();
this.ChangeState(SetActorStatePacket.MAIN_STATE_PASSIVE); zone.BroadcastPacketsAroundActor(this, GetSpawnPackets(null, 0x01));
zone.BroadcastPacketsAroundActor(this, GetInitPackets());
charaWork.parameterSave.hp = charaWork.parameterSave.hpMax;
charaWork.parameterSave.mp = charaWork.parameterSave.mpMax;
RecalculateStats();
updateFlags |= ActorUpdateFlags.AllNpc;
}
} }
public override void Die(DateTime tick) public override void Die(DateTime tick)
{ {
if (IsAlive()) if (IsAlive())
{ {
if (lastAttacker is Pet && ((Pet)lastAttacker).master is Player)
{
lastAttacker = ((Pet)lastAttacker).master;
}
if (lastAttacker is Player)
{
if (lastAttacker.currentParty != null && lastAttacker.currentParty is Party)
{
foreach (var memberId in ((Party)lastAttacker.currentParty).members)
{
var partyMember = zone.FindActorInArea<Player>(memberId);
// onDeath(monster, player, killer)
lua.LuaEngine.CallLuaBattleFunction(this, "onDeath", this, partyMember, lastAttacker);
// <actor> defeat/defeats <target>
((Player)lastAttacker).QueuePacket(BattleActionX01Packet.BuildPacket(lastAttacker.actorId, 0, 0, new BattleAction(actorId, 30108, 0)));
}
}
else
{
// onDeath(monster, player, killer)
lua.LuaEngine.CallLuaBattleFunction(this, "onDeath", this, lastAttacker, lastAttacker);
((Player)lastAttacker).QueuePacket(BattleActionX01Packet.BuildPacket(lastAttacker.actorId, 0, 0, new BattleAction(actorId, 30108, 0)));
}
}
aiContainer.InternalDie(tick, despawnTime); aiContainer.InternalDie(tick, despawnTime);
aiContainer.pathFind.Clear(); aiContainer.pathFind.Clear();
this.ResetMoveSpeeds(); this.ResetMoveSpeeds();
this.positionX = oldPositionX;
this.positionY = oldPositionY;
this.positionZ = oldPositionZ;
// todo: reset cooldowns
this.isAtSpawn = true;
} }
else else
{ {
var err = $"[{actorId}][{customDisplayName}] {positionX} {positionY} {positionZ} {GetZoneID()} tried to die ded"; var err = $"[{actorId}][{GetUniqueId()}] {positionX} {positionY} {positionZ} {GetZone().GetName()} tried to die ded";
Program.Log.Error(err); Program.Log.Error(err);
//throw new Exception(err); //throw new Exception(err);
} }
@ -176,9 +242,10 @@ namespace FFXIVClassic_Map_Server.Actors
public override void Despawn(DateTime tick) public override void Despawn(DateTime tick)
{ {
aiContainer.ClearStates();
// todo: probably didnt need to make a new state... // todo: probably didnt need to make a new state...
aiContainer.ForceChangeState(new DespawnState(this, null, 0)); aiContainer.InternalDespawn(tick, respawnTime);
lua.LuaEngine.CallLuaBattleFunction(this, "onDespawn", this);
this.isAtSpawn = true;
} }
public void OnRoam(DateTime tick) public void OnRoam(DateTime tick)
@ -203,6 +270,7 @@ namespace FFXIVClassic_Map_Server.Actors
else else
{ {
this.isMovingToSpawn = false; this.isMovingToSpawn = false;
lua.LuaEngine.CallLuaBattleFunction(this, "onRoam", this);
} }
} }
@ -217,5 +285,20 @@ namespace FFXIVClassic_Map_Server.Actors
// todo: move this somewhere else prolly and change based on model/appearance (so maybe in Character.cs instead) // todo: move this somewhere else prolly and change based on model/appearance (so maybe in Character.cs instead)
action.animation = 0x11001000; // (temporary) wolf anim action.animation = 0x11001000; // (temporary) wolf anim
} }
public override void OnSpawn()
{
base.OnSpawn();
}
public override void OnDeath()
{
base.OnDeath();
}
public override void OnDespawn()
{
base.OnDespawn();
}
} }
} }

View file

@ -58,14 +58,16 @@ namespace FFXIVClassic_Map_Server.Actors
charaWork.battleSave.potencial = 1.0f; charaWork.battleSave.potencial = 1.0f;
charaWork.parameterSave.state_mainSkill[0] = 3; // todo: these really need to be read from db etc
charaWork.parameterSave.state_mainSkill[2] = 3; {
charaWork.parameterSave.state_mainSkillLevel = 2; charaWork.parameterSave.state_mainSkill[0] = 3;
charaWork.parameterSave.state_mainSkill[2] = 3;
charaWork.parameterSave.state_mainSkillLevel = 1;
charaWork.parameterSave.hp[0] = 500; charaWork.parameterSave.hp[0] = 80;
charaWork.parameterSave.hpMax[0] = 500; charaWork.parameterSave.hpMax[0] = 80;
}
for (int i = 0; i < 32; i++ ) for (int i = 0; i < 32; i++ )
charaWork.property[i] = (byte)(((int)actorClass.propertyFlags >> i) & 1); charaWork.property[i] = (byte)(((int)actorClass.propertyFlags >> i) & 1);
npcWork.pushCommand = actorClass.pushCommand; npcWork.pushCommand = actorClass.pushCommand;
@ -400,13 +402,30 @@ namespace FFXIVClassic_Map_Server.Actors
aiContainer.Update(tick); aiContainer.Update(tick);
} }
//A party member list packet came, set the party public override void OnSpawn()
/* public void SetParty(MonsterPartyGroup group)
{ {
if (group is MonsterPartyGroup) base.OnSpawn();
currentParty = group;
} }
*/
public override void OnDeath()
{
base.OnDeath();
}
public override void OnDespawn()
{
zone.BroadcastPacketAroundActor(this, RemoveActorPacket.BuildPacket(this.actorId));
zone.BroadcastPacketAroundActor(this, RemoveActorPacket.BuildPacket(this.actorId));
QueuePositionUpdate(spawnX, spawnY, spawnZ);
LuaEngine.CallLuaBattleFunction(this, "onDespawn", this);
}
//A party member list packet came, set the party
/* public void SetParty(MonsterPartyGroup group)
{
if (group is MonsterPartyGroup)
currentParty = group;
}
*/
} }
} }

View file

@ -13,6 +13,7 @@ namespace FFXIVClassic_Map_Server.Actors
{ {
class Pet : BattleNpc class Pet : BattleNpc
{ {
public Character master;
public Pet(int actorNumber, ActorClass actorClass, string uniqueId, Area spawnedArea, float posX, float posY, float posZ, float rot, public Pet(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)

View file

@ -1781,21 +1781,6 @@ namespace FFXIVClassic_Map_Server.Actors
base.PostUpdate(tick, packets); base.PostUpdate(tick, packets);
} }
public override void AddHP(int hp)
{
// todo: +/- hp and die
// todo: check hidden effects and shit
var addHp = charaWork.parameterSave.hp[currentJob] + hp;
addHp = addHp.Clamp(ushort.MinValue, charaWork.parameterSave.hpMax[currentJob]);
charaWork.parameterSave.hp[currentJob] = (short)addHp;
if (charaWork.parameterSave.hp[currentJob] < 1)
Die(Program.Tick);
updateFlags |= ActorUpdateFlags.HpTpMp;
}
public override void Die(DateTime tick) public override void Die(DateTime tick)
{ {
// todo: death timer // todo: death timer
@ -1981,7 +1966,7 @@ namespace FFXIVClassic_Map_Server.Actors
{ {
if (aiContainer.CanChangeState()) if (aiContainer.CanChangeState())
aiContainer.Cast(zone.FindActorInArea<Character>(targetId == 0 ? currentTarget : targetId), spellId); aiContainer.Cast(zone.FindActorInArea<Character>(targetId == 0 ? currentTarget : targetId), spellId);
else if (aiContainer.GetCurrentState() is MagicState) else if (aiContainer.IsCurrentState<MagicState>())
// You are already casting. // You are already casting.
SendGameMessage(Server.GetWorldManager().GetActor(), 32536, 0x20); SendGameMessage(Server.GetWorldManager().GetActor(), 32536, 0x20);
else else
@ -2141,7 +2126,7 @@ namespace FFXIVClassic_Map_Server.Actors
//action.animation = 0x19001000; //action.animation = 0x19001000;
} }
var target = state.GetTarget(); var target = state.GetTarget();
//if (target is BattleNpc) if (target is BattleNpc)
{ {
((BattleNpc)target).hateContainer.UpdateHate(this, action.amount); ((BattleNpc)target).hateContainer.UpdateHate(this, action.amount);
} }
@ -2164,6 +2149,8 @@ namespace FFXIVClassic_Map_Server.Actors
var skill = ((WeaponSkillState)state).GetWeaponSkill(); var skill = ((WeaponSkillState)state).GetWeaponSkill();
// todo: should just make a thing that updates the one slot cause this is dumb as hell // todo: should just make a thing that updates the one slot cause this is dumb as hell
UpdateHotbarTimer(skill.id, skill.recastTimeSeconds); UpdateHotbarTimer(skill.id, skill.recastTimeSeconds);
// todo: this really shouldnt be called on each ws?
lua.LuaEngine.CallLuaBattleFunction(this, "onWeaponSkill", this, state.GetTarget(), skill);
} }
} }
} }

View file

@ -134,9 +134,10 @@ namespace FFXIVClassic_Map_Server.lua
/// // todo: this is dumb, should probably make a function for each action with different default return values /// // todo: this is dumb, should probably make a function for each action with different default return values
/// or just make generic function and pass default value as first arg after functionName /// or just make generic function and pass default value as first arg after functionName
/// </summary> /// </summary>
public static void CallLuaBattleAction(Character actor, string functionName, params object[] args) public static void CallLuaBattleFunction(Character actor, string functionName, params object[] args)
{ {
string path = $"./scripts/unique/{actor.zone.zoneName}/Monster/{actor.customDisplayName}.lua"; // todo: should use "scripts/zones/ZONE_NAME/battlenpcs/NAME.lua" instead of scripts/unique
string path = "";
// todo: should we call this for players too? // todo: should we call this for players too?
if (actor is Player) if (actor is Player)
@ -144,6 +145,12 @@ namespace FFXIVClassic_Map_Server.lua
// todo: check this is correct // todo: check this is correct
path = FILEPATH_PLAYER; path = FILEPATH_PLAYER;
} }
else if (actor is Npc)
{
// todo: this is probably unnecessary as im not sure there were pets for players
if (!(actor is Pet && ((Pet)actor).master is Player))
path = String.Format("./scripts/unique/{0}/{1}/{2}.lua", actor.zone.zoneName, actor is BattleNpc ? "Monster" : "PopulaceStandard", ((Npc)actor).GetUniqueId());
}
// dont wanna throw an error if file doesnt exist // dont wanna throw an error if file doesnt exist
if (File.Exists(path)) if (File.Exists(path))
{ {
@ -154,7 +161,7 @@ namespace FFXIVClassic_Map_Server.lua
} }
catch (Exception e) catch (Exception e)
{ {
Program.Log.Error($"LuaEngine.CallLuaBattleAction [{functionName}] {e.Message}"); Program.Log.Error($"LuaEngine.CallLuaBattleFunction [{functionName}] {e.Message}");
} }
DynValue res = new DynValue(); DynValue res = new DynValue();
@ -167,6 +174,7 @@ namespace FFXIVClassic_Map_Server.lua
public static int CallLuaStatusEffectFunction(Character actor, StatusEffect effect, string functionName, params object[] args) public static int CallLuaStatusEffectFunction(Character actor, StatusEffect effect, string functionName, params object[] args)
{ {
// todo: this is stupid, load the actual effect crap
var name = ((StatusEffectId)effect.GetStatusEffectId()).ToString().ToLower(); var name = ((StatusEffectId)effect.GetStatusEffectId()).ToString().ToLower();
string path = $"./scripts/effects/{name}.lua"; string path = $"./scripts/effects/{name}.lua";

View file

@ -116,6 +116,12 @@ namespace FFXIVClassic_Map_Server
public static void WriteLuaParams(BinaryWriter writer, List<LuaParam> luaParams) public static void WriteLuaParams(BinaryWriter writer, List<LuaParam> luaParams)
{ {
if (luaParams == null)
{
Program.Log.Error("LuaUtils.WriteLuaParams LuaParams are null!");
return;
}
foreach (LuaParam l in luaParams) foreach (LuaParam l in luaParams)
{ {
if (l.typeID == 0x1) if (l.typeID == 0x1)

View file

@ -61,7 +61,7 @@ function onEventStarted(player, actor, triggerName)
end end
function onUpdate() function onUpdate(deltaTime, area)
end end
function onTalkEvent(player, npc) function onTalkEvent(player, npc)