mirror of
https://bitbucket.org/Ioncannon/project-meteor-server.git
synced 2025-07-26 04:18:22 +02:00
Combat changes and bug fixes
Added the combo and proc systems Added scripts for most weaponskill and spells as well as some abilities and status effects Added support for multihit attacks Added AbilityState for abilities Added hiteffects that change based on an attack's parameters Added positionals Changed how targeting works for battlecommands Fixed bug that occurred when moving or swapping hotbar commands Fixed bug that occurred when losing status effects
This commit is contained in:
parent
837c7a9223
commit
b8d6a943aa
175 changed files with 4361 additions and 1213 deletions
|
@ -1,5 +1,10 @@
|
|||
using FFXIVClassic.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using FFXIVClassic_Map_Server.actors.chara.ai;
|
||||
using FFXIVClassic_Map_Server.actors.chara.ai.utils;
|
||||
using FFXIVClassic_Map_Server.Actors;
|
||||
using FFXIVClassic_Map_Server.packets.send.actor.battle;
|
||||
|
||||
namespace FFXIVClassic_Map_Server.packets.send.actor.battle
|
||||
{
|
||||
|
@ -9,13 +14,18 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle
|
|||
{
|
||||
//All HitEffects have the last byte 0x8
|
||||
HitEffectType = 8 << 24,
|
||||
//Status effects use 32 << 24
|
||||
StatusEffectType = 32 << 24,
|
||||
//Magic effects use 48 << 24
|
||||
MagicEffectType = 48 << 24,
|
||||
|
||||
//Not setting RecoilLv2 or RecoilLv3 results in the weaker RecoilLv1.
|
||||
//These are the recoil animations that play on the target, ranging from weak to strong.
|
||||
//The recoil that gets set was likely based on the percentage of HP lost from the attack.
|
||||
RecoilLv1 = 0 | HitEffectType,
|
||||
RecoilLv2 = 1 << 0 | HitEffectType,
|
||||
RecoilLv3 = 1 << 1 | HitEffectType,
|
||||
//These also have a visual effect with heals but in reverse. RecoilLv1 has a large effect, Lv3 has none. Crit is very large
|
||||
RecoilLv1 = 0,
|
||||
RecoilLv2 = 1 << 0,
|
||||
RecoilLv3 = 1 << 1,
|
||||
|
||||
//Setting both recoil flags triggers the "Critical!" pop-up text and hit visual effect.
|
||||
CriticalHit = RecoilLv2 | RecoilLv3,
|
||||
|
@ -24,10 +34,19 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle
|
|||
//Mixing these flags together will yield different results.
|
||||
//Each visual likely relates to a specific weapon.
|
||||
//Ex: HitVisual4 flag alone appears to be the visual and sound effect for hand-to-hand attacks.
|
||||
HitVisual1 = 1 << 2 | HitEffectType,
|
||||
HitVisual2 = 1 << 3 | HitEffectType,
|
||||
HitVisual3 = 1 << 4 | HitEffectType,
|
||||
HitVisual4 = 1 << 5 | HitEffectType,
|
||||
|
||||
//HitVisual is probably based on attack property.
|
||||
//HitVisual1 is for slashing attacks
|
||||
//HitVisual2 is for piercing attacks
|
||||
//HitVisual1 | Hitvisual2 is for blunt attacks
|
||||
//HitVisual3 is for projectile attacks
|
||||
//Basically take the attack property of a weapon and shift it left 2
|
||||
//For auto attacks attack property is weapon's damageAttributeType1
|
||||
//Still not totally sure how this works with weaponskills or what hitvisual4 or the other combinations are for
|
||||
HitVisual1 = 1 << 2,
|
||||
HitVisual2 = 1 << 3,
|
||||
HitVisual3 = 1 << 4,
|
||||
HitVisual4 = 1 << 5,
|
||||
|
||||
//An additional visual effect that plays on the target when attacked if:
|
||||
//The attack is physical and they have the protect buff on.
|
||||
|
@ -40,19 +59,27 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle
|
|||
Shell = 1 << 7 | HitEffectType,
|
||||
ProtectShellSpecial = Protect | Shell,
|
||||
|
||||
//Unknown = 1 << 8, -- Not sure what this flag does.
|
||||
// Required for heal text to be blue, not sure if that's all it's used for
|
||||
Heal = 1 << 8,
|
||||
|
||||
//If only HitEffect1 is set out of the hit effects, the "Evade!" pop-up text triggers along with the evade visual.
|
||||
//If no hit effects are set, the "Miss!" pop-up is triggered and no hit visual is played.
|
||||
HitEffect1 = 1 << 9 | HitEffectType,
|
||||
HitEffect2 = 1 << 10 | HitEffectType, //Plays the standard hit visual effect, but with no sound if used alone.
|
||||
Hit = HitEffect1 | HitEffect2, //A standard hit effect with sound effect.
|
||||
HitEffect3 = 1 << 11 | HitEffectType,
|
||||
HitEffect4 = 1 << 12 | HitEffectType,
|
||||
HitEffect5 = 1 << 13 | HitEffectType,
|
||||
HitEffect1 = 1 << 9,
|
||||
HitEffect2 = 1 << 10, //Plays the standard hit visual effect, but with no sound if used alone.
|
||||
HitEffect3 = 1 << 11, //Yellow effect, crit?
|
||||
HitEffect4 = 1 << 12, //Plays the blocking animation
|
||||
HitEffect5 = 1 << 13,
|
||||
GustyHitEffect = HitEffect3 | HitEffect2,
|
||||
GreenTintedHitEffect = HitEffect4 | HitEffect1,
|
||||
|
||||
//For specific animations
|
||||
Miss = 0,
|
||||
Evade = HitEffect1,
|
||||
Hit = HitEffect1 | HitEffect2,
|
||||
Parry = Hit | HitEffect3,
|
||||
Block = HitEffect4,
|
||||
Crit = HitEffect3,
|
||||
|
||||
//Knocks you back away from the attacker.
|
||||
KnockbackLv1 = HitEffect4 | HitEffect2 | HitEffect1,
|
||||
KnockbackLv2 = HitEffect4 | HitEffect3,
|
||||
|
@ -80,10 +107,10 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle
|
|||
//A special effect when performing appropriate skill combos in succession.
|
||||
//Ex: Thunder (SkillCombo1 Effect) -> Thundara (SkillCombo2 Effect) -> Thundaga (SkillCombo3 Effect)
|
||||
//Special Note: SkillCombo4 was never actually used in 1.0 since combos only chained up to 3 times maximum.
|
||||
SkillCombo1 = 1 << 15 | HitEffectType,
|
||||
SkillCombo2 = 1 << 16 | HitEffectType,
|
||||
SkillCombo1 = 1 << 15,
|
||||
SkillCombo2 = 1 << 16,
|
||||
SkillCombo3 = SkillCombo1 | SkillCombo2,
|
||||
SkillCombo4 = 1 << 17 | HitEffectType
|
||||
SkillCombo4 = 1 << 17
|
||||
|
||||
//Flags beyond here are unknown/untested.
|
||||
}
|
||||
|
@ -100,19 +127,45 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle
|
|||
Left = 1 << 3
|
||||
}
|
||||
|
||||
public enum HitType : ushort
|
||||
{
|
||||
Miss = 0,
|
||||
Evade = 1,
|
||||
Parry = 2,
|
||||
Block = 3,
|
||||
Resist = 4,
|
||||
Hit = 5,
|
||||
Crit = 6
|
||||
}
|
||||
|
||||
public enum BattleActionType
|
||||
{
|
||||
None = 0,
|
||||
AttackPhysical = 1,
|
||||
AttackMagic = 2,
|
||||
Heal = 3,
|
||||
Status = 4
|
||||
}
|
||||
|
||||
class BattleAction
|
||||
{
|
||||
public uint targetId;
|
||||
public ushort amount;
|
||||
public ushort enmity; //Seperate from amount for abilities that cause a different amount of enmity than damage
|
||||
public ushort worldMasterTextId;
|
||||
public uint effectId;
|
||||
public byte param;
|
||||
public byte unknown;
|
||||
public uint effectId; //Impact effect, damage/heal/status numbers or name
|
||||
public byte param; //Which side the battle action is coming from
|
||||
public byte hitNum; //Which hit in a sequence of hits this is
|
||||
public HitType hitType;
|
||||
|
||||
//Need a list of actions for commands that may both deal damage and inflict status effects
|
||||
public List<BattleAction> actionsList;
|
||||
|
||||
/// <summary>
|
||||
/// this field is not actually part of the packet struct
|
||||
/// </summary>
|
||||
public uint animation;
|
||||
public BattleActionType battleActionType;
|
||||
|
||||
public BattleAction(uint targetId, ushort worldMasterTextId, uint effectId, ushort amount = 0, byte param = 0, byte unknown = 1)
|
||||
{
|
||||
|
@ -121,7 +174,38 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle
|
|||
this.effectId = effectId;
|
||||
this.amount = amount;
|
||||
this.param = param;
|
||||
this.unknown = unknown;
|
||||
this.hitNum = unknown;
|
||||
this.hitType = HitType.Hit;
|
||||
this.enmity = amount;
|
||||
this.actionsList = new List<BattleAction>();
|
||||
this.battleActionType = BattleActionType.None;
|
||||
actionsList.Add(this);
|
||||
}
|
||||
|
||||
public void AddStatusAction(uint targetId, uint effectId)
|
||||
{
|
||||
actionsList.Add(new BattleAction(targetId, 30328, effectId | (uint) HitEffect.StatusEffectType));
|
||||
}
|
||||
|
||||
public void AddHealAction(uint targetId, ushort amount)
|
||||
{
|
||||
var a = new BattleAction(targetId, 30320, (uint)(HitEffect.MagicEffectType | HitEffect.RecoilLv3 | HitEffect.Heal), amount);
|
||||
actionsList.Add(a);
|
||||
}
|
||||
|
||||
public void CalcHitType(Character caster, Character target, BattleCommand skill)
|
||||
{
|
||||
BattleUtils.CalcHitType(caster, target, skill, this);
|
||||
}
|
||||
|
||||
public void TryStatus(Character caster, Character target, BattleCommand skill, bool isAdditional = true)
|
||||
{
|
||||
BattleUtils.TryStatus(caster, target, skill, this, isAdditional);
|
||||
}
|
||||
|
||||
public List<BattleAction> GetAllActions()
|
||||
{
|
||||
return actionsList;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace FFXIVClassic_Map_Server.packets.send.actor.battle
|
||||
namespace FFXIVClassic_Map_Server.packets.send.actor.battle
|
||||
{
|
||||
// see xtx_command
|
||||
enum BattleActionX01PacketCommand : ushort
|
||||
|
@ -25,7 +25,7 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle
|
|||
using (BinaryWriter binWriter = new BinaryWriter(mem))
|
||||
{
|
||||
binWriter.Write((UInt32)sourceActorId);
|
||||
|
||||
|
||||
binWriter.Write((UInt32)animationId);
|
||||
|
||||
//Missing... last value is float, string in here as well?
|
||||
|
@ -39,15 +39,15 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle
|
|||
|
||||
binWriter.Write((UInt16)action.amount);
|
||||
binWriter.Write((UInt16)action.worldMasterTextId);
|
||||
Program.Log.Info(action.worldMasterTextId);
|
||||
|
||||
binWriter.Write((UInt32)action.effectId);
|
||||
|
||||
binWriter.Write((Byte)action.param);
|
||||
binWriter.Write((Byte)1); //?
|
||||
}
|
||||
}
|
||||
|
||||
new SubPacket(OPCODE, sourceActorId, data).DebugPrintSubPacket();
|
||||
return new SubPacket(OPCODE, sourceActorId, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -57,7 +57,7 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle
|
|||
|
||||
binWriter.Seek(0xAA, SeekOrigin.Begin);
|
||||
for (int i = 0; i < max; i++)
|
||||
binWriter.Write((Byte)actionList[listOffset + i].unknown);
|
||||
binWriter.Write((Byte)actionList[listOffset + i].hitNum);
|
||||
|
||||
listOffset += max;
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle
|
|||
|
||||
binWriter.Seek(0xAA, SeekOrigin.Begin);
|
||||
for (int i = 0; i < max; i++)
|
||||
binWriter.Write((Byte)actionList[listOffset + i].unknown);
|
||||
binWriter.Write((Byte)actionList[listOffset + i].hitNum);
|
||||
|
||||
listOffset += max;
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle
|
|||
|
||||
binWriter.Seek(0x112, SeekOrigin.Begin);
|
||||
for (int i = 0; i < max; i++)
|
||||
binWriter.Write((Byte)actionList[listOffset + i].unknown);
|
||||
binWriter.Write((Byte)actionList[listOffset + i].hitNum);
|
||||
|
||||
listOffset += max;
|
||||
}
|
||||
|
@ -86,33 +86,33 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle
|
|||
//Missing... last value is float, string in here as well?
|
||||
|
||||
binWriter.Seek(0x20, SeekOrigin.Begin);
|
||||
binWriter.Write((UInt32)max); //Num actions
|
||||
binWriter.Write((UInt32)actionList.Count); //Num actions
|
||||
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);
|
||||
binWriter.Write((Byte)actionList[listOffset + i].hitNum);
|
||||
|
||||
listOffset += max;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue