mirror of
https://bitbucket.org/Ioncannon/project-meteor-server.git
synced 2025-04-23 21:27:46 +00:00
added ion's and showmo's enums
- added nullable DateTime param to UnixTimeStampUTC
This commit is contained in:
parent
1ae15df64c
commit
c070f5b80e
10 changed files with 188 additions and 19 deletions
|
@ -84,10 +84,10 @@ namespace FFXIVClassic.Common
|
|||
return sb.ToString().TrimEnd(Environment.NewLine.ToCharArray());
|
||||
}
|
||||
|
||||
public static uint UnixTimeStampUTC()
|
||||
public static uint UnixTimeStampUTC(DateTime? time = null)
|
||||
{
|
||||
uint unixTimeStamp;
|
||||
var currentTime = DateTime.Now;
|
||||
var currentTime = time ?? DateTime.Now;
|
||||
var zuluTime = currentTime.ToUniversalTime();
|
||||
var unixEpoch = new DateTime(1970, 1, 1);
|
||||
unixTimeStamp = (uint)zuluTime.Subtract(unixEpoch).TotalSeconds;
|
||||
|
@ -95,10 +95,10 @@ namespace FFXIVClassic.Common
|
|||
return unixTimeStamp;
|
||||
}
|
||||
|
||||
public static ulong MilisUnixTimeStampUTC()
|
||||
public static ulong MilisUnixTimeStampUTC(DateTime? time = null)
|
||||
{
|
||||
ulong unixTimeStamp;
|
||||
var currentTime = DateTime.Now;
|
||||
var currentTime = time ?? DateTime.Now;
|
||||
var zuluTime = currentTime.ToUniversalTime();
|
||||
var unixEpoch = new DateTime(1970, 1, 1);
|
||||
unixTimeStamp = (ulong)zuluTime.Subtract(unixEpoch).TotalMilliseconds;
|
||||
|
|
|
@ -109,7 +109,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
ResetMoveSpeeds();
|
||||
// todo: base this on equip and shit
|
||||
SetMod((uint)Modifier.AttackRange, 3);
|
||||
SetMod((uint)Modifier.AttackDelay, (Program.Random.Next(30,60) * 100));
|
||||
SetMod((uint)Modifier.AttackDelay, (Program.Random.Next(30, 60) * 100));
|
||||
}
|
||||
|
||||
public SubPacket CreateAppearancePacket()
|
||||
|
@ -322,6 +322,11 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
aiContainer.Cast(Server.GetWorldManager().GetActorInWorld(targetId == 0 ? currentTarget : targetId) as Character, spellId);
|
||||
}
|
||||
|
||||
public void Ability(uint abilityId, uint targetId = 0)
|
||||
{
|
||||
aiContainer.Ability(Server.GetWorldManager().GetActorInWorld(targetId == 0 ? currentTarget : targetId) as Character, abilityId);
|
||||
}
|
||||
|
||||
public void WeaponSkill(uint skillId)
|
||||
{
|
||||
aiContainer.WeaponSkill(Server.GetWorldManager().GetActorInWorld(currentTarget) as Character, skillId);
|
||||
|
|
|
@ -113,7 +113,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||
|
||||
public bool CanChangeState()
|
||||
{
|
||||
return states.Count == 0 || states.Peek().CanInterrupt();
|
||||
return GetCurrentState() == null || states.Peek().CanInterrupt();
|
||||
}
|
||||
|
||||
public void ChangeTarget(Character target)
|
||||
|
@ -217,6 +217,14 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||
InternalDisengage();
|
||||
}
|
||||
|
||||
public void Ability(Character target, uint abilityId)
|
||||
{
|
||||
if (controller != null)
|
||||
controller.Ability(target, abilityId);
|
||||
else
|
||||
InternalAbility(target, abilityId);
|
||||
}
|
||||
|
||||
public void Cast(Character target, uint spellId)
|
||||
{
|
||||
if (controller != null)
|
||||
|
@ -293,6 +301,11 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||
ClearStates();
|
||||
}
|
||||
|
||||
public void InternalAbility(Character target, uint abilityId)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void InternalCast(Character target, uint spellId)
|
||||
{
|
||||
ChangeState(new MagicState(owner, target, (ushort)spellId));
|
||||
|
|
|
@ -68,7 +68,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
|||
|
||||
public override void Ability(Character target, uint abilityId)
|
||||
{
|
||||
|
||||
owner.aiContainer.InternalAbility(target, abilityId);
|
||||
}
|
||||
|
||||
public override void RangedAttack(Character target)
|
||||
|
|
|
@ -18,9 +18,11 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||
public AttackState(Character owner, Character target) :
|
||||
base(owner, target)
|
||||
{
|
||||
this.canInterrupt = true;
|
||||
this.startTime = DateTime.Now;
|
||||
|
||||
owner.ChangeState(SetActorStatePacket.MAIN_STATE_ACTIVE);
|
||||
owner.aiContainer.ChangeTarget(target);
|
||||
this.startTime = DateTime.Now;
|
||||
attackTime = startTime;
|
||||
owner.aiContainer.pathFind?.Clear();
|
||||
// todo: should handle everything here instead of on next tick..
|
||||
|
|
|
@ -8,6 +8,7 @@ using FFXIVClassic_Map_Server.Actors;
|
|||
using FFXIVClassic_Map_Server.packets.send.actor;
|
||||
using FFXIVClassic_Map_Server.packets.send.actor.battle;
|
||||
using FFXIVClassic_Map_Server.packets.send;
|
||||
using FFXIVClassic_Map_Server.utils;
|
||||
|
||||
namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
||||
{
|
||||
|
@ -56,12 +57,21 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||
// todo: check within attack range
|
||||
startPos = owner.GetPosAsVector3();
|
||||
owner.LookAt(target);
|
||||
float[] baseCastDuration = { 1.0f, 0.25f };
|
||||
|
||||
foreach (var player in owner.zone.GetActorsAroundActor<Player>(owner, 50))
|
||||
float spellSpeed = spell.castTimeSeconds;
|
||||
List<SubPacket> packets = new List<SubPacket>();
|
||||
|
||||
// command casting duration
|
||||
if (owner.currentSubState == SetActorStatePacket.SUB_STATE_PLAYER)
|
||||
{
|
||||
// todo: this is retarded, prolly doesnt do what i think its gonna do
|
||||
//player.QueuePacket(BattleActionX01Packet.BuildPacket(player.actorId, owner.actorId, target != null ? target.actorId : 0xC0000000, spell.battleAnimation, spell.effectAnimation, 0, spell.id, 0, (byte)spell.castTimeSeconds));
|
||||
// todo: modify spellSpeed based on modifiers and stuff
|
||||
// ((Player)owner).SendStartCastBar(spell.id, Utils.UnixTimeStampUTC(DateTime.Now.AddSeconds(spellSpeed)));
|
||||
|
||||
}
|
||||
// todo: change
|
||||
|
||||
owner.zone.BroadcastPacketsAroundActor(owner, packets);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,5 +170,16 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||
{
|
||||
return (Utils.DistanceSquared(owner.GetPosAsVector3(), startPos) > 4.0f);
|
||||
}
|
||||
|
||||
public override void Cleanup()
|
||||
{
|
||||
// command casting duration
|
||||
var packets = new List<SubPacket>();
|
||||
if (owner.currentSubState == SetActorStatePacket.SUB_STATE_PLAYER)
|
||||
{
|
||||
// ((Player)owner).SendStartCastBar(0, 0);
|
||||
}
|
||||
owner.zone.BroadcastPacketsAroundActor(owner, packets);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
using FFXIVClassic.Common;
|
||||
using System;
|
||||
|
||||
using FFXIVClassic.Common;
|
||||
|
||||
namespace FFXIVClassic_Map_Server.packets.send.actor
|
||||
{
|
||||
class SetActorStatePacket
|
||||
|
|
|
@ -10,6 +10,17 @@ namespace FFXIVClassic_Map_Server.packets.send.actor
|
|||
public const ushort OPCODE = 0x144;
|
||||
public const uint PACKET_SIZE = 0x28;
|
||||
|
||||
enum SubStat : int
|
||||
{
|
||||
Breakage = 0x00, // (index goes high to low, bitflags)
|
||||
Chant = 0x01, // [Nibbles: left / right hand = value]) (AKA SubStatObject)
|
||||
Guard = 0x02, // [left / right hand = true] 0,1,2,3) ||| High byte also defines how many bools to use as flags for byte 0x4.
|
||||
Waste = 0x03, // (High Nibble)
|
||||
Mode = 0x04, // ???
|
||||
Unknown = 0x05, // ???
|
||||
SubStatMotionPack = 0x06,
|
||||
Unknown2 = 0x07,
|
||||
}
|
||||
public static SubPacket BuildPacket(uint sourceActorId, byte breakage, int leftChant, int rightChant, int guard, int wasteStat, int statMode, uint idleAnimationId)
|
||||
{
|
||||
byte[] data = new byte[PACKET_SIZE - 0x20];
|
||||
|
|
|
@ -10,6 +10,89 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle
|
|||
Disengage = 12002,
|
||||
Attack = 22104,
|
||||
}
|
||||
|
||||
//These flags can be stacked and mixed, but the client will prioritize certain flags over others.
|
||||
[Flags]
|
||||
public enum HitEffect : uint
|
||||
{
|
||||
//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,
|
||||
RecoilLv2 = 1 << 0,
|
||||
RecoilLv3 = 1 << 1,
|
||||
|
||||
//Setting both recoil flags triggers the "Critical!" pop-up text and hit visual effect.
|
||||
CriticalHit = RecoilLv2 | RecoilLv3,
|
||||
|
||||
//Hit visual and sound effects when connecting with the target.
|
||||
//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,
|
||||
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.
|
||||
//The attack is magical and they have the shell buff on.
|
||||
//Special Note: Shell was removed in later versions of the game.
|
||||
//Another effect plays when both Protect and Shell flags are activated.
|
||||
//Not sure what this effect is.
|
||||
//Random guess: if the attack was a hybrid of both physical and magical and the target had both Protect and Shell buffs applied.
|
||||
Protect = 1 << 6,
|
||||
Shell = 1 << 7,
|
||||
ProtectShellSpecial = Protect | Shell,
|
||||
|
||||
//Unknown = 1 << 8, -- Not sure what this flag does.
|
||||
|
||||
//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,
|
||||
HitEffect2 = 1 << 10, //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,
|
||||
HitEffect4 = 1 << 12,
|
||||
HitEffect5 = 1 << 13,
|
||||
GustyHitEffect = HitEffect3 | HitEffect2,
|
||||
GreenTintedHitEffect = HitEffect4 | HitEffect1,
|
||||
|
||||
//Knocks you back away from the attacker.
|
||||
KnockbackLv1 = HitEffect4 | HitEffect2 | HitEffect1,
|
||||
KnockbackLv2 = HitEffect4 | HitEffect3,
|
||||
KnockbackLv3 = HitEffect4 | HitEffect3 | HitEffect1,
|
||||
KnockbackLv4 = HitEffect4 | HitEffect3 | HitEffect2,
|
||||
KnockbackLv5 = HitEffect4 | HitEffect3 | HitEffect2 | HitEffect1,
|
||||
|
||||
//Knocks you away from the attacker in a counter-clockwise direction.
|
||||
KnockbackCounterClockwiseLv1 = HitEffect5,
|
||||
KnockbackCounterClockwiseLv2 = HitEffect5 | HitEffect1,
|
||||
|
||||
//Knocks you away from the attacker in a clockwise direction.
|
||||
KnockbackClockwiseLv1 = HitEffect5 | HitEffect2,
|
||||
KnockbackClockwiseLv2 = HitEffect5 | HitEffect2 | HitEffect1,
|
||||
|
||||
//Completely drags target to the attacker, even across large distances.
|
||||
DrawIn = HitEffect5 | HitEffect3,
|
||||
|
||||
//An additional visual effect that plays on the target based on according buff.
|
||||
UnknownShieldEffect = HitEffect5 | HitEffect4,
|
||||
Stoneskin = HitEffect5 | HitEffect4 | HitEffect1,
|
||||
|
||||
//Unknown = 1 << 14, -- Not sure what this flag does; might be another HitEffect.
|
||||
|
||||
//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,
|
||||
SkillCombo2 = 1 << 16,
|
||||
SkillCombo3 = SkillCombo1 | SkillCombo2,
|
||||
SkillCombo4 = 1 << 17
|
||||
|
||||
//Flags beyond here are unknown/untested.
|
||||
}
|
||||
|
||||
class BattleActionX01Packet
|
||||
{
|
||||
public const ushort OPCODE = 0x0139;
|
||||
|
|
36
data/scripts/commands/Ability.lua
Normal file
36
data/scripts/commands/Ability.lua
Normal file
|
@ -0,0 +1,36 @@
|
|||
require ("global")
|
||||
require ("utils")
|
||||
|
||||
--[[
|
||||
|
||||
AttackWeaponSkill Script
|
||||
|
||||
Finds the correct weaponskill subscript to fire when a weaponskill actor is activated.
|
||||
|
||||
--]]
|
||||
|
||||
local attackMagicHandlers = {
|
||||
|
||||
}
|
||||
|
||||
function onEventStarted(player, command, triggerName, arg1, arg2, arg3, arg4, targetActor, arg5, arg6, arg7, arg8)
|
||||
print(command.actorId)
|
||||
--Are they in active mode?
|
||||
if (player:GetState() != 2) then
|
||||
player:SendGameMessage(GetWorldMaster(), 32503, 0x20);
|
||||
player:endEvent();
|
||||
return;
|
||||
end
|
||||
|
||||
--Does the target exist
|
||||
target = player:getZone():FindActorInArea(targetActor);
|
||||
if (target == nil) then
|
||||
player:SendGameMessage(GetWorldMaster(), 30203, 0x20);
|
||||
player:endEvent();
|
||||
return;
|
||||
end
|
||||
|
||||
player.Ability(command.actorId, targetActor);
|
||||
player:endEvent();
|
||||
|
||||
end
|
Loading…
Add table
Reference in a new issue