renamed tables for consistency

- added magic.lua (todo: enumerate modifiers and stuff)
- moved aggro handling to session position update
- some cleanup
This commit is contained in:
Tahir Akhlaq
2017-08-29 01:15:12 +01:00
parent 6c74222b68
commit f4016e1a12
25 changed files with 539 additions and 442 deletions

View File

@@ -126,7 +126,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
public void ChangeState(State state)
{
if (GetCurrentState() != null)
if (CanChangeState())
{
if (states.Count <= 10)
{

View File

@@ -139,6 +139,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
}
else
{
distanceFromPoint = 0;
return true;
}

View File

@@ -22,7 +22,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
private DateTime waitTime;
private bool firstSpell = true;
private DateTime lastRoamScript; // todo: what even is this used as
private DateTime lastRoamUpdate;
private new BattleNpc owner;
public BattleNpcController(BattleNpc owner) :
@@ -76,7 +76,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
// todo: too far, path to player if mob, message if player
// owner.ResetMoveSpeeds();
owner.moveState = 2;
if (owner.currentSubState == SetActorStatePacket.SUB_STATE_MONSTER && owner.moveSpeeds[1] != 0)
if (owner.currentSubState == SetActorStatePacket.SUB_STATE_MONSTER && owner.GetSpeed() != 0)
{
// todo: actual stat based range
if (Utils.Distance(owner.positionX, owner.positionY, owner.positionZ, target.positionX, target.positionY, target.positionZ) > 10)
@@ -106,6 +106,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
// todo:
lastActionTime = lastUpdate.AddSeconds(5);
owner.isMovingToSpawn = true;
owner.aiContainer.pathFind.SetPathFlags(PathFindFlags.None);
owner.aiContainer.pathFind.PreparePath(owner.spawnX, owner.spawnY, owner.spawnZ, 1.5f, 10);
neutralTime = lastActionTime;
owner.hateContainer.ClearHate();
owner.moveState = 1;
@@ -147,7 +149,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
if (tick >= waitTime)
{
// todo: aggro cooldown
neutralTime = tick.AddSeconds(5);
neutralTime = tick.AddSeconds(3);
if (owner.aiContainer.pathFind.IsFollowingPath())
{
owner.aiContainer.pathFind.FollowPath();
@@ -157,8 +159,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
{
if (tick >= lastActionTime)
{
var battlenpc = owner as BattleNpc;
owner.aiContainer.pathFind.PathInRange(battlenpc.spawnX, battlenpc.spawnY, battlenpc.spawnZ, 1.5f, 15.0f);
}
}
// todo:
@@ -166,6 +167,28 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
owner.OnRoam(tick);
}
if (tick >= lastRoamUpdate && !owner.aiContainer.pathFind.IsFollowingPath())
{
// will move on next tick
owner.aiContainer.pathFind.SetPathFlags(PathFindFlags.None);
owner.aiContainer.pathFind.PathInRange(owner.spawnX, owner.spawnY, owner.spawnZ, 1.5f, 20.0f);
}
if (tick >= neutralTime)
{
foreach (var player in owner.zone.GetActorsAroundActor<Player>(owner, 50))
{
if (!owner.isMovingToSpawn && owner.aiContainer.pathFind.AtPoint() && owner.aggroType != AggroType.None)
{
uint levelDifference = (uint)Math.Abs(owner.charaWork.parameterSave.state_mainSkillLevel - ((Player)player).charaWork.parameterSave.state_mainSkillLevel);
if (levelDifference < 10 || (owner.aggroType & AggroType.IgnoreLevelDifference) != 0 && ((BattleNpcController)owner.aiContainer.GetController()).CanAggroTarget((Player)player))
owner.hateContainer.AddBaseHate((Player)player);
}
}
}
if (owner.aiContainer.pathFind.IsFollowingPath())
{
owner.aiContainer.pathFind.FollowPath();
@@ -223,7 +246,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
continue;
float mobDistance = Utils.Distance(owner.positionX, owner.positionY, owner.positionZ, chara.positionX, chara.positionY, chara.positionZ);
if (mobDistance < 0.90f && (chara.updateFlags & ActorUpdateFlags.Position) == 0)
if (mobDistance < 0.70f && (chara.updateFlags & ActorUpdateFlags.Position) == 0)
{
owner.aiContainer.pathFind.PathInRange(targetPos, 1.3f, 1.8f);
break;

View File

@@ -88,14 +88,38 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
{
// todo: possible underflow
BattleAction action = new BattleAction();
//var packet = BattleActionX01Packet.BuildPacket(owner.actorId, owner.actorId, target.actorId, (uint)0x19001000, (uint)0x8000604, (ushort)0x765D, (ushort)BattleActionX01PacketCommand.Attack, (ushort)damage, (byte)0x1);
errorPacket = null;
//var packet = BattleActionX01Packet.BuildPacket(owner.actorId, owner.actorId, target.actorId, (uint)0x19001000, (uint)0x8000604, (ushort)0x765D, (ushort)BattleActionX01PacketCommand.Attack, (ushort)damage, (byte)0x1);
action.animation = 0x19001000;
action.targetId = target.actorId;
action.effectId = (uint)HitEffect.Hit;
action.worldMasterTextId = 0x765D;
action.param = 1; // todo: hit effect doesnt display without this?
owner.OnAttack(this, action);
//this.errorPacket = BattleActionX01Packet.BuildPacket(target.actorId, owner.actorId, target.actorId, 0, effectId, 0, (ushort)BattleActionX01PacketCommand.Attack, (ushort)damage, 0);
action.param = (byte)HitDirection.None; // HitDirection (auto attack shouldnt need this afaik)
// todo: implement auto attack damage bonus in Character.OnAttack
/*
≪Auto-attack Damage Bonus≫
Class Bonus 1 Bonus 2
Pugilist Intelligence Strength
Gladiator Mind Strength
Marauder Vitality Strength
Archer Dexterity Piety
Lancer Piety Strength
Conjurer Mind Piety
Thaumaturge Mind Piety
* The above damage bonus also applies to “Shot” attacks by archers.
*/
owner.OnAttack(this, action, ref errorPacket);
// handle paralyze/intimidate/sleep/whatever in character thing
if (errorPacket == null)
owner.zone.BroadcastPacketAroundActor(owner, BattleActionX01Packet.BuildPacket(owner.actorId, owner.actorId, action.targetId, action.animation,
0x8000000 | action.effectId, action.worldMasterTextId, (ushort)BattleActionX01PacketCommand.Attack, action.amount, action.param)
);
else
owner.zone.BroadcastPacketAroundActor(owner, errorPacket);
//this.errorPacket = BattleActionX01Packet.BuildPacket(target.actorId, owner.actorId, target.actorId, 0, effectId, 0, (ushort)BattleActionX01PacketCommand.Attack, (ushort)damage, 0);
}
public override void TryInterrupt()
@@ -104,14 +128,14 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
{
// 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;
uint statusId = 0;
if (list.Count > 0)
{
// todo: actually check proc rate/random chance of whatever effect
effectId = list[0].GetStatusEffectId();
statusId = list[0].GetStatusId();
}
// todo: which is actually the swing packet
//this.errorPacket = BattleActionX01Packet.BuildPacket(target.actorId, owner.actorId, target.actorId, 0, effectId, 0, (ushort)BattleActionX01PacketCommand.Attack, (ushort)damage, 0);
//this.errorPacket = BattleActionX01Packet.BuildPacket(target.actorId, owner.actorId, target.actorId, 0, statusId, 0, (ushort)BattleActionX01PacketCommand.Attack, (ushort)damage, 0);
//owner.zone.BroadcastPacketAroundActor(owner, errorPacket);
//errorPacket = null;
interrupt = true;
@@ -135,6 +159,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
// todo: shouldnt need to check if owner is dead since all states would be cleared
if (owner.aiContainer.IsDead() || target.aiContainer.IsDead())
{
target = null;
return false;
}
else if (!owner.aiContainer.GetTargetFind().CanTarget(target, false, true))

View File

@@ -24,7 +24,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
this.startPos = owner.GetPosAsVector3();
this.startTime = DateTime.Now;
// todo: lookup spell from global table
this.spell = Server.GetWorldManager().GetAbility(spellId);
this.spell = Server.GetWorldManager().GetBattleCommand(spellId);
var returnCode = lua.LuaEngine.CallLuaBattleCommandFunction(owner, spell, "magic", "onMagicPrepare", owner, target, spell);
// todo: check recast
@@ -125,20 +125,21 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
{
var action = new BattleAction();
action.effectId = spell.effectAnimation;
action.param = 1;
action.param = (byte)HitDirection.None; // HitDirection (magic shouldnt need this afaik)
action.unknown = 1;
action.targetId = chara.actorId;
action.worldMasterTextId = spell.worldMasterTextId;
action.animation = spell.battleAnimation;
action.amount = (ushort)lua.LuaEngine.CallLuaBattleCommandFunction(owner, spell, "magic", "onMagicFinish", owner, chara, spell, action);
actions[i++] = action;
//packets.Add(BattleActionX01Packet.BuildPacket(chara.actorId, owner.actorId, action.targetId, spell.battleAnimation, action.effectId, action.worldMasterTextId, spell.id, action.amount, action.param));
}
owner.zone.BroadcastPacketAroundActor(owner,
spell.aoeType != TargetFindAOEType.None ? (BattleActionX10Packet.BuildPacket(owner.target.actorId, owner.actorId, spell.battleAnimation, spell.id, actions)) :
spell.aoeType != TargetFindAOEType.None ? (BattleActionX10Packet.BuildPacket(owner.actorId, owner.actorId, actions[0].animation, spell.id, actions)) :
BattleActionX01Packet.BuildPacket(owner.actorId, owner.actorId, target.actorId, spell.battleAnimation, actions[0].effectId, actions[0].worldMasterTextId, spell.id, actions[0].amount, actions[0].param)
);
owner.zone.BroadcastPacketsAroundActor(owner, packets);
//owner.zone.BroadcastPacketsAroundActor(owner, packets);
}
public override void TryInterrupt()

View File

@@ -21,7 +21,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
{
this.startTime = DateTime.Now;
// todo: lookup skill from global table
this.skill = Server.GetWorldManager().GetAbility(skillId);
this.skill = Server.GetWorldManager().GetBattleCommand(skillId);
var returnCode = lua.LuaEngine.CallLuaBattleCommandFunction(owner, skill, "weaponskill", "onSkillPrepare", owner, target, skill);
// todo: check recast
@@ -109,10 +109,11 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
{
var action = new BattleAction();
action.effectId = (uint)HitEffect.Hit;
action.param = 1;
action.param = 1; // HitDirection
action.unknown = 1;
action.targetId = chara.actorId;
action.worldMasterTextId = skill.worldMasterTextId;
action.animation = skill.battleAnimation;
// evasion, miss, dodge, etc to be handled in script, calling helpers from scripts/weaponskills.lua
action.amount = (ushort)lua.LuaEngine.CallLuaBattleCommandFunction(owner, skill, "weaponskill", "onSkillFinish", owner, target, skill, action);
actions[i++] = action;
@@ -121,7 +122,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
}
owner.zone.BroadcastPacketAroundActor(owner,
skill.aoeType != TargetFindAOEType.None ? (BattleActionX10Packet.BuildPacket(owner.target.actorId, owner.actorId, skill.battleAnimation, skill.id, actions)) :
skill.aoeType != TargetFindAOEType.None ? (BattleActionX10Packet.BuildPacket(owner.target.actorId, owner.actorId, actions[0].animation, skill.id, actions)) :
BattleActionX01Packet.BuildPacket(owner.actorId, owner.actorId, target.actorId, skill.battleAnimation, actions[0].effectId, actions[0].worldMasterTextId, skill.id, actions[0].amount, actions[0].param)
);
}

View File

@@ -7,16 +7,17 @@ using System.Threading.Tasks;
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.packets.send.actor;
using FFXIVClassic_Map_Server.packets.send.actor.battle;
using FFXIVClassic.Common;
namespace FFXIVClassic_Map_Server.actors.chara.ai.utils
{
static class BattleUtils
{
public static void TryAttack(Character attacker, Character defender, BattleAction action)
public static bool TryAttack(Character attacker, Character defender, BattleAction action, ref SubPacket errorPacket)
{
// todo: get hit rate, hit count, set hit effect
action.effectId |= (uint)(HitEffect.RecoilLv2 | HitEffect.Hit | HitEffect.HitVisual1);
return true;
}
public static ushort CalculateAttackDamage(Character attacker, Character defender, BattleAction action)
@@ -40,6 +41,17 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.utils
return damage;
}
public static ushort GetCriticalHitDamage(Character attacker, Character defender, BattleAction action)
{
ushort damage = action.amount;
// todo:
//
// action.effectId |= (uint)HitEffect.Critical;
//
return damage;
}
public static ushort CalculateSpellDamage(Character attacker, Character defender, BattleAction action)
{
ushort damage = 0;