mirror of
https://bitbucket.org/Ioncannon/project-meteor-server.git
synced 2025-04-20 11:47:48 +00:00
moved getpath crap to pathfinding (or should i keep it in actor?)
- stubbed some more crap
This commit is contained in:
parent
100f3ae156
commit
cc1929a9fb
9 changed files with 149 additions and 25 deletions
|
@ -64,12 +64,15 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
public DateTime lastAiUpdate;
|
||||
|
||||
public AIContainer aiContainer;
|
||||
public StatusEffects statusEffects;
|
||||
|
||||
public Character(uint actorID) : base(actorID)
|
||||
{
|
||||
//Init timer array to "notimer"
|
||||
for (int i = 0; i < charaWork.statusShownTime.Length; i++)
|
||||
charaWork.statusShownTime[i] = 0xFFFFFFFF;
|
||||
|
||||
this.statusEffects = new StatusEffects(this);
|
||||
}
|
||||
|
||||
public SubPacket CreateAppearancePacket(uint playerActorId)
|
||||
|
|
|
@ -45,6 +45,14 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||
|
||||
// todo: action queues
|
||||
controller?.Update(tick);
|
||||
State currState;
|
||||
while (states.Count > 0 && (currState = states.Peek()).Update(tick))
|
||||
{
|
||||
if (currState == GetCurrentState())
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void CheckCompletedStates()
|
||||
|
|
|
@ -4,6 +4,10 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FFXIVClassic_Map_Server.Actors;
|
||||
using FFXIVClassic_Map_Server;
|
||||
using FFXIVClassic_Map_Server.utils;
|
||||
using FFXIVClassic.Common;
|
||||
using FFXIVClassic_Map_Server.actors.area;
|
||||
|
||||
namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
{
|
||||
|
@ -15,5 +19,49 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||
{
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
// todo: is this class even needed?
|
||||
public void PathTo(float x, float y, float z, float stepSize = 0.70f, int maxPath = 40, float polyRadius = 0.0f)
|
||||
{
|
||||
var pos = new Vector3(owner.positionX, owner.positionY, owner.positionZ);
|
||||
var dest = new Vector3(x, y, z);
|
||||
var zone = (Zone)owner.GetZone();
|
||||
var sw = new System.Diagnostics.Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
var path = NavmeshUtils.GetPath(zone, pos, dest, stepSize, maxPath, polyRadius);
|
||||
|
||||
if (path != null)
|
||||
{
|
||||
if (owner.oldPositionX == 0.0f && owner.oldPositionY == 0.0f && owner.oldPositionZ == 0.0f)
|
||||
{
|
||||
owner.oldPositionX = owner.positionX;
|
||||
owner.oldPositionY = owner.positionY;
|
||||
owner.oldPositionZ = owner.positionZ;
|
||||
}
|
||||
|
||||
// todo: something went wrong
|
||||
if (path.Count == 0)
|
||||
{
|
||||
owner.positionX = owner.oldPositionX;
|
||||
owner.positionY = owner.oldPositionY;
|
||||
owner.positionZ = owner.oldPositionZ;
|
||||
}
|
||||
|
||||
owner.positionUpdates = path;
|
||||
|
||||
owner.hasMoved = true;
|
||||
owner.isAtSpawn = false;
|
||||
|
||||
sw.Stop();
|
||||
zone.pathCalls++;
|
||||
zone.pathCallTime += sw.ElapsedMilliseconds;
|
||||
|
||||
if (path.Count == 1)
|
||||
Program.Log.Info($"mypos: {owner.positionX} {owner.positionY} {owner.positionZ} | targetPos: {x} {y} {z} | step {stepSize} | maxPath {maxPath} | polyRadius {polyRadius}");
|
||||
|
||||
Program.Log.Error("[{0}][{1}] Created {2} points in {3} milliseconds", owner.actorId, owner.actorName, path.Count, sw.ElapsedMilliseconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,8 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FFXIVClassic_Map_Server.Actors;
|
||||
|
||||
using FFXIVClassic_Map_Server.packets.send.actor;
|
||||
using FFXIVClassic_Map_Server.packets.send.actor.battle;
|
||||
namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
||||
{
|
||||
class AttackState : State
|
||||
|
@ -21,24 +22,84 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||
|
||||
}
|
||||
|
||||
public override void Update(DateTime time)
|
||||
public override bool Update(DateTime tick)
|
||||
{
|
||||
TryInterrupt();
|
||||
|
||||
if (interrupt)
|
||||
{
|
||||
OnInterrupt();
|
||||
return true;
|
||||
}
|
||||
|
||||
// todo: check weapon delay/haste etc and use that
|
||||
if ((tick - startTime).Milliseconds >= 0)
|
||||
{
|
||||
OnComplete();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void OnInterrupt()
|
||||
{
|
||||
|
||||
// todo: send paralyzed/sleep message etc.
|
||||
}
|
||||
|
||||
public override void OnComplete()
|
||||
{
|
||||
var damage = FFXIVClassic_Map_Server.actors.chara.ai.utils.AttackUtils.CalculateDamage(owner, target);
|
||||
|
||||
lua.LuaEngine.GetInstance().CallLuaFunction(owner, target, "onAttack", false, damage);
|
||||
|
||||
//var packet = BattleAction1Packet.BuildPacket(owner.actorId, target.actorId);
|
||||
|
||||
// todo: find a better place to put this?
|
||||
if (owner.GetState() != SetActorStatePacket.MAIN_STATE_ACTIVE)
|
||||
owner.ChangeState(SetActorStatePacket.MAIN_STATE_ACTIVE);
|
||||
|
||||
isCompleted = true;
|
||||
}
|
||||
|
||||
public override void TryInterrupt()
|
||||
{
|
||||
if (owner.statusEffects.HasStatusEffectsByFlag((uint)StatusEffectFlags.PreventAction))
|
||||
{
|
||||
// todo: sometimes paralyze can let you attack, get random percentage of actually letting you attack
|
||||
var list = owner.statusEffects.GetStatusEffectsByFlag((uint)StatusEffectFlags.PreventAction);
|
||||
uint effectId = 0;
|
||||
if (list.Count > 0)
|
||||
{
|
||||
// todo: actually check proc rate/random chance of whatever effect
|
||||
effectId = list[0].GetEffectId();
|
||||
}
|
||||
this.errorPacket = BattleActionX01Packet.BuildPacket(target.actorId, owner.actorId, target.actorId, 0, effectId, 0, 0, 0, 0);
|
||||
owner.zone.BroadcastPacketAroundActor(owner, errorPacket);
|
||||
errorPacket = null;
|
||||
interrupt = true;
|
||||
return;
|
||||
}
|
||||
else if (target.zone != owner.zone)
|
||||
{
|
||||
interrupt = true;
|
||||
return;
|
||||
}
|
||||
else if (owner.aiContainer.IsDead())
|
||||
{
|
||||
// todo: this really shouldnt ever hit since we'd be clearing states on death
|
||||
interrupt = true;
|
||||
return;
|
||||
}
|
||||
interrupt = CanAttack();
|
||||
}
|
||||
|
||||
private bool CanAttack()
|
||||
{
|
||||
if (target.aiContainer.IsDead())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||
this.interrupt = false;
|
||||
}
|
||||
|
||||
public virtual void Update(DateTime tick) { }
|
||||
public virtual bool Update(DateTime tick) { return true; }
|
||||
public virtual void OnStart() { }
|
||||
public virtual void OnInterrupt() { }
|
||||
public virtual void OnComplete() { isCompleted = true; }
|
||||
|
@ -54,5 +54,10 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||
return isCompleted;
|
||||
}
|
||||
|
||||
public void ChangeTarget(Character target)
|
||||
{
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.utils
|
|||
}
|
||||
public static int CalculateBaseDamage(Character attacker, Character defender)
|
||||
{
|
||||
return 0;
|
||||
// todo: actually calculate damage
|
||||
return Program.Random.Next(10) * 10;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,7 +16,6 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
class Mob : Npc
|
||||
{
|
||||
public HateContainer hateContainer;
|
||||
public StatusEffects statusEffects;
|
||||
|
||||
public Mob(int actorNumber, ActorClass actorClass, string uniqueId, Area spawnedArea, float posX, float posY, float posZ, float rot,
|
||||
ushort actorState, uint animationId, string customDisplayName)
|
||||
|
@ -25,7 +24,6 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
this.aiContainer = new AIContainer(this, new MobController(this), new PathFind(this), new TargetFind(this));
|
||||
this.currentSubState = SetActorStatePacket.SUB_STATE_MONSTER;
|
||||
this.hateContainer = new HateContainer(this);
|
||||
this.statusEffects = new StatusEffects(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -141,8 +141,6 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
|
||||
public Session playerSession;
|
||||
|
||||
public StatusEffects statusEffects;
|
||||
|
||||
public Player(Session cp, uint actorID) : base(actorID)
|
||||
{
|
||||
playerSession = cp;
|
||||
|
@ -253,7 +251,6 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
lastPlayTimeUpdate = Utils.UnixTimeStampUTC();
|
||||
|
||||
this.aiContainer = new AIContainer(this, new PlayerController(this), null, new TargetFind(this));
|
||||
this.statusEffects = new StatusEffects(this);
|
||||
}
|
||||
|
||||
public List<SubPacket> Create0x132Packets(uint playerActorId)
|
||||
|
|
|
@ -320,40 +320,41 @@ namespace FFXIVClassic_Map_Server.lua
|
|||
return null;
|
||||
}
|
||||
|
||||
public void CallLuaFunction(Player player, Actor target, string funcName, bool optional, params object[] args)
|
||||
public void CallLuaFunction(Actor actor, Actor target, string funcName, bool optional, params object[] args)
|
||||
{
|
||||
bool isPlayer = actor is Player;
|
||||
//Need a seperate case for NPCs cause that child/parent thing.
|
||||
if (target is Npc)
|
||||
if (target is Npc && isPlayer)
|
||||
{
|
||||
CallLuaFunctionNpc(player, (Npc)target, funcName, optional, args);
|
||||
CallLuaFunctionNpc((Player)actor, (Npc)target, funcName, optional, args);
|
||||
return;
|
||||
}
|
||||
|
||||
object[] args2 = new object[args.Length + 2];
|
||||
Array.Copy(args, 0, args2, 2, args.Length);
|
||||
args2[0] = player;
|
||||
args2[0] = actor;
|
||||
args2[1] = target;
|
||||
|
||||
string luaPath = GetScriptPath(target);
|
||||
LuaScript script = LoadScript(luaPath);
|
||||
if (script != null)
|
||||
{
|
||||
if (!script.Globals.Get(funcName).IsNil())
|
||||
if (!script.Globals.Get(funcName).IsNil() && isPlayer)
|
||||
{
|
||||
Coroutine coroutine = script.CreateCoroutine(script.Globals[funcName]).Coroutine;
|
||||
DynValue value = coroutine.Resume(args2);
|
||||
ResolveResume(player, coroutine, value);
|
||||
ResolveResume((Player)actor, coroutine, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!optional)
|
||||
SendError(player, String.Format("Could not find function '{0}' for actor {1}.", funcName, target.GetName()));
|
||||
SendError((Player)actor, String.Format("Could not find function '{0}' for actor {1}.", funcName, target.GetName()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(target is Area) && !optional)
|
||||
SendError(player, String.Format("Could not find script for actor {0}.", target.GetName()));
|
||||
if (!(target is Area) && !optional && isPlayer)
|
||||
SendError((Player)actor, String.Format("Could not find script for actor {0}.", target.GetName()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -372,16 +373,18 @@ namespace FFXIVClassic_Map_Server.lua
|
|||
CallLuaFunction(player, target, "onEventStarted", false, LuaUtils.CreateLuaParamObjectList(lparams));
|
||||
}
|
||||
|
||||
private DynValue ResolveResume(Player player, Coroutine coroutine, DynValue value)
|
||||
private DynValue ResolveResume(Actor actor, Coroutine coroutine, DynValue value)
|
||||
{
|
||||
var isPlayer = actor is Player;
|
||||
|
||||
if (value == null || value.IsVoid())
|
||||
return value;
|
||||
|
||||
if (value.String != null && value.String.Equals("_WAIT_EVENT"))
|
||||
if (isPlayer && value.String != null && value.String.Equals("_WAIT_EVENT"))
|
||||
{
|
||||
GetInstance().AddWaitEventCoroutine(player, coroutine);
|
||||
GetInstance().AddWaitEventCoroutine((Player)actor, coroutine);
|
||||
}
|
||||
else if (value.Tuple != null && value.Tuple.Length >= 1 && value.Tuple[0].String != null)
|
||||
else if (isPlayer && value.Tuple != null && value.Tuple.Length >= 1 && value.Tuple[0].String != null)
|
||||
{
|
||||
switch (value.Tuple[0].String)
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue