stubbed item use state (needs to actually look up the item and get its reuse stuff)

- added tables to load mobs from (probably dont import besides server_battlenpc_genus.sql)
- added field to server_battle_commands for commands usable by both monsters and players (probably arent any really)
This commit is contained in:
Tahir Akhlaq
2017-09-05 05:05:25 +01:00
parent 4978813c27
commit 68a2d5f0b9
26 changed files with 615 additions and 179 deletions

View File

@@ -19,10 +19,10 @@ namespace FFXIVClassic_Map_Server.Actors
/// <summary> Which Character types am I friendly with </summary>
enum CharacterTargetingAllegiance
{
/// <summary> Friendly to Players </summary>
Player,
/// <summary> Friendly to BattleNpcs </summary>
BattleNpcs
BattleNpcs,
/// <summary> Friendly to Players </summary>
Player
}
class Character : Actor
@@ -564,6 +564,16 @@ namespace FFXIVClassic_Map_Server.Actors
updateFlags |= ActorUpdateFlags.HpTpMp;
}
public void SetStat(uint statId, uint val)
{
charaWork.battleTemp.generalParameter[statId] = (ushort)val;
}
public ushort GetStat(uint statId)
{
return charaWork.battleTemp.generalParameter[statId];
}
public virtual float GetSpeed()
{
// todo: for battlenpc/player calculate speed

View File

@@ -93,6 +93,23 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
}
}
public void InternalUseItem(Character target, uint slot, uint itemId)
{
// todo: can allies use items?
if (owner is Player)
{
if (CanChangeState())
{
ChangeState(new ItemState((Player)owner, target, (ushort)slot, itemId));
}
else
{
// You cannot use that item now.
((Player)owner).SendGameMessage(Server.GetWorldManager().GetActor(), 32544, 0x20, itemId);
}
}
}
public void ClearStates()
{
while (states.Count > 0)
@@ -107,9 +124,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
this.controller = controller;
}
public Controller GetController()
public T GetController<T>() where T : Controller
{
return controller;
return controller as T;
}
public TargetFind GetTargetFind()
@@ -190,13 +207,11 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
public bool IsSpawned()
{
// todo: set a flag when finished spawning
return !IsDead();
}
public bool IsEngaged()
{
// todo: check this is legit
return owner.currentMainState == SetActorStatePacket.MAIN_STATE_ACTIVE;
}
@@ -260,6 +275,11 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
InternalMobSkill(target, mobSkillId);
}
public void UseItem(Character target, uint slot, uint itemId)
{
if (controller != null)
controller.UseItem(target, slot, itemId);
}
public void InternalChangeTarget(Character target)
{
// targets are changed in the controller

View File

@@ -44,6 +44,13 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
Miss = 0x08
}
public enum BattleCommandValidUser : byte
{
All,
Player,
Monster
}
class BattleCommand
{
public ushort id;
@@ -75,6 +82,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
public int aoeRange;
public TargetFind targetFind;
public BattleCommandValidUser validUser;
public BattleCommand(ushort id, string name)
{
@@ -100,12 +108,10 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
public bool IsValidTarget(Character user, Character target)
{
// todo: set box length..
targetFind = new TargetFind(user);
if (aoeType == TargetFindAOEType.Box)
{
// todo: read box width from sql
targetFind.SetAOEBox(validTarget, aoeTarget, range, aoeRange);
}
else

View File

@@ -125,6 +125,13 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
this.param = param != -1.0f ? param : 0.0f;
}
/// <summary>
/// Call this to prepare Box AOE
/// </summary>
/// <param name="validTarget"></param>
/// <param name="aoeTarget"></param>
/// <param name="length"></param>
/// <param name="width"></param>
public void SetAOEBox(ValidTarget validTarget, TargetFindAOETarget aoeTarget, float length, float width)
{
this.validTarget = validTarget;
@@ -272,7 +279,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
{
foreach (var actorId in party.members)
{
AddTarget(owner.zone.FindActorInArea(actorId) as Character, withPet);
AddTarget(owner.zone.FindActorInArea<Character>(actorId), withPet);
}
}
}
@@ -373,9 +380,12 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
private bool IsWithinCircle(Character target, float maxDistance)
{
// todo: make y diff modifiable?
if (Math.Abs(owner.positionX - target.positionY) > 6.0f)
return false;
if (this.targetPosition == null)
this.targetPosition = aoeTarget == TargetFindAOETarget.Self ? owner.GetPosAsVector3() : masterTarget.GetPosAsVector3();
return target.GetPosAsVector3().IsWithinCircle(targetPosition, param);
}
@@ -393,9 +403,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
// if character is a player owned pet, treat as a player
if (target.aiContainer != null)
{
var controller = target.aiContainer.GetController();
if (controller != null && controller is PetController)
return ((PetController)controller).GetPetMaster();
var controller = target.aiContainer.GetController<PetController>();
if (controller != null)
return controller.GetPetMaster();
}
return null;
}

View File

@@ -36,6 +36,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
public override void Update(DateTime tick)
{
lastUpdate = tick;
// todo: handle aggro/deaggro and other shit here
if (owner.aiContainer.IsEngaged())
{
@@ -104,8 +105,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
owner.aiContainer.pathFind.PreparePath(owner.spawnX, owner.spawnY, owner.spawnZ, 1.5f, 10);
neutralTime = lastActionTime;
owner.hateContainer.ClearHate();
owner.ResetMoveSpeeds();
owner.moveState = 1;
lua.LuaEngine.CallLuaBattleFunction(owner, "onDisengage", owner, target, Utils.UnixTimeStampUTC(battleStartTime));
lua.LuaEngine.CallLuaBattleFunction(owner, "onDisengage", owner, target, Utils.UnixTimeStampUTC(lastUpdate));
}
public override void Cast(Character target, uint spellId)
@@ -143,7 +145,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
if (tick >= waitTime)
{
// todo: aggro cooldown
neutralTime = tick.AddSeconds(3);
neutralTime = tick.AddSeconds(5);
if (owner.aiContainer.pathFind.IsFollowingPath())
{
owner.aiContainer.pathFind.FollowPath();

View File

@@ -29,6 +29,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
public abstract void Cast(Character target, uint spellId);
public virtual void WeaponSkill(Character target, uint weaponSkillId) { }
public virtual void MonsterSkill(Character target, uint mobSkillId) { }
public virtual void UseItem(Character target, uint slot, uint itemId) { }
public abstract void Ability(Character target, uint abilityId);
public abstract void RangedAttack(Character target);
public virtual void Spawn() { }

View File

@@ -87,5 +87,10 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
{
}
public override void UseItem(Character target, uint slot, uint itemId)
{
owner.aiContainer.InternalUseItem(target, slot, itemId);
}
}
}

View File

@@ -15,7 +15,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
: base(owner, null)
{
owner.Disengage();
owner.ChangeState(SetActorStatePacket.MAIN_STATE_DEAD);
owner.ChangeState(SetActorStatePacket.MAIN_STATE_DEAD2);
canInterrupt = false;
startTime = tick;
despawnTime = startTime.AddSeconds(timeToFadeOut);

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.actors.chara.player;
using FFXIVClassic_Map_Server.dataobjects;
namespace FFXIVClassic_Map_Server.actors.chara.ai.state
{
class ItemState : State
{
ItemData item;
new Player owner;
public ItemState(Player owner, Character target, ushort slot, uint itemId) :
base(owner, target)
{
this.owner = owner;
this.target = target;
}
}
}

View File

@@ -26,21 +26,41 @@ namespace FFXIVClassic_Map_Server.Actors
None = 0x00,
Sight = 0x01,
Scent = 0x02,
LowHp = 0x04,
IgnoreLevelDifference = 0x08
Sound = 0x04,
LowHp = 0x08,
IgnoreLevelDifference = 0x10
}
enum KindredType
{
Unknown = 0,
Beast = 1,
Plantoid = 2,
Aquan = 3,
Spoken = 4,
Reptilian = 5,
Insect = 6,
Avian = 7,
Undead = 8,
Cursed = 9,
Voidsent = 10,
}
class BattleNpc : Npc
{
public HateContainer hateContainer;
public AggroType aggroType;
public KindredType kindredType;
public bool neutral;
private uint despawnTime;
private uint respawnTime;
private uint spawnDistance;
public Character lastAttacker;
public Dictionary<uint, BattleCommand> skillList = new Dictionary<uint, BattleCommand>();
public Dictionary<uint, BattleCommand> spellList = new Dictionary<uint, BattleCommand>();
public BattleNpc(int actorNumber, ActorClass actorClass, string uniqueId, Area spawnedArea, float posX, float posY, float posZ, float rot,
ushort actorState, uint animationId, string customDisplayName)
: base(actorNumber, actorClass, uniqueId, spawnedArea, posX, posY, posZ, rot, actorState, animationId, customDisplayName)
@@ -193,6 +213,7 @@ namespace FFXIVClassic_Map_Server.Actors
charaWork.parameterSave.mp = charaWork.parameterSave.mpMax;
RecalculateStats();
OnSpawn();
updateFlags |= ActorUpdateFlags.AllNpc;
}
}
@@ -201,9 +222,10 @@ namespace FFXIVClassic_Map_Server.Actors
{
if (IsAlive())
{
if (lastAttacker is Pet && ((Pet)lastAttacker).master is Player)
// todo: does retail
if (lastAttacker is Pet && lastAttacker.aiContainer.GetController<PetController>()?.GetPetMaster() is Player)
{
lastAttacker = ((Pet)lastAttacker).master;
lastAttacker = lastAttacker.aiContainer.GetController<PetController>().GetPetMaster();
}
if (lastAttacker is Player)
@@ -226,8 +248,8 @@ namespace FFXIVClassic_Map_Server.Actors
((Player)lastAttacker).QueuePacket(BattleActionX01Packet.BuildPacket(lastAttacker.actorId, 0, 0, new BattleAction(actorId, 30108, 0)));
}
}
positionUpdates?.Clear();
aiContainer.InternalDie(tick, despawnTime);
aiContainer.pathFind.Clear();
this.ResetMoveSpeeds();
// todo: reset cooldowns
@@ -289,6 +311,7 @@ namespace FFXIVClassic_Map_Server.Actors
public override void OnSpawn()
{
base.OnSpawn();
lua.LuaEngine.CallLuaBattleFunction(this, "onSpawn", this);
}
public override void OnDeath()

View File

@@ -21,6 +21,17 @@ using FFXIVClassic_Map_Server.actors.chara.ai;
namespace FFXIVClassic_Map_Server.Actors
{
[Flags]
enum NpcSpawnType : ushort
{
Normal = 0x00,
Scripted = 0x01,
Nighttime = 0x02,
Evening = 0x04,
Daytime = 0x08,
Weather = 0x10,
}
class Npc : Character
{
private uint actorClassId;
@@ -30,6 +41,7 @@ namespace FFXIVClassic_Map_Server.Actors
private uint layout, instance;
public NpcWork npcWork = new NpcWork();
public NpcSpawnType npcSpawnType;
public Npc(int actorNumber, ActorClass actorClass, string uniqueId, Area spawnedArea, float posX, float posY, float posZ, float rot, ushort actorState, uint animationId, string customDisplayName)
: base((4 << 28 | spawnedArea.actorId << 19 | (uint)actorNumber))
@@ -414,7 +426,6 @@ namespace FFXIVClassic_Map_Server.Actors
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);

View File

@@ -13,7 +13,6 @@ namespace FFXIVClassic_Map_Server.Actors
{
class Pet : BattleNpc
{
public Character master;
public Pet(int actorNumber, ActorClass actorClass, string uniqueId, Area spawnedArea, float posX, float posY, float posZ, float rot,
ushort actorState, uint animationId, string customDisplayName)
: base(actorNumber, actorClass, uniqueId, spawnedArea, posX, posY, posZ, rot, actorState, animationId, customDisplayName)

View File

@@ -1755,6 +1755,10 @@ namespace FFXIVClassic_Map_Server.Actors
public override void PostUpdate(DateTime tick, List<SubPacket> packets = null)
{
// todo: is this correct?
if (this.playerSession.isUpdatesLocked)
return;
// todo: should probably add another flag for battleTemp since all this uses reflection
packets = new List<SubPacket>();