mirror of
https://bitbucket.org/Ioncannon/project-meteor-server.git
synced 2025-07-24 11:28:22 +02:00
Added party to Gridania opening, fixed BattleActionx18 and made it so x18 is used for packets with more than 10 targets. Changed how death works. Added respawn time and roam modifiers. Added TryAggro functions and moved aggroing out of roaming and helpplayers. Fixed high cpu usage in zone's OnUpdate function. Fixed work value in player update
This commit is contained in:
parent
520ae7a119
commit
1275c8b5da
61 changed files with 1226 additions and 223 deletions
|
@ -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,6 +419,11 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
public virtual List<BattleNpc> GetMonsters()
|
||||
{
|
||||
return GetAllActors<BattleNpc>();
|
||||
}
|
||||
|
||||
public virtual List<Ally> GetAllies()
|
||||
{
|
||||
return GetAllActors<Ally>();
|
||||
}
|
||||
|
||||
public void BroadcastPacketsAroundActor(Actor actor, List<SubPacket> packets)
|
||||
|
@ -495,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);
|
||||
|
||||
|
@ -666,7 +671,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
a.Update(tick);
|
||||
|
||||
var deltaTime = (tick - Program.LastTick).TotalMilliseconds;
|
||||
LuaEngine.GetInstance().CallLuaFunction(null, this, "onUpdate", true, deltaTime, this);
|
||||
//LuaEngine.GetInstance().CallLuaFunction(null, this, "onUpdate", true, this, deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -230,10 +230,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));
|
||||
|
@ -244,7 +244,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.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -313,7 +315,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;
|
||||
|
@ -347,7 +349,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");
|
||||
|
@ -470,6 +472,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)
|
||||
|
@ -543,6 +546,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)
|
||||
{
|
||||
|
@ -562,7 +579,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
}
|
||||
}
|
||||
|
||||
public short GetJob()
|
||||
public short GetClass()
|
||||
{
|
||||
return charaWork.parameterSave.state_mainSkill[0];
|
||||
}
|
||||
|
@ -614,8 +631,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;
|
||||
|
@ -650,9 +689,10 @@ 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);
|
||||
BattleUtils.DamageTarget(this, target, action);
|
||||
target.OnDamageTaken(this, action, DamageTakenType.Ability);
|
||||
|
||||
if (target is BattleNpc)
|
||||
((BattleNpc)target).lastAttacker = this;
|
||||
|
||||
|
@ -664,13 +704,26 @@ 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)
|
||||
{
|
||||
if (chara != null && chara is BattleNpc)
|
||||
{
|
||||
((BattleNpc)chara).hateContainer.UpdateHate(this, action.amount);
|
||||
((BattleNpc)chara).lastAttacker = this;
|
||||
}
|
||||
|
||||
BattleUtils.DamageTarget(this, chara, action);
|
||||
}
|
||||
}
|
||||
|
||||
if (target is BattleNpc)
|
||||
((BattleNpc)target).lastAttacker = this;
|
||||
|
||||
lua.LuaEngine.GetInstance().OnSignal("spellUsed");
|
||||
}
|
||||
|
||||
public virtual void OnWeaponSkill(State state, BattleAction[] actions, ref BattleAction[] errors)
|
||||
|
@ -679,11 +732,25 @@ 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)
|
||||
{
|
||||
if (chara != null && chara is BattleNpc)
|
||||
{
|
||||
((BattleNpc)chara).hateContainer.UpdateHate(this, action.amount);
|
||||
((BattleNpc)chara).lastAttacker = this;
|
||||
}
|
||||
|
||||
BattleUtils.DamageTarget(this, chara, action);
|
||||
}
|
||||
}
|
||||
|
||||
if (target is BattleNpc)
|
||||
((BattleNpc)target).lastAttacker = this;
|
||||
|
||||
|
||||
lua.LuaEngine.GetInstance().OnSignal("weaponskillUsed");
|
||||
}
|
||||
|
||||
public virtual void OnAbility(State state, BattleAction[] actions, ref BattleAction[] errors)
|
||||
|
@ -769,22 +836,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())
|
||||
{
|
||||
TryAggro(tick);
|
||||
}
|
||||
|
||||
if(owner.aiContainer.IsEngaged())
|
||||
{
|
||||
DoCombatTick(tick);
|
||||
}
|
||||
else if (!owner.IsDead())
|
||||
|
||||
//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
|
||||
|
@ -129,12 +170,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);
|
||||
|
@ -150,7 +185,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())
|
||||
|
@ -159,31 +194,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())
|
||||
|
@ -202,8 +213,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
Move();
|
||||
lua.LuaEngine.CallLuaBattleFunction(owner, "onCombatTick", owner, owner.target, Utils.UnixTimeStampUTC(tick), contentGroupCharas);
|
||||
}
|
||||
|
||||
protected virtual void Move()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,12 +99,12 @@ 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.OnWeaponSkill(this, actions, ref errors);
|
||||
owner.DoBattleAction(skill.id, skill.battleAnimation, actions);
|
||||
}
|
||||
|
||||
|
|
|
@ -78,16 +78,19 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.utils
|
|||
|
||||
public static void DamageTarget(Character attacker, Character defender, BattleAction action)
|
||||
{
|
||||
// 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);
|
||||
if (!((BattleNpc)defender).hateContainer.HasHateForTarget(attacker))
|
||||
{
|
||||
((BattleNpc)defender).hateContainer.AddBaseHate(attacker);
|
||||
}
|
||||
((BattleNpc)defender).hateContainer.UpdateHate(attacker, action.amount);
|
||||
}
|
||||
((BattleNpc)defender).hateContainer.UpdateHate(attacker, action.amount);
|
||||
defender.DelHP((short)action.amount);
|
||||
}
|
||||
defender.DelHP((short)action.amount);
|
||||
}
|
||||
|
||||
public static int CalculateSpellDamage(Character attacker, Character defender, BattleCommand spell)
|
||||
|
|
|
@ -177,7 +177,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]");
|
||||
|
@ -290,6 +290,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)
|
||||
|
@ -297,14 +301,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
|
||||
|
@ -317,7 +316,6 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
positionUpdates?.Clear();
|
||||
aiContainer.InternalDie(tick, despawnTime);
|
||||
this.ResetMoveSpeeds();
|
||||
|
||||
// todo: reset cooldowns
|
||||
|
||||
lua.LuaEngine.GetInstance().OnSignal("mobkill");
|
||||
|
@ -381,6 +379,9 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
|
||||
if (GetMobMod((uint)MobModifier.AttackScript) != 0)
|
||||
lua.LuaEngine.CallLuaBattleFunction(this, "onAttack", this, state.GetTarget(), action.amount);
|
||||
|
||||
if (target is BattleNpc)
|
||||
((BattleNpc)target).hateContainer.UpdateHate(this, action.amount);
|
||||
}
|
||||
|
||||
public override void OnCast(State state, BattleAction[] actions, ref BattleAction[] errors)
|
||||
|
@ -390,6 +391,19 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
if (GetMobMod((uint)MobModifier.SpellScript) != 0)
|
||||
foreach (var action in actions)
|
||||
lua.LuaEngine.CallLuaBattleFunction(this, "onCast", this, zone.FindActorInArea<Character>(action.targetId), ((MagicState)state).GetSpell(), action);
|
||||
|
||||
foreach (BattleAction action in actions)
|
||||
{
|
||||
if (zone.FindActorInArea<Character>(action.targetId) is Character chara)
|
||||
{
|
||||
if (chara is BattleNpc)
|
||||
{
|
||||
((BattleNpc)chara).hateContainer.UpdateHate(this, action.amount);
|
||||
((BattleNpc)chara).lastAttacker = this;
|
||||
}
|
||||
BattleUtils.DamageTarget(this, chara, action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnAbility(State state, BattleAction[] actions, ref BattleAction[] errors)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -2300,27 +2300,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()
|
||||
|
|
|
@ -64,11 +64,23 @@ namespace FFXIVClassic_Map_Server.actors.group
|
|||
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