mirror of
https://bitbucket.org/Ioncannon/project-meteor-server.git
synced 2025-04-02 19:42:05 -04:00
added mob name colour update
- added mobmods (need to be loaded from db) - added Zone.GetBattleNpcById - added missing IsValidTarget check in AttackState
This commit is contained in:
parent
9077c60b96
commit
ce5030acd1
@ -109,6 +109,7 @@
|
|||||||
<Compile Include="actors\chara\Modifier.cs" />
|
<Compile Include="actors\chara\Modifier.cs" />
|
||||||
<Compile Include="actors\chara\npc\ActorClass.cs" />
|
<Compile Include="actors\chara\npc\ActorClass.cs" />
|
||||||
<Compile Include="actors\chara\npc\BattleNpc.cs" />
|
<Compile Include="actors\chara\npc\BattleNpc.cs" />
|
||||||
|
<Compile Include="actors\chara\npc\MobModifier.cs" />
|
||||||
<Compile Include="actors\chara\npc\NpcWork.cs" />
|
<Compile Include="actors\chara\npc\NpcWork.cs" />
|
||||||
<Compile Include="actors\chara\AetheryteWork.cs" />
|
<Compile Include="actors\chara\AetheryteWork.cs" />
|
||||||
<Compile Include="actors\chara\npc\Pet.cs" />
|
<Compile Include="actors\chara\npc\Pet.cs" />
|
||||||
|
@ -154,6 +154,7 @@ namespace FFXIVClassic_Map_Server
|
|||||||
case 0x00CC:
|
case 0x00CC:
|
||||||
LockTargetPacket lockTarget = new LockTargetPacket(subpacket.data);
|
LockTargetPacket lockTarget = new LockTargetPacket(subpacket.data);
|
||||||
session.GetActor().currentLockedTarget = lockTarget.actorID;
|
session.GetActor().currentLockedTarget = lockTarget.actorID;
|
||||||
|
// todo: this really needs figuring out..
|
||||||
session.GetActor().isAutoAttackEnabled = lockTarget.otherVal == 0x00000040;
|
session.GetActor().isAutoAttackEnabled = lockTarget.otherVal == 0x00000040;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -25,6 +25,7 @@ using System.Diagnostics;
|
|||||||
using FFXIVClassic_Map_Server.actors.director;
|
using FFXIVClassic_Map_Server.actors.director;
|
||||||
using FFXIVClassic_Map_Server.actors.chara.ai;
|
using FFXIVClassic_Map_Server.actors.chara.ai;
|
||||||
using FFXIVClassic_Map_Server.actors.chara;
|
using FFXIVClassic_Map_Server.actors.chara;
|
||||||
|
using FFXIVClassic_Map_Server.Actors.Chara;
|
||||||
|
|
||||||
namespace FFXIVClassic_Map_Server
|
namespace FFXIVClassic_Map_Server
|
||||||
{
|
{
|
||||||
@ -427,7 +428,7 @@ namespace FFXIVClassic_Map_Server
|
|||||||
{
|
{
|
||||||
conn.Open();
|
conn.Open();
|
||||||
var query = @"
|
var query = @"
|
||||||
SELECT bsl.groupId, bsl.positionX, bsl.positionY, bsl.positionZ, bsl.rotation,
|
SELECT bsl.bnpcId, bsl.groupId, bsl.positionX, bsl.positionY, bsl.positionZ, bsl.rotation,
|
||||||
bgr.groupId, bgr.poolId, bgr.actorClassId, bgr.scriptName, bgr.minLevel, bgr.maxLevel, bgr.respawnTime, bgr.hp, bgr.mp,
|
bgr.groupId, bgr.poolId, bgr.actorClassId, bgr.scriptName, bgr.minLevel, bgr.maxLevel, bgr.respawnTime, bgr.hp, bgr.mp,
|
||||||
bgr.dropListId, bgr.allegiance, bgr.spawnType, bgr.animationId, bgr.actorState, bgr.privateAreaName, bgr.privateAreaLevel, bgr.zoneId,
|
bgr.dropListId, bgr.allegiance, bgr.spawnType, bgr.animationId, bgr.actorState, bgr.privateAreaName, bgr.privateAreaLevel, bgr.zoneId,
|
||||||
bpo.poolId, bpo.genusId, bpo.currentJob, bpo.combatSkill, bpo.combatDelay, bpo.combatDmgMult, bpo.aggroType,
|
bpo.poolId, bpo.genusId, bpo.currentJob, bpo.combatSkill, bpo.combatDelay, bpo.combatDmgMult, bpo.aggroType,
|
||||||
@ -439,7 +440,7 @@ namespace FFXIVClassic_Map_Server
|
|||||||
INNER JOIN server_battlenpc_groups bgr ON bsl.groupId = bgr.groupId
|
INNER JOIN server_battlenpc_groups bgr ON bsl.groupId = bgr.groupId
|
||||||
INNER JOIN server_battlenpc_pools bpo ON bgr.poolId = bpo.poolId
|
INNER JOIN server_battlenpc_pools bpo ON bgr.poolId = bpo.poolId
|
||||||
INNER JOIN server_battlenpc_genus bge ON bpo.genusId = bge.genusId
|
INNER JOIN server_battlenpc_genus bge ON bpo.genusId = bge.genusId
|
||||||
WHERE bgr.zoneId = @zoneId GROUP BY bsl.bnpcIndex;
|
WHERE bgr.zoneId = @zoneId GROUP BY bsl.bnpcId;
|
||||||
";
|
";
|
||||||
|
|
||||||
var count = 0;
|
var count = 0;
|
||||||
@ -457,20 +458,19 @@ namespace FFXIVClassic_Map_Server
|
|||||||
int actorId = zone.GetActorCount() + 1;
|
int actorId = zone.GetActorCount() + 1;
|
||||||
|
|
||||||
// todo: add to private areas, set up immunity, mob linking,
|
// todo: add to private areas, set up immunity, mob linking,
|
||||||
// - load skill/spell/drop lists, set npcWork.hateType,
|
// - load skill/spell/drop lists, set detection icon, load pool/family/group mods
|
||||||
|
|
||||||
var battleNpc = new BattleNpc(actorId, Server.GetWorldManager().GetActorClass(reader.GetUInt32("actorClassId")),
|
var battleNpc = new BattleNpc(actorId, Server.GetWorldManager().GetActorClass(reader.GetUInt32("actorClassId")),
|
||||||
reader.GetString("scriptName"), zone, reader.GetFloat("positionX"), reader.GetFloat("positionY"), reader.GetFloat("positionZ"), reader.GetFloat("rotation"),
|
reader.GetString("scriptName"), zone, reader.GetFloat("positionX"), reader.GetFloat("positionY"), reader.GetFloat("positionZ"), reader.GetFloat("rotation"),
|
||||||
reader.GetUInt16("actorState"), reader.GetUInt32("animationId"), "");
|
reader.GetUInt16("actorState"), reader.GetUInt32("animationId"), "");
|
||||||
|
|
||||||
|
battleNpc.SetBattleNpcId(reader.GetUInt32("bnpcId"));
|
||||||
battleNpc.neutral = reader.GetByte("aggroType") == 0;
|
battleNpc.neutral = reader.GetByte("aggroType") == 0;
|
||||||
|
|
||||||
battleNpc.SetDetectionType(reader.GetUInt32("detection"));
|
battleNpc.SetDetectionType(reader.GetUInt32("detection"));
|
||||||
battleNpc.kindredType = (KindredType)reader.GetUInt32("kindredId");
|
battleNpc.kindredType = (KindredType)reader.GetUInt32("kindredId");
|
||||||
battleNpc.npcSpawnType = (NpcSpawnType)reader.GetUInt32("spawnType");
|
battleNpc.npcSpawnType = (NpcSpawnType)reader.GetUInt32("spawnType");
|
||||||
|
|
||||||
// todo: set hateType to appropriate detectionType thing
|
|
||||||
//battleNpc.npcWork.hateType
|
|
||||||
battleNpc.charaWork.parameterSave.state_mainSkill[0] = reader.GetByte("currentJob");
|
battleNpc.charaWork.parameterSave.state_mainSkill[0] = reader.GetByte("currentJob");
|
||||||
battleNpc.charaWork.parameterSave.state_mainSkillLevel = (short)Program.Random.Next(reader.GetByte("minLevel"), reader.GetByte("maxLevel"));
|
battleNpc.charaWork.parameterSave.state_mainSkillLevel = (short)Program.Random.Next(reader.GetByte("minLevel"), reader.GetByte("maxLevel"));
|
||||||
|
|
||||||
@ -527,6 +527,112 @@ namespace FFXIVClassic_Map_Server
|
|||||||
z.SpawnAllActors(true);
|
z.SpawnAllActors(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SpawnBattleNpcById(uint id)
|
||||||
|
{
|
||||||
|
// todo: this is stupid duplicate code and really needs to die, think of a better way later
|
||||||
|
using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD)))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
conn.Open();
|
||||||
|
var query = @"
|
||||||
|
SELECT bsl.bnpcId, bsl.groupId, bsl.positionX, bsl.positionY, bsl.positionZ, bsl.rotation,
|
||||||
|
bgr.groupId, bgr.poolId, bgr.actorClassId, bgr.scriptName, bgr.minLevel, bgr.maxLevel, bgr.respawnTime, bgr.hp, bgr.mp,
|
||||||
|
bgr.dropListId, bgr.allegiance, bgr.spawnType, bgr.animationId, bgr.actorState, bgr.privateAreaName, bgr.privateAreaLevel, bgr.zoneId,
|
||||||
|
bpo.poolId, bpo.genusId, bpo.currentJob, bpo.combatSkill, bpo.combatDelay, bpo.combatDmgMult, bpo.aggroType,
|
||||||
|
bpo.immunity, bpo.linkType, bpo.skillListId, bpo.spellListId,
|
||||||
|
bge.genusId, bge.modelSize, bge.kindredId, bge.detection, bge.hpp, bge.mpp, bge.tpp, bge.str, bge.vit, bge.dex,
|
||||||
|
bge.int, bge.mnd, bge.pie, bge.att, bge.acc, bge.def, bge.eva, bge.slash, bge.pierce, bge.h2h, bge.blunt,
|
||||||
|
bge.fire, bge.ice, bge.wind, bge.lightning, bge.earth, bge.water
|
||||||
|
FROM server_battlenpc_spawn_locations bsl
|
||||||
|
INNER JOIN server_battlenpc_groups bgr ON bsl.groupId = bgr.groupId
|
||||||
|
INNER JOIN server_battlenpc_pools bpo ON bgr.poolId = bpo.poolId
|
||||||
|
INNER JOIN server_battlenpc_genus bge ON bpo.genusId = bge.genusId
|
||||||
|
WHERE bsl.bnpcId = @bnpcId GROUP BY bsl.bnpcId;
|
||||||
|
";
|
||||||
|
|
||||||
|
var count = 0;
|
||||||
|
|
||||||
|
MySqlCommand cmd = new MySqlCommand(query, conn);
|
||||||
|
cmd.Parameters.AddWithValue("@bnpcId", id);
|
||||||
|
|
||||||
|
using (MySqlDataReader reader = cmd.ExecuteReader())
|
||||||
|
{
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
var zone = Server.GetWorldManager().GetZone(reader.GetUInt16("zoneId"));
|
||||||
|
int actorId = zone.GetActorCount() + 1;
|
||||||
|
var bnpc = zone.GetBattleNpcById(id);
|
||||||
|
|
||||||
|
if (bnpc != null)
|
||||||
|
{
|
||||||
|
bnpc.ForceRespawn();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: add to private areas, set up immunity, mob linking,
|
||||||
|
// - load skill/spell/drop lists, set detection icon, load pool/family/group mods
|
||||||
|
|
||||||
|
var battleNpc = new BattleNpc(actorId, Server.GetWorldManager().GetActorClass(reader.GetUInt32("actorClassId")),
|
||||||
|
reader.GetString("scriptName"), zone, reader.GetFloat("positionX"), reader.GetFloat("positionY"), reader.GetFloat("positionZ"), reader.GetFloat("rotation"),
|
||||||
|
reader.GetUInt16("actorState"), reader.GetUInt32("animationId"), "");
|
||||||
|
|
||||||
|
battleNpc.SetBattleNpcId(reader.GetUInt32("bnpcId"));
|
||||||
|
battleNpc.neutral = reader.GetByte("aggroType") == 0;
|
||||||
|
|
||||||
|
battleNpc.SetDetectionType(reader.GetUInt32("detection"));
|
||||||
|
battleNpc.kindredType = (KindredType)reader.GetUInt32("kindredId");
|
||||||
|
battleNpc.npcSpawnType = (NpcSpawnType)reader.GetUInt32("spawnType");
|
||||||
|
|
||||||
|
battleNpc.charaWork.parameterSave.state_mainSkill[0] = reader.GetByte("currentJob");
|
||||||
|
battleNpc.charaWork.parameterSave.state_mainSkillLevel = (short)Program.Random.Next(reader.GetByte("minLevel"), reader.GetByte("maxLevel"));
|
||||||
|
|
||||||
|
battleNpc.allegiance = (CharacterTargetingAllegiance)reader.GetByte("allegiance");
|
||||||
|
|
||||||
|
// todo: setup private areas and other crap and
|
||||||
|
// set up rest of stat resists
|
||||||
|
battleNpc.SetMod((uint)Modifier.Hp, reader.GetUInt32("hp"));
|
||||||
|
battleNpc.SetMod((uint)Modifier.HpPercent, reader.GetUInt32("hpp"));
|
||||||
|
battleNpc.SetMod((uint)Modifier.Mp, reader.GetUInt32("mp"));
|
||||||
|
battleNpc.SetMod((uint)Modifier.MpPercent, reader.GetUInt32("mpp"));
|
||||||
|
battleNpc.SetMod((uint)Modifier.TpPercent, reader.GetUInt32("tpp"));
|
||||||
|
|
||||||
|
battleNpc.SetMod((uint)Modifier.Strength, reader.GetUInt32("str"));
|
||||||
|
battleNpc.SetMod((uint)Modifier.Vitality, reader.GetUInt32("vit"));
|
||||||
|
battleNpc.SetMod((uint)Modifier.Dexterity, reader.GetUInt32("dex"));
|
||||||
|
battleNpc.SetMod((uint)Modifier.Intelligence, reader.GetUInt32("int"));
|
||||||
|
battleNpc.SetMod((uint)Modifier.Mind, reader.GetUInt32("mnd"));
|
||||||
|
battleNpc.SetMod((uint)Modifier.Piety, reader.GetUInt32("pie"));
|
||||||
|
battleNpc.SetMod((uint)Modifier.Attack, reader.GetUInt32("att"));
|
||||||
|
battleNpc.SetMod((uint)Modifier.Accuracy, reader.GetUInt32("acc"));
|
||||||
|
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");
|
||||||
|
|
||||||
|
battleNpc.SetBattleNpcId(reader.GetUInt32("bnpcId"));
|
||||||
|
//battleNpc.SetMod((uint)Modifier.ResistFire, )
|
||||||
|
|
||||||
|
zone.AddActorToZone(battleNpc);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Program.Log.Info("WorldManager.SpawnBattleNpcById spawned BattleNpc {0}.", id);
|
||||||
|
}
|
||||||
|
catch (MySqlException e)
|
||||||
|
{
|
||||||
|
Program.Log.Error(e.ToString());
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
conn.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Moves the actor to the new zone if exists. No packets are sent nor position changed. Merged zone is removed.
|
//Moves the actor to the new zone if exists. No packets are sent nor position changed. Merged zone is removed.
|
||||||
public void DoSeamlessZoneChange(Player player, uint destinationZoneId)
|
public void DoSeamlessZoneChange(Player player, uint destinationZoneId)
|
||||||
{
|
{
|
||||||
|
@ -25,9 +25,10 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
Name = 0x08,
|
Name = 0x08,
|
||||||
Appearance = 0x10,
|
Appearance = 0x10,
|
||||||
Speed = 0x20,
|
Speed = 0x20,
|
||||||
|
Work = 0x40,
|
||||||
|
|
||||||
AllNpc = 0x2F,
|
AllNpc = 0x6F,
|
||||||
AllPlayer = 0x3F
|
AllPlayer = 0x9F
|
||||||
}
|
}
|
||||||
|
|
||||||
class Actor
|
class Actor
|
||||||
|
@ -526,6 +526,16 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BattleNpc GetBattleNpcById(uint id)
|
||||||
|
{
|
||||||
|
foreach (var bnpc in GetAllActors<BattleNpc>())
|
||||||
|
{
|
||||||
|
if (bnpc.GetBattleNpcId() == id)
|
||||||
|
return bnpc;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public void DespawnActor(string uniqueId)
|
public void DespawnActor(string uniqueId)
|
||||||
{
|
{
|
||||||
RemoveActorFromZone(FindActorInZoneByUniqueID(uniqueId));
|
RemoveActorFromZone(FindActorInZoneByUniqueID(uniqueId));
|
||||||
|
@ -159,7 +159,6 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
ActorPropertyPacketUtil propPacketUtil = new ActorPropertyPacketUtil("charaWork/currentContentGroup", this);
|
ActorPropertyPacketUtil propPacketUtil = new ActorPropertyPacketUtil("charaWork/currentContentGroup", this);
|
||||||
propPacketUtil.AddProperty("charaWork.currentContentGroup");
|
propPacketUtil.AddProperty("charaWork.currentContentGroup");
|
||||||
zone.BroadcastPacketsAroundActor(this, propPacketUtil.Done());
|
zone.BroadcastPacketsAroundActor(this, propPacketUtil.Done());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<SubPacket> GetActorStatusPackets()
|
public List<SubPacket> GetActorStatusPackets()
|
||||||
@ -593,6 +592,7 @@ 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);
|
//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);
|
||||||
// todo: call onAttack/onDamageTaken
|
// todo: call onAttack/onDamageTaken
|
||||||
target.DelHP(action.amount);
|
target.DelHP(action.amount);
|
||||||
if (target is BattleNpc)
|
if (target is BattleNpc)
|
||||||
@ -605,6 +605,9 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
// damage is handled in script
|
// damage is handled in script
|
||||||
this.DelMP(spell.mpCost); // mpCost can be set in script e.g. if caster has something for free spells
|
this.DelMP(spell.mpCost); // 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);
|
||||||
|
|
||||||
if (target is BattleNpc)
|
if (target is BattleNpc)
|
||||||
((BattleNpc)target).lastAttacker = this;
|
((BattleNpc)target).lastAttacker = this;
|
||||||
}
|
}
|
||||||
@ -615,6 +618,9 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
// damage is handled in script
|
// damage is handled in script
|
||||||
this.DelTP(skill.tpCost);
|
this.DelTP(skill.tpCost);
|
||||||
|
|
||||||
|
foreach (var action in actions)
|
||||||
|
zone.FindActorInArea<BattleNpc>(action.targetId)?.OnDamageTaken(this, action);
|
||||||
|
|
||||||
if (target is BattleNpc)
|
if (target is BattleNpc)
|
||||||
((BattleNpc)target).lastAttacker = this;
|
((BattleNpc)target).lastAttacker = this;
|
||||||
}
|
}
|
||||||
@ -623,6 +629,9 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
{
|
{
|
||||||
if (target is BattleNpc)
|
if (target is BattleNpc)
|
||||||
((BattleNpc)target).lastAttacker = this;
|
((BattleNpc)target).lastAttacker = this;
|
||||||
|
|
||||||
|
foreach (var action in actions)
|
||||||
|
zone.FindActorInArea<BattleNpc>(action.targetId)?.OnDamageTaken(this, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void OnSpawn()
|
public virtual void OnSpawn()
|
||||||
@ -638,6 +647,11 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
public virtual void OnDespawn()
|
public virtual void OnDespawn()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnDamageTaken(Character attacker, BattleAction action)
|
||||||
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
|||||||
using FFXIVClassic_Map_Server.Actors;
|
using FFXIVClassic_Map_Server.Actors;
|
||||||
using MoonSharp;
|
using MoonSharp;
|
||||||
using MoonSharp.Interpreter;
|
using MoonSharp.Interpreter;
|
||||||
|
using FFXIVClassic_Map_Server.lua;
|
||||||
|
|
||||||
namespace FFXIVClassic_Map_Server.actors.chara.ai
|
namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||||
{
|
{
|
||||||
@ -15,8 +16,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||||||
public uint durationMs;
|
public uint durationMs;
|
||||||
public bool checkState;
|
public bool checkState;
|
||||||
// todo: lua function
|
// todo: lua function
|
||||||
Script script;
|
LuaScript script;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ActionQueue
|
class ActionQueue
|
||||||
{
|
{
|
||||||
private Character owner;
|
private Character owner;
|
||||||
@ -27,7 +29,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||||||
|
|
||||||
public ActionQueue(Character owner)
|
public ActionQueue(Character owner)
|
||||||
{
|
{
|
||||||
|
this.owner = owner;
|
||||||
|
actionQueue = new Queue<Action>();
|
||||||
|
timerQueue = new Queue<Action>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PushAction(Action action)
|
public void PushAction(Action action)
|
||||||
@ -45,5 +49,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void CheckAction(DateTime tick)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -363,8 +363,12 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
|||||||
public override void ChangeTarget(Character target)
|
public override void ChangeTarget(Character target)
|
||||||
{
|
{
|
||||||
owner.target = target;
|
owner.target = target;
|
||||||
owner.currentLockedTarget = target != null ? target.actorId : 0xC0000000;
|
owner.currentLockedTarget = target?.actorId ?? 0xC0000000;
|
||||||
owner.currentTarget = target != null ? target.actorId : 0xC0000000;
|
owner.currentTarget = target?.actorId ?? 0xC0000000;
|
||||||
|
|
||||||
|
foreach (var player in owner.zone.GetActorsAroundActor<Player>(owner, 50))
|
||||||
|
player.QueuePacket(owner.GetHateTypePacket(player));
|
||||||
|
|
||||||
base.ChangeTarget(target);
|
base.ChangeTarget(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,7 +155,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||||||
owner.aiContainer.ChangeTarget(null);
|
owner.aiContainer.ChangeTarget(null);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (!owner.aiContainer.GetTargetFind().CanTarget(target, false, true))
|
else if (!owner.IsValidTarget(target, ValidTarget.Enemy) || !owner.aiContainer.GetTargetFind().CanTarget(target, false, true))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ using FFXIVClassic_Map_Server.packets.send.actor.battle;
|
|||||||
using FFXIVClassic_Map_Server.actors.chara.ai.utils;
|
using FFXIVClassic_Map_Server.actors.chara.ai.utils;
|
||||||
using FFXIVClassic_Map_Server.actors.group;
|
using FFXIVClassic_Map_Server.actors.group;
|
||||||
using FFXIVClassic_Map_Server.packets.send;
|
using FFXIVClassic_Map_Server.packets.send;
|
||||||
|
using FFXIVClassic_Map_Server.Actors.Chara;
|
||||||
|
|
||||||
namespace FFXIVClassic_Map_Server.Actors
|
namespace FFXIVClassic_Map_Server.Actors
|
||||||
{
|
{
|
||||||
@ -56,12 +57,13 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
private uint despawnTime;
|
private uint despawnTime;
|
||||||
private uint respawnTime;
|
private uint respawnTime;
|
||||||
private uint spawnDistance;
|
private uint spawnDistance;
|
||||||
|
private uint bnpcId;
|
||||||
public Character lastAttacker;
|
public Character lastAttacker;
|
||||||
|
|
||||||
public uint spellListId, skillListId, dropListId;
|
public uint spellListId, skillListId, dropListId;
|
||||||
public Dictionary<uint, BattleCommand> skillList = new Dictionary<uint, BattleCommand>();
|
public Dictionary<uint, BattleCommand> skillList = new Dictionary<uint, BattleCommand>();
|
||||||
public Dictionary<uint, BattleCommand> spellList = new Dictionary<uint, BattleCommand>();
|
public Dictionary<uint, BattleCommand> spellList = new Dictionary<uint, BattleCommand>();
|
||||||
|
private Dictionary<MobModifier, Int64> mobModifiers = new Dictionary<MobModifier, Int64>();
|
||||||
|
|
||||||
public BattleNpc(int actorNumber, ActorClass actorClass, string uniqueId, Area spawnedArea, float posX, float posY, float posZ, float rot,
|
public BattleNpc(int actorNumber, ActorClass actorClass, string uniqueId, Area spawnedArea, float posX, float posY, float posZ, float rot,
|
||||||
ushort actorState, uint animationId, string customDisplayName)
|
ushort actorState, uint animationId, string customDisplayName)
|
||||||
@ -110,10 +112,43 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
subpackets.Add(CreateSetActorIconPacket());
|
subpackets.Add(CreateSetActorIconPacket());
|
||||||
subpackets.Add(CreateIsZoneingPacket());
|
subpackets.Add(CreateIsZoneingPacket());
|
||||||
subpackets.Add(CreateScriptBindPacket(player));
|
subpackets.Add(CreateScriptBindPacket(player));
|
||||||
|
subpackets.Add(GetHateTypePacket(player));
|
||||||
}
|
}
|
||||||
return subpackets;
|
return subpackets;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SubPacket GetHateTypePacket(Player player)
|
||||||
|
{
|
||||||
|
npcWork.hateType = 1;
|
||||||
|
|
||||||
|
if (player != null)
|
||||||
|
{
|
||||||
|
if (aiContainer.IsEngaged())
|
||||||
|
{
|
||||||
|
npcWork.hateType = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player.actorId == this.currentLockedTarget)
|
||||||
|
{
|
||||||
|
npcWork.hateType = NpcWork.HATE_TYPE_ENGAGED_PARTY;
|
||||||
|
}
|
||||||
|
else if (player.currentParty != null)
|
||||||
|
{
|
||||||
|
foreach (var memberId in ((Party)player.currentParty).members)
|
||||||
|
{
|
||||||
|
if (this.currentLockedTarget == memberId)
|
||||||
|
{
|
||||||
|
npcWork.hateType = NpcWork.HATE_TYPE_ENGAGED_PARTY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var propPacketUtil = new ActorPropertyPacketUtil("npcWork", this);
|
||||||
|
propPacketUtil.AddProperty("npcWork.hateType");
|
||||||
|
return propPacketUtil.Done()[0];
|
||||||
|
}
|
||||||
|
|
||||||
public uint GetDetectionType()
|
public uint GetDetectionType()
|
||||||
{
|
{
|
||||||
return (uint)detectionType;
|
return (uint)detectionType;
|
||||||
@ -220,6 +255,23 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ForceRespawn()
|
||||||
|
{
|
||||||
|
base.Spawn(Program.Tick);
|
||||||
|
|
||||||
|
this.isMovingToSpawn = false;
|
||||||
|
this.ResetMoveSpeeds();
|
||||||
|
this.hateContainer.ClearHate();
|
||||||
|
zone.BroadcastPacketsAroundActor(this, GetSpawnPackets(null, 0x01));
|
||||||
|
zone.BroadcastPacketsAroundActor(this, GetInitPackets());
|
||||||
|
charaWork.parameterSave.hp = charaWork.parameterSave.hpMax;
|
||||||
|
charaWork.parameterSave.mp = charaWork.parameterSave.mpMax;
|
||||||
|
RecalculateStats();
|
||||||
|
|
||||||
|
OnSpawn();
|
||||||
|
updateFlags |= ActorUpdateFlags.AllNpc;
|
||||||
|
}
|
||||||
|
|
||||||
public override void Die(DateTime tick)
|
public override void Die(DateTime tick)
|
||||||
{
|
{
|
||||||
if (IsAlive())
|
if (IsAlive())
|
||||||
@ -308,6 +360,25 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
base.OnAttack(state, action, ref error);
|
base.OnAttack(state, action, ref error);
|
||||||
// todo: move this somewhere else prolly and change based on model/appearance (so maybe in Character.cs instead)
|
// todo: move this somewhere else prolly and change based on model/appearance (so maybe in Character.cs instead)
|
||||||
action.animation = 0x11001000; // (temporary) wolf anim
|
action.animation = 0x11001000; // (temporary) wolf anim
|
||||||
|
|
||||||
|
if (GetMobMod((uint)MobModifier.AttackScript) != 0)
|
||||||
|
lua.LuaEngine.CallLuaBattleFunction(this, "onAttack", this, state.GetTarget(), action.amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnCast(State state, BattleAction[] actions, ref BattleAction[] errors)
|
||||||
|
{
|
||||||
|
base.OnCast(state, actions, ref errors);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnAbility(State state, BattleAction[] actions, ref BattleAction[] errors)
|
||||||
|
{
|
||||||
|
base.OnAbility(state, actions, ref errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnWeaponSkill(State state, BattleAction[] actions, ref BattleAction[] errors)
|
||||||
|
{
|
||||||
|
base.OnWeaponSkill(state, actions, ref errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnSpawn()
|
public override void OnSpawn()
|
||||||
@ -325,5 +396,38 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
{
|
{
|
||||||
base.OnDespawn();
|
base.OnDespawn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public uint GetBattleNpcId()
|
||||||
|
{
|
||||||
|
return bnpcId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetBattleNpcId(uint id)
|
||||||
|
{
|
||||||
|
this.bnpcId = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Int64 GetMobMod(uint mobModId)
|
||||||
|
{
|
||||||
|
Int64 res;
|
||||||
|
if (mobModifiers.TryGetValue((MobModifier)mobModId, out res))
|
||||||
|
return res;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetMobMod(uint mobModId, Int64 val)
|
||||||
|
{
|
||||||
|
if (mobModifiers.ContainsKey((MobModifier)mobModId))
|
||||||
|
mobModifiers[(MobModifier)mobModId] = val;
|
||||||
|
else
|
||||||
|
mobModifiers.Add((MobModifier)mobModId, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnDamageTaken(Character attacker, BattleAction action)
|
||||||
|
{
|
||||||
|
if (GetMobMod((uint)MobModifier.DefendScript) != 0)
|
||||||
|
lua.LuaEngine.CallLuaBattleFunction(this, "onDamageTaken", this, attacker, action.amount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
36
FFXIVClassic Map Server/actors/chara/npc/MobModifier.cs
Normal file
36
FFXIVClassic Map Server/actors/chara/npc/MobModifier.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FFXIVClassic_Map_Server.actors.chara.npc
|
||||||
|
{
|
||||||
|
enum MobModifier
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
SpawnLeash = 1, // how far can i move before i deaggro target
|
||||||
|
SightRange = 2, // how close does target need to be for me to detect by sight
|
||||||
|
SoundRange = 3, // how close does target need to be for me to detect by sound
|
||||||
|
BuffChance = 4,
|
||||||
|
HealChance = 5,
|
||||||
|
SkillUseChance = 6,
|
||||||
|
LinkRadius = 7,
|
||||||
|
MagicDelay = 8,
|
||||||
|
SpecialDelay = 9,
|
||||||
|
ExpBonus = 10, //
|
||||||
|
IgnoreSpawnLeash = 11, // pursue target forever
|
||||||
|
DrawIn = 12, // do i suck people in around me
|
||||||
|
HpScale = 13, //
|
||||||
|
Assist = 14, // gotta call the bois
|
||||||
|
NoMove = 15, // cant move
|
||||||
|
ShareTarget = 16, // use this actor's id as target id
|
||||||
|
AttackScript = 17, // call my script's onAttack whenever i attack
|
||||||
|
DefendScript = 18, // call my script's onDamageTaken whenever i take damage
|
||||||
|
SpellScript = 19, // call my script's onSpellCast whenever i finish casting
|
||||||
|
WeaponskillScript = 20, // call my script's onWeaponSkill whenever i finish using a weaponskill
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
@ -414,6 +414,17 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
aiContainer.Update(tick);
|
aiContainer.Update(tick);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void PostUpdate(DateTime tick, List<SubPacket> packets = null)
|
||||||
|
{
|
||||||
|
packets = packets ?? new List<SubPacket>();
|
||||||
|
|
||||||
|
if ((updateFlags & ActorUpdateFlags.Work) != 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
base.PostUpdate(tick, packets);
|
||||||
|
}
|
||||||
|
|
||||||
public override void OnSpawn()
|
public override void OnSpawn()
|
||||||
{
|
{
|
||||||
base.OnSpawn();
|
base.OnSpawn();
|
||||||
|
@ -2,6 +2,10 @@
|
|||||||
{
|
{
|
||||||
class NpcWork
|
class NpcWork
|
||||||
{
|
{
|
||||||
|
public static byte HATE_TYPE_NONE = 0;
|
||||||
|
public static byte HATE_TYPE_ENGAGED = 2;
|
||||||
|
public static byte HATE_TYPE_ENGAGED_PARTY = 3;
|
||||||
|
|
||||||
public ushort pushCommand;
|
public ushort pushCommand;
|
||||||
public int pushCommandSub;
|
public int pushCommandSub;
|
||||||
public byte pushCommandPriority;
|
public byte pushCommandPriority;
|
||||||
|
@ -25,6 +25,7 @@ using FFXIVClassic_Map_Server.actors.chara.ai.controllers;
|
|||||||
using FFXIVClassic_Map_Server.packets.send.actor.battle;
|
using FFXIVClassic_Map_Server.packets.send.actor.battle;
|
||||||
using FFXIVClassic_Map_Server.actors.chara.ai.utils;
|
using FFXIVClassic_Map_Server.actors.chara.ai.utils;
|
||||||
using FFXIVClassic_Map_Server.actors.chara.ai.state;
|
using FFXIVClassic_Map_Server.actors.chara.ai.state;
|
||||||
|
using FFXIVClassic_Map_Server.actors.chara.npc;
|
||||||
|
|
||||||
namespace FFXIVClassic_Map_Server.Actors
|
namespace FFXIVClassic_Map_Server.Actors
|
||||||
{
|
{
|
||||||
@ -2037,6 +2038,47 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
SendGameMessage(Server.GetWorldManager().GetActor(), 32549, 0x20);
|
SendGameMessage(Server.GetWorldManager().GetActor(), 32549, 0x20);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool partyEngaged = false;
|
||||||
|
// todo: replace with confrontation status effect? (see how dsp does it)
|
||||||
|
if (target.aiContainer.IsEngaged())
|
||||||
|
{
|
||||||
|
if (currentParty != null)
|
||||||
|
{
|
||||||
|
if (target is BattleNpc)
|
||||||
|
{
|
||||||
|
var helpingActorId = ((BattleNpc)target).GetMobMod((uint)MobModifier.CallForHelp);
|
||||||
|
partyEngaged = this.actorId == helpingActorId || (((BattleNpc)target).GetMobMod((uint)MobModifier.FreeForAll) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!partyEngaged)
|
||||||
|
{
|
||||||
|
foreach (var memberId in ((Party)currentParty).members)
|
||||||
|
{
|
||||||
|
if (memberId == target.currentLockedTarget)
|
||||||
|
{
|
||||||
|
partyEngaged = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (target.currentLockedTarget == actorId)
|
||||||
|
{
|
||||||
|
partyEngaged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
partyEngaged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!partyEngaged)
|
||||||
|
{
|
||||||
|
// That target is already engaged.
|
||||||
|
SendGameMessage(Server.GetWorldManager().GetActor(), 32520, 0x20);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((validTarget & ValidTarget.Ally) != 0 && target.allegiance != allegiance)
|
if ((validTarget & ValidTarget.Ally) != 0 && target.allegiance != allegiance)
|
||||||
|
27
data/scripts/commands/weaponskill/fast_blade.lua
Normal file
27
data/scripts/commands/weaponskill/fast_blade.lua
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
require("global");
|
||||||
|
require("weaponskill");
|
||||||
|
|
||||||
|
function onSkillPrepare(caster, target, spell)
|
||||||
|
return 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function onSkillStart(caster, target, spell)
|
||||||
|
return 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function onSkillFinish(caster, target, spell, action)
|
||||||
|
local damage = math.random(10, 100);
|
||||||
|
|
||||||
|
-- todo: populate a global script with statuses and modifiers
|
||||||
|
action.worldMasterTextId = 0x765D;
|
||||||
|
|
||||||
|
-- todo: populate a global script with statuses and modifiers
|
||||||
|
-- magic.HandleAttackSkill(caster, target, spell, action)
|
||||||
|
-- action.effectId = bit32.bxor(0x8000000, spell.effectAnimation, 15636);
|
||||||
|
action.effectId = bit32.bxor(0x8000000, spell.effectAnimation, 15636);
|
||||||
|
|
||||||
|
if target.hateContainer then
|
||||||
|
target.hateContainer.UpdateHate(caster, damage);
|
||||||
|
end;
|
||||||
|
return damage;
|
||||||
|
end;
|
@ -7,10 +7,11 @@ magic =
|
|||||||
};
|
};
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
modifier - Modifier.Intelligence, Modifier.Mind (see Modifier.cs)
|
statId - see BattleTemp.cs
|
||||||
|
modifierId - Modifier.Intelligence, Modifier.Mind (see Modifier.cs)
|
||||||
multiplier -
|
multiplier -
|
||||||
]]
|
]]
|
||||||
function magic.HandleHealingMagic(caster, target, spell, action, modifierId, multiplier, baseAmount)
|
function magic.HandleHealingMagic(caster, target, spell, action, statId, modifierId, multiplier, baseAmount)
|
||||||
potency = potency or 1.0;
|
potency = potency or 1.0;
|
||||||
healAmount = baseAmount;
|
healAmount = baseAmount;
|
||||||
|
|
||||||
@ -18,19 +19,19 @@ function magic.HandleHealingMagic(caster, target, spell, action, modifierId, mul
|
|||||||
local mind = caster.GetMod(Modifier.Mind);
|
local mind = caster.GetMod(Modifier.Mind);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function magic.HandleAttackMagic(caster, target, spell, action, modifierId, multiplier, baseAmount)
|
function magic.HandleAttackMagic(caster, target, spell, action, statId, modifierId, multiplier, baseAmount)
|
||||||
-- todo: actually handle this
|
-- todo: actually handle this
|
||||||
damage = baseAmount or math.random(1,10) * 10;
|
damage = baseAmount or math.random(1,10) * 10;
|
||||||
|
|
||||||
return damage;
|
return damage;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function magic.HandleEvasion(caster, target, spell, action, modifierId)
|
function magic.HandleEvasion(caster, target, spell, action, statId, modifierId)
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function magic.HandleStoneskin(caster, target, spell, action, modifierId, damage)
|
function magic.HandleStoneskin(caster, target, spell, action, statId, modifierId, damage)
|
||||||
--[[
|
--[[
|
||||||
if target.statusEffects.HasStatusEffect(StatusEffect.Stoneskin) then
|
if target.statusEffects.HasStatusEffect(StatusEffect.Stoneskin) then
|
||||||
-- todo: damage reduction
|
-- todo: damage reduction
|
||||||
|
42
data/scripts/weaponskill.lua
Normal file
42
data/scripts/weaponskill.lua
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
-- todo: add enums for status effects in global.lua
|
||||||
|
require("global")
|
||||||
|
|
||||||
|
weaponskill =
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
--[[
|
||||||
|
statId - see BattleTemp.cs
|
||||||
|
modifier - Modifier.Intelligence, Modifier.Mind (see Modifier.cs)
|
||||||
|
multiplier -
|
||||||
|
]]
|
||||||
|
function weaponskill.HandleHealingSkill(caster, target, spell, action, statId, modifierId, multiplier, baseAmount)
|
||||||
|
potency = potency or 1.0;
|
||||||
|
healAmount = baseAmount;
|
||||||
|
|
||||||
|
-- todo: shit based on mnd
|
||||||
|
local mind = caster.GetMod(Modifier.Mind);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function weaponskill.HandleAttackSkill(caster, target, spell, action, statId, modifierId, multiplier, baseAmount)
|
||||||
|
-- todo: actually handle this
|
||||||
|
damage = baseAmount or math.random(1,10) * 10;
|
||||||
|
|
||||||
|
return damage;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function weaponskill.HandleEvasion(caster, target, spell, action, statId, modifierId)
|
||||||
|
|
||||||
|
return false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function weaponskill.HandleStoneskin(caster, target, spell, action, statId, modifierId, damage)
|
||||||
|
--[[
|
||||||
|
if target.statusEffects.HasStatusEffect(StatusEffect.Stoneskin) then
|
||||||
|
-- todo: damage reduction
|
||||||
|
return true;
|
||||||
|
end;
|
||||||
|
]]
|
||||||
|
return false;
|
||||||
|
end;
|
@ -23,14 +23,14 @@ DROP TABLE IF EXISTS `server_battlenpc_spawn_locations`;
|
|||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8 */;
|
/*!40101 SET character_set_client = utf8 */;
|
||||||
CREATE TABLE `server_battlenpc_spawn_locations` (
|
CREATE TABLE `server_battlenpc_spawn_locations` (
|
||||||
`bnpcIndex` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
`bnpcId` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`customDisplayName` varchar(32) NOT NULL DEFAULT '',
|
`customDisplayName` varchar(32) NOT NULL DEFAULT '',
|
||||||
`groupId` int(10) unsigned NOT NULL,
|
`groupId` int(10) unsigned NOT NULL,
|
||||||
`positionX` float NOT NULL,
|
`positionX` float NOT NULL,
|
||||||
`positionY` float NOT NULL,
|
`positionY` float NOT NULL,
|
||||||
`positionZ` float NOT NULL,
|
`positionZ` float NOT NULL,
|
||||||
`rotation` float NOT NULL,
|
`rotation` float NOT NULL,
|
||||||
PRIMARY KEY (`bnpcIndex`)
|
PRIMARY KEY (`bnpcId`)
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
|
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
@ -56,4 +56,4 @@ commit;
|
|||||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||||
|
|
||||||
-- Dump completed on 2017-09-07 21:54:41
|
-- Dump completed on 2017-09-10 2:47:43
|
||||||
|
Loading…
Reference in New Issue
Block a user