mirror of
https://bitbucket.org/Ioncannon/project-meteor-server.git
synced 2025-07-25 03:48:23 +02:00
Merge branch 'ai-open' of https://bitbucket.org/skeletonhorn/ffxiv-classic-server-ai-fork into ai
# Conflicts: # data/scripts/modifiers.lua
This commit is contained in:
commit
cd60c571ac
54 changed files with 935 additions and 268 deletions
|
@ -40,6 +40,28 @@
|
|||
<PropertyGroup>
|
||||
<RunPostBuildEvent>Always</RunPostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Cyotek.Collections.Generic.CircularBuffer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=58daa28b0b2de221, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Cyotek.CircularBuffer.1.0.0.0\lib\net20\Cyotek.Collections.Generic.CircularBuffer.dll</HintPath>
|
||||
|
|
|
@ -511,7 +511,6 @@ namespace FFXIVClassic_Map_Server
|
|||
battleNpc.SetMod((uint)Modifier.Defense, reader.GetUInt32("def"));
|
||||
battleNpc.SetMod((uint)Modifier.Evasion, reader.GetUInt32("eva"));
|
||||
|
||||
|
||||
battleNpc.dropListId = reader.GetUInt32("dropListId");
|
||||
battleNpc.spellListId = reader.GetUInt32("spellListId");
|
||||
battleNpc.skillListId = reader.GetUInt32("skillListId");
|
||||
|
@ -644,12 +643,48 @@ namespace FFXIVClassic_Map_Server
|
|||
battleNpc.SetMod((uint)Modifier.Defense, reader.GetUInt32("def"));
|
||||
battleNpc.SetMod((uint)Modifier.Evasion, reader.GetUInt32("eva"));
|
||||
|
||||
if (battleNpc.poolMods != null)
|
||||
{
|
||||
foreach (var a in battleNpc.poolMods.mobModList)
|
||||
{
|
||||
battleNpc.SetMobMod(a.Value.id, (long)(a.Value.value));
|
||||
}
|
||||
foreach (var a in battleNpc.poolMods.modList)
|
||||
{
|
||||
battleNpc.SetMod(a.Key, (long)(a.Value.value));
|
||||
}
|
||||
}
|
||||
|
||||
if (battleNpc.genusMods != null)
|
||||
{
|
||||
foreach (var a in battleNpc.genusMods.mobModList)
|
||||
{
|
||||
battleNpc.SetMobMod(a.Key, (long)(a.Value.value));
|
||||
}
|
||||
foreach (var a in battleNpc.genusMods.modList)
|
||||
{
|
||||
battleNpc.SetMod(a.Key, (long)(a.Value.value));
|
||||
}
|
||||
}
|
||||
|
||||
if(battleNpc.spawnMods != null)
|
||||
{
|
||||
foreach (var a in battleNpc.spawnMods.mobModList)
|
||||
{
|
||||
battleNpc.SetMobMod(a.Key, (long)(a.Value.value));
|
||||
}
|
||||
|
||||
foreach (var a in battleNpc.spawnMods.modList)
|
||||
{
|
||||
battleNpc.SetMod(a.Key, (long)(a.Value.value));
|
||||
}
|
||||
}
|
||||
|
||||
battleNpc.dropListId = reader.GetUInt32("dropListId");
|
||||
battleNpc.spellListId = reader.GetUInt32("spellListId");
|
||||
battleNpc.skillListId = reader.GetUInt32("skillListId");
|
||||
battleNpc.SetMaxHP(1000);
|
||||
battleNpc.SetHP(1000);
|
||||
battleNpc.SetBattleNpcId(reader.GetUInt32("bnpcId"));
|
||||
battleNpc.SetRespawnTime(reader.GetUInt32("respawnTime"));
|
||||
battleNpc.CalculateBaseStats();
|
||||
battleNpc.RecalculateStats();
|
||||
//battleNpc.SetMod((uint)Modifier.ResistFire, )
|
||||
|
@ -679,7 +714,7 @@ namespace FFXIVClassic_Map_Server
|
|||
try
|
||||
{
|
||||
conn.Open();
|
||||
var query = $"SELECT {primaryKey}, modId, modVal, isMobMod FROM {tableName} GROUP BY {primaryKey};";
|
||||
var query = $"SELECT {primaryKey}, modId, modVal, isMobMod FROM {tableName}";
|
||||
|
||||
MySqlCommand cmd = new MySqlCommand(query, conn);
|
||||
|
||||
|
@ -688,9 +723,9 @@ namespace FFXIVClassic_Map_Server
|
|||
while (reader.Read())
|
||||
{
|
||||
var id = reader.GetUInt32(primaryKey);
|
||||
ModifierList modList = new ModifierList(id);
|
||||
ModifierList modList = list.TryGetValue(id, out modList) ? modList : new ModifierList(id);
|
||||
modList.SetModifier(reader.GetUInt16("modId"), reader.GetInt64("modVal"), reader.GetBoolean("isMobMod"));
|
||||
list.Add(id, modList);
|
||||
list[id] = modList;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -438,9 +438,6 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
|
||||
updateFlags = ActorUpdateFlags.None;
|
||||
zone.BroadcastPacketsAroundActor(this, packets);
|
||||
|
||||
SetActorPropetyPacket hpInfo = new SetActorPropetyPacket("charaWork/exp");
|
||||
hpInfo.AddTarget();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -419,8 +419,8 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
public virtual List<BattleNpc> GetMonsters()
|
||||
{
|
||||
return GetAllActors<BattleNpc>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public virtual List<Ally> GetAllies()
|
||||
{
|
||||
return GetAllActors<Ally>();
|
||||
|
@ -500,8 +500,8 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
npc = new Npc(mActorList.Count + 1, actorClass, uniqueId, this, x, y, z, rot, state, animId, null);
|
||||
|
||||
npc.LoadEventConditions(actorClass.eventConditions);
|
||||
npc.SetMaxHP(300);
|
||||
npc.SetHP(300);
|
||||
//npc.SetMaxHP(30000);
|
||||
//npc.SetHP(30000);
|
||||
|
||||
AddActorToZone(npc);
|
||||
|
||||
|
@ -669,12 +669,12 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
{
|
||||
foreach (Actor a in mActorList.Values.ToList())
|
||||
a.Update(tick);
|
||||
|
||||
|
||||
if ((tick - lastUpdateScript).TotalMilliseconds > 1500)
|
||||
{
|
||||
LuaEngine.GetInstance().CallLuaFunctionForReturn(LuaEngine.GetScriptPath(this), "onUpdate", true, this, tick);
|
||||
//LuaEngine.GetInstance().CallLuaFunctionForReturn(LuaEngine.GetScriptPath(this), "onUpdate", true, this, tick);
|
||||
lastUpdateScript = tick;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -132,6 +132,18 @@ namespace FFXIVClassic_Map_Server.actors.area
|
|||
return actor;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (List<PrivateAreaContent> paList in contentAreas.Values)
|
||||
{
|
||||
foreach (PrivateArea pa in paList)
|
||||
{
|
||||
Actor actor = pa.FindActorInArea(id);
|
||||
if (actor != null)
|
||||
return actor;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
else
|
||||
|
@ -184,7 +196,7 @@ namespace FFXIVClassic_Map_Server.actors.area
|
|||
{
|
||||
if (this.pathCalls > 0)
|
||||
{
|
||||
Program.Log.Debug("Number of pathfinding calls {0} average time {1}ms", pathCalls, (float)(pathCallTime / pathCalls));
|
||||
Program.Log.Debug("Number of pathfinding calls {0} average time {1}ms", pathCalls, (float)(pathCallTime / pathCalls));
|
||||
}
|
||||
lastUpdate = tick;
|
||||
}
|
||||
|
|
|
@ -229,10 +229,10 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
public void DoBattleAction(ushort commandId, uint animationId, BattleAction[] actions)
|
||||
{
|
||||
int currentIndex = 0;
|
||||
|
||||
//AoE abilities only ever hit 16 people, so we probably won't need this loop anymore
|
||||
while (true)
|
||||
{
|
||||
if (actions.Length - currentIndex >= 18)
|
||||
if (actions.Length - currentIndex >= 10)
|
||||
zone.BroadcastPacketAroundActor(this, BattleActionX18Packet.BuildPacket(actorId, animationId, commandId, actions, ref currentIndex));
|
||||
else if (actions.Length - currentIndex > 1)
|
||||
zone.BroadcastPacketAroundActor(this, BattleActionX10Packet.BuildPacket(actorId, animationId, commandId, actions, ref currentIndex));
|
||||
|
@ -243,7 +243,9 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
}
|
||||
else
|
||||
break;
|
||||
animationId = 0; //If more than one packet is sent out, only send the animation once to avoid double playing.
|
||||
|
||||
//I think aoe effects play on all hit enemies. Firaga does at least
|
||||
//animationId = 0; //If more than one packet is sent out, only send the animation once to avoid double playing.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -298,7 +300,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
|
||||
public virtual void OnPath(Vector3 point)
|
||||
{
|
||||
lua.LuaEngine.CallLuaBattleFunction(this, "onPath", this, point);
|
||||
//lua.LuaEngine.CallLuaBattleFunction(this, "onPath", this, point);
|
||||
|
||||
updateFlags |= ActorUpdateFlags.Position;
|
||||
this.isAtSpawn = false;
|
||||
|
@ -332,7 +334,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
|
||||
if ((updateFlags & ActorUpdateFlags.HpTpMp) != 0)
|
||||
{
|
||||
var propPacketUtil = new ActorPropertyPacketUtil("charaWork.parameterSave", this);
|
||||
var propPacketUtil = new ActorPropertyPacketUtil("charaWork/stateAtQuicklyForAll", this);
|
||||
|
||||
propPacketUtil.AddProperty("charaWork.parameterSave.mp");
|
||||
propPacketUtil.AddProperty("charaWork.parameterSave.mpMax");
|
||||
|
@ -455,6 +457,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
{
|
||||
// todo: actual despawn timer
|
||||
aiContainer.InternalDie(tick, 10);
|
||||
ChangeSpeed(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
public virtual void Despawn(DateTime tick)
|
||||
|
@ -528,6 +531,20 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
updateFlags |= ActorUpdateFlags.HpTpMp;
|
||||
}
|
||||
|
||||
public void SetMP(uint mp)
|
||||
{
|
||||
charaWork.parameterSave.mpMax = (short)mp;
|
||||
if (mp > charaWork.parameterSave.hpMax[0])
|
||||
SetMaxMP(mp);
|
||||
|
||||
updateFlags |= ActorUpdateFlags.HpTpMp;
|
||||
}
|
||||
|
||||
public void SetMaxMP(uint mp)
|
||||
{
|
||||
charaWork.parameterSave.mp = (short)mp;
|
||||
updateFlags |= ActorUpdateFlags.HpTpMp;
|
||||
}
|
||||
// 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)
|
||||
{
|
||||
|
@ -547,7 +564,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
}
|
||||
}
|
||||
|
||||
public short GetJob()
|
||||
public short GetClass()
|
||||
{
|
||||
return charaWork.parameterSave.state_mainSkill[0];
|
||||
}
|
||||
|
@ -599,8 +616,30 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
|
||||
public void RecalculateStats()
|
||||
{
|
||||
if (GetMod((uint)Modifier.Hp) != 0)
|
||||
uint hpMod = (uint) GetMod((uint)Modifier.Hp);
|
||||
if (hpMod != 0)
|
||||
{
|
||||
SetMaxHP(hpMod);
|
||||
uint hpp = (uint) GetMod((uint) Modifier.HpPercent);
|
||||
uint hp = hpMod;
|
||||
if(hpp != 0)
|
||||
{
|
||||
hp = (uint) Math.Ceiling(((float)hpp / 100.0f) * hpMod);
|
||||
}
|
||||
SetHP(hp);
|
||||
}
|
||||
|
||||
uint mpMod = (uint)GetMod((uint)Modifier.Mp);
|
||||
if (mpMod != 0)
|
||||
{
|
||||
SetMaxMP(mpMod);
|
||||
uint mpp = (uint)GetMod((uint)Modifier.MpPercent);
|
||||
uint mp = mpMod;
|
||||
if (mpp != 0)
|
||||
{
|
||||
mp = (uint)Math.Ceiling(((float)mpp / 100.0f) * mpMod);
|
||||
}
|
||||
SetMP(mp);
|
||||
}
|
||||
// todo: recalculate stats and crap
|
||||
updateFlags |= ActorUpdateFlags.HpTpMp;
|
||||
|
@ -635,14 +674,8 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
//var packet = BattleActionX01Packet.BuildPacket(owner.actorId, owner.actorId, target.actorId, (uint)0x19001000, (uint)0x8000604, (ushort)0x765D, (ushort)BattleActionX01PacketCommand.Attack, (ushort)damage, (byte)0x1);
|
||||
}
|
||||
|
||||
target.OnDamageTaken(this, action, DamageTakenType.Ability);
|
||||
// todo: call onAttack/onDamageTaken
|
||||
target.DelHP(action.amount);
|
||||
if (target is BattleNpc)
|
||||
{
|
||||
((BattleNpc)target).lastAttacker = this;
|
||||
((BattleNpc)target).hateContainer.UpdateHate(this, action.amount);
|
||||
}
|
||||
BattleUtils.DamageTarget(this, target, action, DamageTakenType.Attack);
|
||||
AddTP(115);
|
||||
target.AddTP(100);
|
||||
}
|
||||
|
@ -651,13 +684,14 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
{
|
||||
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
|
||||
var spellCost = spell.CalculateCost((uint)this.GetLevel());
|
||||
this.DelMP(spellCost); // mpCost can be set in script e.g. if caster has something for free spells
|
||||
|
||||
foreach (var action in actions)
|
||||
zone.FindActorInArea<Character>(action.targetId).OnDamageTaken(this, action, DamageTakenType.Magic);
|
||||
foreach (BattleAction action in actions)
|
||||
if (zone.FindActorInArea<Character>(action.targetId) is Character chara)
|
||||
BattleUtils.DamageTarget(this, chara, action, DamageTakenType.Magic);
|
||||
|
||||
if (target is BattleNpc)
|
||||
((BattleNpc)target).lastAttacker = this;
|
||||
lua.LuaEngine.GetInstance().OnSignal("spellUsed");
|
||||
}
|
||||
|
||||
public virtual void OnWeaponSkill(State state, BattleAction[] actions, ref BattleAction[] errors)
|
||||
|
@ -666,11 +700,11 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
// damage is handled in script
|
||||
this.DelTP(skill.tpCost);
|
||||
|
||||
foreach (var action in actions)
|
||||
zone.FindActorInArea<BattleNpc>(action.targetId)?.OnDamageTaken(this, action, DamageTakenType.Weaponskill);
|
||||
foreach (BattleAction action in actions)
|
||||
if (zone.FindActorInArea<Character>(action.targetId) is Character chara)
|
||||
BattleUtils.DamageTarget(this, chara, action, DamageTakenType.Weaponskill);
|
||||
|
||||
if (target is BattleNpc)
|
||||
((BattleNpc)target).lastAttacker = this;
|
||||
lua.LuaEngine.GetInstance().OnSignal("weaponskillUsed");
|
||||
}
|
||||
|
||||
public virtual void OnAbility(State state, BattleAction[] actions, ref BattleAction[] errors)
|
||||
|
@ -756,22 +790,22 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
|
||||
public bool IsDiscipleOfWar()
|
||||
{
|
||||
return currentJob < CLASSID_THM;
|
||||
return GetClass() < CLASSID_THM;
|
||||
}
|
||||
|
||||
public bool IsDiscipleOfMagic()
|
||||
{
|
||||
return currentJob >= CLASSID_THM && currentJob < CLASSID_CRP;
|
||||
return GetClass() >= CLASSID_THM && currentJob < CLASSID_CRP;
|
||||
}
|
||||
|
||||
public bool IsDiscipleOfHand()
|
||||
{
|
||||
return currentJob >= CLASSID_CRP && currentJob < CLASSID_MIN;
|
||||
return GetClass() >= CLASSID_CRP && currentJob < CLASSID_MIN;
|
||||
}
|
||||
|
||||
public bool IsDiscipleOfLand()
|
||||
{
|
||||
return currentJob >= CLASSID_MIN;
|
||||
return GetClass() >= CLASSID_MIN;
|
||||
}
|
||||
#endregion lua helpers
|
||||
#endregion ai stuff
|
||||
|
|
|
@ -5,6 +5,7 @@ using System.Text;
|
|||
using System.Threading.Tasks;
|
||||
using FFXIVClassic_Map_Server.Actors;
|
||||
using FFXIVClassic_Map_Server.actors.chara.npc;
|
||||
using FFXIVClassic.Common;
|
||||
|
||||
namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
||||
{
|
||||
|
@ -17,10 +18,11 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
|||
{
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
// server really likes to hang whenever scripts iterate area's actorlist
|
||||
protected override void DoCombatTick(DateTime tick, List<Character> contentGroupCharas = null)
|
||||
|
||||
protected List<Character> GetContentGroupCharas()
|
||||
{
|
||||
List<Character> contentGroupCharas = null;
|
||||
|
||||
if (owner.currentContentGroup != null)
|
||||
{
|
||||
contentGroupCharas = new List<Character>(owner.currentContentGroup.GetMemberCount());
|
||||
|
@ -32,20 +34,46 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
|||
contentGroupCharas.Add(chara);
|
||||
}
|
||||
}
|
||||
|
||||
return contentGroupCharas;
|
||||
}
|
||||
|
||||
//Iterate over players in the group and if they are fighting, assist them
|
||||
protected override void TryAggro(DateTime tick)
|
||||
{
|
||||
//lua.LuaEngine.CallLuaBattleFunction(owner, "tryAggro", owner, GetContentGroupCharas());
|
||||
|
||||
foreach(Character chara in GetContentGroupCharas())
|
||||
{
|
||||
if(chara.IsPlayer())
|
||||
{
|
||||
if(owner.aiContainer.GetTargetFind().CanTarget((Character) chara.target) && chara.target is BattleNpc && ((BattleNpc)chara.target).hateContainer.HasHateForTarget(chara))
|
||||
{
|
||||
owner.Engage(chara.target.actorId);
|
||||
owner.hateContainer.AddBaseHate((Character) chara.target);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//base.TryAggro(tick);
|
||||
}
|
||||
|
||||
// server really likes to hang whenever scripts iterate area's actorlist
|
||||
protected override void DoCombatTick(DateTime tick, List<Character> contentGroupCharas = null)
|
||||
{
|
||||
if (contentGroupCharas == null)
|
||||
{
|
||||
contentGroupCharas = GetContentGroupCharas();
|
||||
}
|
||||
|
||||
base.DoCombatTick(tick, contentGroupCharas);
|
||||
}
|
||||
|
||||
protected override void DoRoamTick(DateTime tick, List<Character> contentGroupCharas = null)
|
||||
{
|
||||
if (owner.currentContentGroup != null)
|
||||
if (contentGroupCharas == null)
|
||||
{
|
||||
contentGroupCharas = new List<Character>(owner.currentContentGroup.GetMemberCount());
|
||||
foreach (var charaId in owner.currentContentGroup.GetMembers())
|
||||
{
|
||||
var chara = owner.zone.FindActorInArea<Character>(charaId);
|
||||
|
||||
if (chara != null)
|
||||
contentGroupCharas.Add(chara);
|
||||
}
|
||||
contentGroupCharas = GetContentGroupCharas();
|
||||
}
|
||||
base.DoRoamTick(tick, contentGroupCharas);
|
||||
}
|
||||
|
|
|
@ -39,12 +39,20 @@ 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())
|
||||
if (!owner.aiContainer.IsEngaged())
|
||||
{
|
||||
DoCombatTick(tick);
|
||||
TryAggro(tick);
|
||||
}
|
||||
else if (!owner.IsDead())
|
||||
|
||||
if(owner.aiContainer.IsEngaged())
|
||||
{
|
||||
//DoCombatTick(tick);
|
||||
}
|
||||
|
||||
//Only move if owner isn't dead and is either too far away from their spawn point or is meant to roam
|
||||
if (!owner.IsDead() && (owner.isMovingToSpawn || owner.GetMobMod((uint) MobModifier.Roams) > 0))
|
||||
{
|
||||
DoRoamTick(tick);
|
||||
}
|
||||
|
@ -63,6 +71,38 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
|||
return false;
|
||||
}
|
||||
|
||||
//If the owner isn't moving to spawn, iterate over nearby enemies and
|
||||
//aggro the first one that is within 10 levels and can be detected, then engage
|
||||
protected virtual void TryAggro(DateTime tick)
|
||||
{
|
||||
if (tick >= neutralTime && !owner.isMovingToSpawn)
|
||||
{
|
||||
if (!owner.neutral && owner.IsAlive())
|
||||
{
|
||||
foreach (var chara in owner.zone.GetActorsAroundActor<Character>(owner, 50))
|
||||
{
|
||||
if (owner.allegiance == chara.allegiance)
|
||||
continue;
|
||||
|
||||
if (owner.aiContainer.pathFind.AtPoint() && owner.detectionType != DetectionType.None)
|
||||
{
|
||||
uint levelDifference = (uint)Math.Abs(owner.GetLevel() - chara.GetLevel());
|
||||
|
||||
if (levelDifference <= 10 || (owner.detectionType & DetectionType.IgnoreLevelDifference) != 0 && CanAggroTarget(chara))
|
||||
{
|
||||
owner.hateContainer.AddBaseHate(chara);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (owner.hateContainer.GetHateList().Count > 0)
|
||||
{
|
||||
Engage(owner.hateContainer.GetMostHatedTarget());
|
||||
}
|
||||
}
|
||||
public override bool Engage(Character target)
|
||||
{
|
||||
var canEngage = this.owner.aiContainer.InternalEngage(target);
|
||||
|
@ -77,6 +117,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
|||
owner.ChangeState(SetActorStatePacket.MAIN_STATE_ACTIVE);
|
||||
|
||||
owner.moveState = 2;
|
||||
//owner.SetMod((uint)Modifier.Speed, 5);
|
||||
lastActionTime = DateTime.Now;
|
||||
battleStartTime = lastActionTime;
|
||||
// todo: adjust cooldowns with modifiers
|
||||
|
@ -127,12 +168,6 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
|||
|
||||
protected virtual void DoRoamTick(DateTime tick, List<Character> contentGroupCharas = null)
|
||||
{
|
||||
if (owner.hateContainer.GetHateList().Count > 0)
|
||||
{
|
||||
Engage(owner.hateContainer.GetMostHatedTarget());
|
||||
return;
|
||||
}
|
||||
|
||||
if (tick >= waitTime)
|
||||
{
|
||||
neutralTime = tick.AddSeconds(5);
|
||||
|
@ -148,7 +183,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
|||
|
||||
}
|
||||
}
|
||||
waitTime = tick.AddSeconds(10);
|
||||
waitTime = tick.AddSeconds(owner.GetMobMod((uint) MobModifier.RoamDelay));
|
||||
owner.OnRoam(tick);
|
||||
|
||||
if (CanMoveForward(0.0f) && !owner.aiContainer.pathFind.IsFollowingPath())
|
||||
|
@ -157,31 +192,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
|||
owner.aiContainer.pathFind.SetPathFlags(PathFindFlags.None);
|
||||
owner.aiContainer.pathFind.PathInRange(owner.spawnX, owner.spawnY, owner.spawnZ, 1.5f, 50.0f);
|
||||
}
|
||||
lua.LuaEngine.CallLuaBattleFunction(owner, "onRoam", owner, contentGroupCharas);
|
||||
}
|
||||
|
||||
|
||||
if (tick >= neutralTime)
|
||||
{
|
||||
if (!owner.neutral && owner.IsAlive())
|
||||
{
|
||||
foreach (var chara in owner.zone.GetActorsAroundActor<Character>(owner, 50))
|
||||
{
|
||||
if (owner.allegiance == chara.allegiance)
|
||||
continue;
|
||||
|
||||
if (!owner.isMovingToSpawn && owner.aiContainer.pathFind.AtPoint() && owner.detectionType != DetectionType.None)
|
||||
{
|
||||
uint levelDifference = (uint)Math.Abs(owner.GetLevel() - chara.GetLevel());
|
||||
|
||||
if (levelDifference <= 10 || (owner.detectionType & DetectionType.IgnoreLevelDifference) != 0 && CanAggroTarget(chara))
|
||||
{
|
||||
owner.hateContainer.AddBaseHate(chara);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//lua.LuaEngine.CallLuaBattleFunction(owner, "onRoam", owner, contentGroupCharas);
|
||||
}
|
||||
|
||||
if (owner.aiContainer.pathFind.IsFollowingPath() && owner.aiContainer.CanFollowPath())
|
||||
|
@ -200,7 +211,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
Move();
|
||||
|
||||
if ((tick - lastCombatTickScript).TotalSeconds > 2)
|
||||
{
|
||||
lua.LuaEngine.CallLuaBattleFunction(owner, "onCombatTick", owner, owner.target, Utils.UnixTimeStampUTC(tick), contentGroupCharas);
|
||||
|
|
|
@ -159,6 +159,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||
/// </summary>
|
||||
public void FindWithinArea(Character target, ValidTarget flags, TargetFindAOETarget aoeTarget)
|
||||
{
|
||||
targets.Clear();
|
||||
validTarget = flags;
|
||||
// are we creating aoe circles around target or self
|
||||
if (aoeTarget == TargetFindAOETarget.Self)
|
||||
|
@ -174,59 +175,63 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||
if (masterTarget != null)
|
||||
targets.Add(masterTarget);
|
||||
|
||||
if (IsPlayer(owner))
|
||||
if (aoeType != TargetFindAOEType.None)
|
||||
{
|
||||
if (masterTarget is Player)
|
||||
if (IsPlayer(owner))
|
||||
{
|
||||
findType = TargetFindCharacterType.PlayerToPlayer;
|
||||
|
||||
if (masterTarget.currentParty != null)
|
||||
if (masterTarget is Player)
|
||||
{
|
||||
if ((validTarget & (ValidTarget.Ally | ValidTarget.PartyMember)) != 0)
|
||||
AddAllInAlliance(masterTarget, withPet);
|
||||
findType = TargetFindCharacterType.PlayerToPlayer;
|
||||
|
||||
if (masterTarget.currentParty != null)
|
||||
{
|
||||
if ((validTarget & (ValidTarget.Ally | ValidTarget.PartyMember)) != 0)
|
||||
AddAllInAlliance(masterTarget, withPet);
|
||||
else
|
||||
AddAllInParty(masterTarget, withPet);
|
||||
}
|
||||
else
|
||||
AddAllInParty(masterTarget, withPet);
|
||||
{
|
||||
AddTarget(masterTarget, withPet);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddTarget(masterTarget, withPet);
|
||||
findType = TargetFindCharacterType.PlayerToBattleNpc;
|
||||
AddAllBattleNpcs(masterTarget, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
findType = TargetFindCharacterType.PlayerToBattleNpc;
|
||||
AddAllBattleNpcs(masterTarget, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// todo: this needs checking..
|
||||
if (masterTarget is Player || owner.allegiance == CharacterTargetingAllegiance.Player)
|
||||
findType = TargetFindCharacterType.BattleNpcToPlayer;
|
||||
else
|
||||
findType = TargetFindCharacterType.BattleNpcToBattleNpc;
|
||||
|
||||
// todo: configurable pet aoe buff
|
||||
if (findType == TargetFindCharacterType.BattleNpcToBattleNpc && TryGetMasterTarget(target) != null)
|
||||
withPet = true;
|
||||
|
||||
// todo: does ffxiv have call for help flag?
|
||||
//if ((findFlags & ValidTarget.HitAll) != 0)
|
||||
//{
|
||||
// AddAllInZone(masterTarget, withPet);
|
||||
//}
|
||||
|
||||
AddAllInAlliance(target, withPet);
|
||||
|
||||
if (findType == TargetFindCharacterType.BattleNpcToPlayer)
|
||||
{
|
||||
if (owner.allegiance == CharacterTargetingAllegiance.Player)
|
||||
AddAllInZone(masterTarget, withPet);
|
||||
// todo: this needs checking..
|
||||
if (masterTarget is Player || owner.allegiance == CharacterTargetingAllegiance.Player)
|
||||
findType = TargetFindCharacterType.BattleNpcToPlayer;
|
||||
else
|
||||
AddAllInHateList();
|
||||
findType = TargetFindCharacterType.BattleNpcToBattleNpc;
|
||||
|
||||
// todo: configurable pet aoe buff
|
||||
if (findType == TargetFindCharacterType.BattleNpcToBattleNpc && TryGetMasterTarget(target) != null)
|
||||
withPet = true;
|
||||
|
||||
// todo: does ffxiv have call for help flag?
|
||||
//if ((findFlags & ValidTarget.HitAll) != 0)
|
||||
//{
|
||||
// AddAllInZone(masterTarget, withPet);
|
||||
//}
|
||||
|
||||
AddAllInAlliance(target, withPet);
|
||||
|
||||
if (findType == TargetFindCharacterType.BattleNpcToPlayer)
|
||||
{
|
||||
if (owner.allegiance == CharacterTargetingAllegiance.Player)
|
||||
AddAllInZone(masterTarget, withPet);
|
||||
else
|
||||
AddAllInHateList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(targets.Count > 16)
|
||||
targets.RemoveRange(16, targets.Count - 16);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -288,7 +293,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||
|
||||
private void AddAllBattleNpcs(Character target, bool withPet)
|
||||
{
|
||||
var actors = owner.zone.GetActorsAroundActor<BattleNpc>(owner, 50);
|
||||
int dist = (int)maxDistance;
|
||||
var actors = owner.zone.GetActorsAroundActor<BattleNpc>(target, dist);
|
||||
|
||||
foreach (BattleNpc actor in actors)
|
||||
{
|
||||
|
@ -375,12 +381,13 @@ 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 (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);
|
||||
return target.GetPosAsVector3().IsWithinCircle(targetPosition, maxDistance);
|
||||
}
|
||||
|
||||
private bool IsPlayer(Character target)
|
||||
|
|
|
@ -129,6 +129,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||
|
||||
private bool CanAttack()
|
||||
{
|
||||
return false;
|
||||
if (!owner.isAutoAttackEnabled)
|
||||
{
|
||||
return false;
|
||||
|
|
|
@ -15,7 +15,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||
: base(owner, null)
|
||||
{
|
||||
owner.Disengage();
|
||||
owner.ChangeState(SetActorStatePacket.MAIN_STATE_DEAD2);
|
||||
//owner.ChangeState(SetActorStatePacket.MAIN_STATE_DEAD2);
|
||||
var deathStatePacket = SetActorStatePacket.BuildPacket(owner.actorId, SetActorStatePacket.MAIN_STATE_DEAD, owner.currentSubState);
|
||||
owner.zone.BroadcastPacketAroundActor(owner, deathStatePacket);
|
||||
canInterrupt = false;
|
||||
startTime = tick;
|
||||
despawnTime = startTime.AddSeconds(timeToFadeOut);
|
||||
|
|
|
@ -110,16 +110,16 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||
var i = 0;
|
||||
foreach (var chara in targets)
|
||||
{
|
||||
var action = new BattleAction(target.actorId, spell.worldMasterTextId, spell.battleAnimation, 0, (byte)HitDirection.None, 1);
|
||||
var action = new BattleAction(chara.actorId, spell.worldMasterTextId, spell.battleAnimation, 0, (byte)HitDirection.None, 1);
|
||||
action.amount = (ushort)lua.LuaEngine.CallLuaBattleCommandFunction(owner, spell, "magic", "onMagicFinish", owner, chara, spell, action);
|
||||
actions[i++] = action;
|
||||
}
|
||||
|
||||
// todo: this is fuckin stupid, probably only need *one* error packet, not an error for each action
|
||||
var errors = (BattleAction[])actions.Clone();
|
||||
|
||||
owner.OnCast(this, actions, ref errors);
|
||||
owner.DoBattleAction(spell.id, spell.battleAnimation, actions);
|
||||
|
||||
}
|
||||
|
||||
public override void TryInterrupt()
|
||||
|
|
|
@ -88,7 +88,6 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||
{
|
||||
skill.targetFind.FindWithinArea(target, skill.validTarget, skill.aoeTarget);
|
||||
isCompleted = true;
|
||||
|
||||
var targets = skill.targetFind.GetTargets();
|
||||
|
||||
BattleAction[] actions = new BattleAction[targets.Count];
|
||||
|
@ -100,11 +99,11 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||
// 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;
|
||||
chara.Engage(chara.actorId, 1);
|
||||
}
|
||||
|
||||
// todo: this is fuckin stupid, probably only need *one* error packet, not an error for each action
|
||||
var errors = (BattleAction[])actions.Clone();
|
||||
|
||||
owner.OnWeaponSkill(this, actions, ref errors);
|
||||
owner.DoBattleAction(skill.id, skill.battleAnimation, actions);
|
||||
}
|
||||
|
|
|
@ -76,18 +76,24 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.utils
|
|||
return damage;
|
||||
}
|
||||
|
||||
public static void DamageTarget(Character attacker, Character defender, BattleAction action)
|
||||
public static void DamageTarget(Character attacker, Character defender, BattleAction action, DamageTakenType type)
|
||||
{
|
||||
// todo: other stuff too
|
||||
if (defender is BattleNpc)
|
||||
if (defender != null)
|
||||
{
|
||||
if (!((BattleNpc)defender).hateContainer.HasHateForTarget(attacker))
|
||||
// todo: other stuff too
|
||||
if (defender is BattleNpc)
|
||||
{
|
||||
((BattleNpc)defender).hateContainer.AddBaseHate(attacker);
|
||||
var bnpc = defender as BattleNpc;
|
||||
if (!bnpc.hateContainer.HasHateForTarget(attacker))
|
||||
{
|
||||
bnpc.hateContainer.AddBaseHate(attacker);
|
||||
}
|
||||
bnpc.hateContainer.UpdateHate(attacker, action.amount);
|
||||
bnpc.lastAttacker = attacker;
|
||||
}
|
||||
((BattleNpc)defender).hateContainer.UpdateHate(attacker, action.amount);
|
||||
defender.DelHP((short)action.amount);
|
||||
defender.OnDamageTaken(attacker, action, type);
|
||||
}
|
||||
defender.DelHP((short)action.amount);
|
||||
}
|
||||
|
||||
public static int CalculateSpellDamage(Character attacker, Character defender, BattleCommand spell)
|
||||
|
|
|
@ -172,7 +172,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
packets = new List<SubPacket>();
|
||||
if ((updateFlags & ActorUpdateFlags.HpTpMp) != 0)
|
||||
{
|
||||
var propPacketUtil = new ActorPropertyPacketUtil("charaWork.parameterSave", this);
|
||||
var propPacketUtil = new ActorPropertyPacketUtil("charaWork/stateAtQuicklyForAll", this);
|
||||
|
||||
propPacketUtil.AddProperty("charaWork.parameterSave.hp[0]");
|
||||
propPacketUtil.AddProperty("charaWork.parameterSave.hpMax[0]");
|
||||
|
@ -272,6 +272,10 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
|
||||
if (lastAttacker is Player)
|
||||
{
|
||||
//I think this is, or should be odne in DoBattleAction. Packet capture had the message in the same packet as an attack
|
||||
// <actor> defeat/defeats <target>
|
||||
//((Player)lastAttacker).QueuePacket(BattleActionX01Packet.BuildPacket(lastAttacker.actorId, 0, 0, new BattleAction(actorId, 30108, 0)));
|
||||
|
||||
if (lastAttacker.currentParty != null && lastAttacker.currentParty is Party)
|
||||
{
|
||||
foreach (var memberId in ((Party)lastAttacker.currentParty).members)
|
||||
|
@ -279,14 +283,9 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
var partyMember = zone.FindActorInArea<Player>(memberId);
|
||||
// onDeath(monster, player, killer)
|
||||
lua.LuaEngine.CallLuaBattleFunction(this, "onDeath", this, partyMember, lastAttacker);
|
||||
// <actor> defeat/defeats <target>
|
||||
|
||||
if (lastAttacker is Player)
|
||||
((Player)lastAttacker).QueuePacket(BattleActionX01Packet.BuildPacket(lastAttacker.actorId, 0, 0, new BattleAction(actorId, 30108, 0)));
|
||||
|
||||
if(partyMember is Player)
|
||||
((Player)partyMember).AddExp(1500, (byte)partyMember.GetJob(), 5);
|
||||
|
||||
if (partyMember is Player)
|
||||
((Player)partyMember).AddExp(1500, (byte)partyMember.GetClass(), 5);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -298,6 +297,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
}
|
||||
positionUpdates?.Clear();
|
||||
aiContainer.InternalDie(tick, despawnTime);
|
||||
//this.ResetMoveSpeeds();
|
||||
// todo: reset cooldowns
|
||||
|
||||
lua.LuaEngine.GetInstance().OnSignal("mobkill");
|
||||
|
|
|
@ -32,5 +32,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.npc
|
|||
AbilityScript = 21, // call my script's onAbility whenever i finish using an ability
|
||||
CallForHelp = 22, // actor with this id outside of target's party with this can attack me
|
||||
FreeForAll = 23, // any actor can attack me
|
||||
Roams = 24, // Do I walk around?
|
||||
RoamDelay = 25 // What is the delay between roam ticks
|
||||
}
|
||||
}
|
|
@ -557,6 +557,9 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
|
||||
if (currentContentGroup != null)
|
||||
currentContentGroup.SendGroupPackets(playerSession);
|
||||
|
||||
if (currentParty != null)
|
||||
currentParty.SendGroupPackets(playerSession);
|
||||
}
|
||||
|
||||
private void SendRemoveInventoryPackets(List<ushort> slots)
|
||||
|
@ -1625,7 +1628,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
//Update Instance
|
||||
List<Actor> aroundMe = new List<Actor>();
|
||||
|
||||
if (zone != null)
|
||||
if (zone != null)
|
||||
aroundMe.AddRange(zone.GetActorsAroundActor(this, 50));
|
||||
if (zone2 != null)
|
||||
aroundMe.AddRange(zone2.GetActorsAroundActor(this, 50));
|
||||
|
@ -1714,6 +1717,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
//currentParty.members.Remove(this);
|
||||
if (partyGroup.members.Count == 0)
|
||||
Server.GetWorldManager().NoMembersInParty((Party)currentParty);
|
||||
|
||||
currentParty = null;
|
||||
}
|
||||
|
||||
|
@ -1755,7 +1759,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
|
||||
if ((updateFlags & ActorUpdateFlags.HpTpMp) != 0)
|
||||
{
|
||||
var propPacketUtil = new ActorPropertyPacketUtil("charaWork.parameterSave", this);
|
||||
var propPacketUtil = new ActorPropertyPacketUtil("charaWork/stateAtQuicklyForAll", this);
|
||||
|
||||
// todo: should this be using job as index?
|
||||
propPacketUtil.AddProperty($"charaWork.parameterSave.hp[{0}]");
|
||||
|
@ -1768,9 +1772,6 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
}
|
||||
|
||||
base.PostUpdate(tick, packets);
|
||||
SetActorPropetyPacket hpInfo = new SetActorPropetyPacket("charaWork/exp");
|
||||
hpInfo.AddTarget();
|
||||
QueuePacket(hpInfo.BuildPacket(actorId));
|
||||
}
|
||||
|
||||
public override void Die(DateTime tick)
|
||||
|
@ -1801,7 +1802,6 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
public void UpdateHotbarCommands(List<ushort> slotsToUpdate)
|
||||
{
|
||||
ActorPropertyPacketUtil propPacketUtil = new ActorPropertyPacketUtil("charaWork/command", this);
|
||||
ActorPropertyPacketUtil compatibiltyUtil = new ActorPropertyPacketUtil("charaWork/commandDetailForSelf", this);
|
||||
foreach (ushort slot in slotsToUpdate)
|
||||
{
|
||||
propPacketUtil.AddProperty($"charaWork.command[{slot}]");
|
||||
|
@ -2184,9 +2184,9 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
{
|
||||
// todo: update hotbar timers to skill's recast time (also needs to be done on class change or equip crap)
|
||||
base.OnCast(state, actions, ref errors);
|
||||
|
||||
var spell = ((MagicState)state).GetSpell();
|
||||
// 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(spell.id, spell.recastTimeSeconds);
|
||||
LuaEngine.GetInstance().OnSignal("spellUse");
|
||||
}
|
||||
|
@ -2309,27 +2309,23 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
Database.LoadHotbar(this);
|
||||
}
|
||||
|
||||
//Gets the id of the player's current job. If they aren't a job, gets the id of their class
|
||||
public byte GetCurrentClassOrJob()
|
||||
{
|
||||
if (currentJob != 0)
|
||||
return (byte) currentJob;
|
||||
|
||||
return charaWork.parameterSave.state_mainSkill[0];
|
||||
}
|
||||
|
||||
public void hpstuff(uint hp)
|
||||
{
|
||||
SetMaxHP(hp);
|
||||
SetHP(hp);
|
||||
SetHP(hp);
|
||||
mpMaxBase = (ushort)hp;
|
||||
charaWork.parameterSave.mpMax = (short)hp;
|
||||
charaWork.parameterSave.mp = (short)hp;
|
||||
AddTP(0);
|
||||
//SendCharaExpInfo();
|
||||
//ActorPropertyPacketUtil exp = new ActorPropertyPacketUtil("charaWork/exp", this);
|
||||
SetActorPropetyPacket hpInfo = new SetActorPropetyPacket("charaWork/exp");
|
||||
hpInfo.AddTarget();
|
||||
QueuePacket(hpInfo.BuildPacket(actorId));
|
||||
AddTP(3000);
|
||||
updateFlags |= ActorUpdateFlags.HpTpMp;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -161,6 +161,9 @@ namespace FFXIVClassic_Map_Server.actors.director
|
|||
{
|
||||
members.Add(actor);
|
||||
|
||||
if (actor is Player)
|
||||
((Player)actor).AddDirector(this);
|
||||
|
||||
if (contentGroup != null)
|
||||
contentGroup.AddMember(actor);
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ namespace FFXIVClassic_Map_Server.actors.group
|
|||
public void Start()
|
||||
{
|
||||
isStarted = true;
|
||||
|
||||
SendGroupPacketsAll(members);
|
||||
}
|
||||
|
||||
|
@ -50,7 +51,8 @@ namespace FFXIVClassic_Map_Server.actors.group
|
|||
if (actor == null)
|
||||
return;
|
||||
|
||||
members.Add(actor.actorId);
|
||||
if(!members.Contains(actor.actorId))
|
||||
members.Add(actor.actorId);
|
||||
|
||||
if (actor is Character)
|
||||
((Character)actor).SetCurrentContentGroup(this);
|
||||
|
@ -121,7 +123,6 @@ namespace FFXIVClassic_Map_Server.actors.group
|
|||
}
|
||||
|
||||
session.QueuePacket(GroupMembersEndPacket.buildPacket(session.id, session.GetActor().zoneId, time, this));
|
||||
|
||||
}
|
||||
|
||||
public override uint GetTypeId()
|
||||
|
|
|
@ -63,12 +63,24 @@ namespace FFXIVClassic_Map_Server.actors.group
|
|||
List<GroupMember> groupMembers = new List<GroupMember>();
|
||||
groupMembers.Add(new GroupMember(id, -1, 0, false, true, Server.GetWorldManager().GetActorInWorld(id).customDisplayName));
|
||||
foreach (uint charaId in members)
|
||||
{
|
||||
if (charaId != id)
|
||||
groupMembers.Add(new GroupMember(charaId, -1, 0, false, true, Server.GetWorldManager().GetActorInWorld(charaId).customDisplayName));
|
||||
{
|
||||
var chara = Server.GetWorldManager().GetActorInWorld(charaId);
|
||||
if (charaId != id && chara != null)
|
||||
groupMembers.Add(new GroupMember(charaId, -1, 0, false, true, chara.customDisplayName));
|
||||
}
|
||||
return groupMembers;
|
||||
}
|
||||
|
||||
public void AddMember(uint memberId)
|
||||
{
|
||||
members.Add(memberId);
|
||||
SendGroupPacketsAll(members);
|
||||
}
|
||||
|
||||
public void RemoveMember(uint memberId)
|
||||
{
|
||||
members.Remove(memberId);
|
||||
SendGroupPacketsAll(members);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace FFXIVClassic_Map_Server.dataobjects
|
|||
|
||||
public void FlushQueuedSendPackets()
|
||||
{
|
||||
if (!socket.Connected)
|
||||
if (socket == null || !socket.Connected)
|
||||
return;
|
||||
|
||||
while (SendPacketQueue.Count > 0)
|
||||
|
|
|
@ -478,10 +478,18 @@ namespace FFXIVClassic_Map_Server.lua
|
|||
{
|
||||
if (!script.Globals.Get(funcName).IsNil())
|
||||
{
|
||||
Coroutine coroutine = script.CreateCoroutine(script.Globals[funcName]).Coroutine;
|
||||
DynValue value = coroutine.Resume(args2);
|
||||
ResolveResume(player, coroutine, value);
|
||||
|
||||
try
|
||||
{
|
||||
Coroutine coroutine = script.CreateCoroutine(script.Globals[funcName]).Coroutine;
|
||||
DynValue value = coroutine.Resume(args2);
|
||||
ResolveResume(player, coroutine, value);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
player.SendMessage(0x20, "", e.Message);
|
||||
player.EndEvent();
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -112,7 +112,6 @@ namespace FFXIVClassic_Map_Server.packets.send.actor
|
|||
{
|
||||
string[] split = name.Split('.');
|
||||
int arrayIndex = 0;
|
||||
|
||||
if (!(split[0].Equals("work") || split[0].Equals("charaWork") || split[0].Equals("playerWork") || split[0].Equals("npcWork") || split[0].Equals("guildleveWork")))
|
||||
return false;
|
||||
|
||||
|
|
|
@ -35,33 +35,33 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle
|
|||
binWriter.Write((UInt16)commandId);
|
||||
binWriter.Write((UInt16)0x810); //?
|
||||
|
||||
binWriter.Seek(0x58, SeekOrigin.Begin);
|
||||
binWriter.Seek(0x28, SeekOrigin.Begin);
|
||||
for (int i = 0; i < max; i++)
|
||||
binWriter.Write((UInt32)actionList[listOffset + i].targetId);
|
||||
|
||||
binWriter.Seek(0xA0, SeekOrigin.Begin);
|
||||
binWriter.Seek(0x70, SeekOrigin.Begin);
|
||||
for (int i = 0; i < max; i++)
|
||||
binWriter.Write((UInt16)actionList[listOffset + i].amount);
|
||||
|
||||
binWriter.Seek(0xC4, SeekOrigin.Begin);
|
||||
binWriter.Seek(0x94, SeekOrigin.Begin);
|
||||
for (int i = 0; i < max; i++)
|
||||
binWriter.Write((UInt16)actionList[listOffset + i].worldMasterTextId);
|
||||
|
||||
binWriter.Seek(0xE8, SeekOrigin.Begin);
|
||||
binWriter.Seek(0xB8, SeekOrigin.Begin);
|
||||
for (int i = 0; i < max; i++)
|
||||
binWriter.Write((UInt32)actionList[listOffset + i].effectId);
|
||||
|
||||
binWriter.Seek(0x130, SeekOrigin.Begin);
|
||||
binWriter.Seek(0x100, SeekOrigin.Begin);
|
||||
for (int i = 0; i < max; i++)
|
||||
binWriter.Write((Byte)actionList[listOffset + i].param);
|
||||
|
||||
binWriter.Seek(0x142, SeekOrigin.Begin);
|
||||
binWriter.Seek(0x112, SeekOrigin.Begin);
|
||||
for (int i = 0; i < max; i++)
|
||||
binWriter.Write((Byte)actionList[listOffset + i].unknown);
|
||||
|
||||
listOffset += max;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new SubPacket(OPCODE, sourceActorId, data);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue