# Conflicts:
#	data/scripts/modifiers.lua
This commit is contained in:
Tahir Akhlaq 2017-12-10 15:07:28 +00:00
commit cd60c571ac
54 changed files with 935 additions and 268 deletions

View File

@ -10,7 +10,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>FFXIVClassic.Common</RootNamespace> <RootNamespace>FFXIVClassic.Common</RootNamespace>
<AssemblyName>FFXIVClassic.Common</AssemblyName> <AssemblyName>FFXIVClassic.Common</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<TargetFrameworkProfile> <TargetFrameworkProfile>
</TargetFrameworkProfile> </TargetFrameworkProfile>
@ -38,6 +38,26 @@
<Prefer32Bit>false</Prefer32Bit> <Prefer32Bit>false</Prefer32Bit>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="DotNetZip"> <Reference Include="DotNetZip">
<HintPath>..\packages\DotNetZip.1.10.1\lib\net20\DotNetZip.dll</HintPath> <HintPath>..\packages\DotNetZip.1.10.1\lib\net20\DotNetZip.dll</HintPath>

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<system.data> <system.data>
<DbProviderFactories> <DbProviderFactories>
<remove invariant="MySql.Data.MySqlClient" /> <remove invariant="MySql.Data.MySqlClient"/>
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.9.8.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" /> <add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.9.8.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d"/>
</DbProviderFactories> </DbProviderFactories>
</system.data> </system.data>
</configuration> <startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1"/></startup></configuration>

View File

@ -10,7 +10,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>FFXIVClassic_Lobby_Server</RootNamespace> <RootNamespace>FFXIVClassic_Lobby_Server</RootNamespace>
<AssemblyName>FFXIVClassic_Lobby_Server</AssemblyName> <AssemblyName>FFXIVClassic_Lobby_Server</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<IsWebBootstrapper>false</IsWebBootstrapper> <IsWebBootstrapper>false</IsWebBootstrapper>
<PublishUrl>publish\</PublishUrl> <PublishUrl>publish\</PublishUrl>
@ -28,6 +28,7 @@
<UseApplicationTrust>false</UseApplicationTrust> <UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled> <BootstrapperEnabled>true</BootstrapperEnabled>
<NuGetPackageImportStamp>cc1ba6f5</NuGetPackageImportStamp> <NuGetPackageImportStamp>cc1ba6f5</NuGetPackageImportStamp>
<TargetFrameworkProfile />
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget> <PlatformTarget>AnyCPU</PlatformTarget>
@ -50,6 +51,28 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Cyotek.Collections.Generic.CircularBuffer"> <Reference Include="Cyotek.Collections.Generic.CircularBuffer">
<HintPath>..\packages\Cyotek.CircularBuffer.1.0.0.0\lib\net20\Cyotek.Collections.Generic.CircularBuffer.dll</HintPath> <HintPath>..\packages\Cyotek.CircularBuffer.1.0.0.0\lib\net20\Cyotek.Collections.Generic.CircularBuffer.dll</HintPath>

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<system.data> <system.data>
<DbProviderFactories> <DbProviderFactories>
<remove invariant="MySql.Data.MySqlClient" /> <remove invariant="MySql.Data.MySqlClient"/>
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.9.8.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" /> <add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.9.8.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d"/>
</DbProviderFactories> </DbProviderFactories>
</system.data> </system.data>
</configuration> <startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1"/></startup></configuration>

View File

@ -40,6 +40,28 @@
<PropertyGroup> <PropertyGroup>
<RunPostBuildEvent>Always</RunPostBuildEvent> <RunPostBuildEvent>Always</RunPostBuildEvent>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Cyotek.Collections.Generic.CircularBuffer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=58daa28b0b2de221, processorArchitecture=MSIL"> <Reference Include="Cyotek.Collections.Generic.CircularBuffer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=58daa28b0b2de221, processorArchitecture=MSIL">
<HintPath>..\packages\Cyotek.CircularBuffer.1.0.0.0\lib\net20\Cyotek.Collections.Generic.CircularBuffer.dll</HintPath> <HintPath>..\packages\Cyotek.CircularBuffer.1.0.0.0\lib\net20\Cyotek.Collections.Generic.CircularBuffer.dll</HintPath>

View File

@ -511,7 +511,6 @@ namespace FFXIVClassic_Map_Server
battleNpc.SetMod((uint)Modifier.Defense, reader.GetUInt32("def")); battleNpc.SetMod((uint)Modifier.Defense, reader.GetUInt32("def"));
battleNpc.SetMod((uint)Modifier.Evasion, reader.GetUInt32("eva")); battleNpc.SetMod((uint)Modifier.Evasion, reader.GetUInt32("eva"));
battleNpc.dropListId = reader.GetUInt32("dropListId"); battleNpc.dropListId = reader.GetUInt32("dropListId");
battleNpc.spellListId = reader.GetUInt32("spellListId"); battleNpc.spellListId = reader.GetUInt32("spellListId");
battleNpc.skillListId = reader.GetUInt32("skillListId"); 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.Defense, reader.GetUInt32("def"));
battleNpc.SetMod((uint)Modifier.Evasion, reader.GetUInt32("eva")); 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.dropListId = reader.GetUInt32("dropListId");
battleNpc.spellListId = reader.GetUInt32("spellListId"); battleNpc.spellListId = reader.GetUInt32("spellListId");
battleNpc.skillListId = reader.GetUInt32("skillListId"); battleNpc.skillListId = reader.GetUInt32("skillListId");
battleNpc.SetMaxHP(1000);
battleNpc.SetHP(1000);
battleNpc.SetBattleNpcId(reader.GetUInt32("bnpcId")); battleNpc.SetBattleNpcId(reader.GetUInt32("bnpcId"));
battleNpc.SetRespawnTime(reader.GetUInt32("respawnTime"));
battleNpc.CalculateBaseStats(); battleNpc.CalculateBaseStats();
battleNpc.RecalculateStats(); battleNpc.RecalculateStats();
//battleNpc.SetMod((uint)Modifier.ResistFire, ) //battleNpc.SetMod((uint)Modifier.ResistFire, )
@ -679,7 +714,7 @@ namespace FFXIVClassic_Map_Server
try try
{ {
conn.Open(); 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); MySqlCommand cmd = new MySqlCommand(query, conn);
@ -688,9 +723,9 @@ namespace FFXIVClassic_Map_Server
while (reader.Read()) while (reader.Read())
{ {
var id = reader.GetUInt32(primaryKey); 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")); modList.SetModifier(reader.GetUInt16("modId"), reader.GetInt64("modVal"), reader.GetBoolean("isMobMod"));
list.Add(id, modList); list[id] = modList;
} }
} }
} }

View File

@ -438,9 +438,6 @@ namespace FFXIVClassic_Map_Server.Actors
updateFlags = ActorUpdateFlags.None; updateFlags = ActorUpdateFlags.None;
zone.BroadcastPacketsAroundActor(this, packets); zone.BroadcastPacketsAroundActor(this, packets);
SetActorPropetyPacket hpInfo = new SetActorPropetyPacket("charaWork/exp");
hpInfo.AddTarget();
} }
} }

View File

@ -500,8 +500,8 @@ namespace FFXIVClassic_Map_Server.Actors
npc = new Npc(mActorList.Count + 1, actorClass, uniqueId, this, x, y, z, rot, state, animId, null); npc = new Npc(mActorList.Count + 1, actorClass, uniqueId, this, x, y, z, rot, state, animId, null);
npc.LoadEventConditions(actorClass.eventConditions); npc.LoadEventConditions(actorClass.eventConditions);
npc.SetMaxHP(300); //npc.SetMaxHP(30000);
npc.SetHP(300); //npc.SetHP(30000);
AddActorToZone(npc); AddActorToZone(npc);
@ -672,7 +672,7 @@ namespace FFXIVClassic_Map_Server.Actors
if ((tick - lastUpdateScript).TotalMilliseconds > 1500) if ((tick - lastUpdateScript).TotalMilliseconds > 1500)
{ {
LuaEngine.GetInstance().CallLuaFunctionForReturn(LuaEngine.GetScriptPath(this), "onUpdate", true, this, tick); //LuaEngine.GetInstance().CallLuaFunctionForReturn(LuaEngine.GetScriptPath(this), "onUpdate", true, this, tick);
lastUpdateScript = tick; lastUpdateScript = tick;
} }
} }

View File

@ -132,6 +132,18 @@ namespace FFXIVClassic_Map_Server.actors.area
return actor; 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; return null;
} }
else else

View File

@ -229,10 +229,10 @@ namespace FFXIVClassic_Map_Server.Actors
public void DoBattleAction(ushort commandId, uint animationId, BattleAction[] actions) public void DoBattleAction(ushort commandId, uint animationId, BattleAction[] actions)
{ {
int currentIndex = 0; int currentIndex = 0;
//AoE abilities only ever hit 16 people, so we probably won't need this loop anymore
while (true) while (true)
{ {
if (actions.Length - currentIndex >= 18) if (actions.Length - currentIndex >= 10)
zone.BroadcastPacketAroundActor(this, BattleActionX18Packet.BuildPacket(actorId, animationId, commandId, actions, ref currentIndex)); zone.BroadcastPacketAroundActor(this, BattleActionX18Packet.BuildPacket(actorId, animationId, commandId, actions, ref currentIndex));
else if (actions.Length - currentIndex > 1) else if (actions.Length - currentIndex > 1)
zone.BroadcastPacketAroundActor(this, BattleActionX10Packet.BuildPacket(actorId, animationId, commandId, actions, ref currentIndex)); zone.BroadcastPacketAroundActor(this, BattleActionX10Packet.BuildPacket(actorId, animationId, commandId, actions, ref currentIndex));
@ -243,7 +243,9 @@ namespace FFXIVClassic_Map_Server.Actors
} }
else else
break; break;
animationId = 0; //If more than one packet is sent out, only send the animation once to avoid double playing.
//I think aoe effects play on all hit enemies. Firaga does at least
//animationId = 0; //If more than one packet is sent out, only send the animation once to avoid double playing.
} }
} }
@ -298,7 +300,7 @@ namespace FFXIVClassic_Map_Server.Actors
public virtual void OnPath(Vector3 point) public virtual void OnPath(Vector3 point)
{ {
lua.LuaEngine.CallLuaBattleFunction(this, "onPath", this, point); //lua.LuaEngine.CallLuaBattleFunction(this, "onPath", this, point);
updateFlags |= ActorUpdateFlags.Position; updateFlags |= ActorUpdateFlags.Position;
this.isAtSpawn = false; this.isAtSpawn = false;
@ -332,7 +334,7 @@ namespace FFXIVClassic_Map_Server.Actors
if ((updateFlags & ActorUpdateFlags.HpTpMp) != 0) 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.mp");
propPacketUtil.AddProperty("charaWork.parameterSave.mpMax"); propPacketUtil.AddProperty("charaWork.parameterSave.mpMax");
@ -455,6 +457,7 @@ namespace FFXIVClassic_Map_Server.Actors
{ {
// todo: actual despawn timer // todo: actual despawn timer
aiContainer.InternalDie(tick, 10); aiContainer.InternalDie(tick, 10);
ChangeSpeed(0.0f, 0.0f, 0.0f, 0.0f);
} }
public virtual void Despawn(DateTime tick) public virtual void Despawn(DateTime tick)
@ -528,6 +531,20 @@ namespace FFXIVClassic_Map_Server.Actors
updateFlags |= ActorUpdateFlags.HpTpMp; 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 // 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) public virtual void AddHP(int hp)
{ {
@ -547,7 +564,7 @@ namespace FFXIVClassic_Map_Server.Actors
} }
} }
public short GetJob() public short GetClass()
{ {
return charaWork.parameterSave.state_mainSkill[0]; return charaWork.parameterSave.state_mainSkill[0];
} }
@ -599,8 +616,30 @@ namespace FFXIVClassic_Map_Server.Actors
public void RecalculateStats() 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 // todo: recalculate stats and crap
updateFlags |= ActorUpdateFlags.HpTpMp; updateFlags |= ActorUpdateFlags.HpTpMp;
@ -635,14 +674,8 @@ namespace FFXIVClassic_Map_Server.Actors
//var packet = BattleActionX01Packet.BuildPacket(owner.actorId, owner.actorId, target.actorId, (uint)0x19001000, (uint)0x8000604, (ushort)0x765D, (ushort)BattleActionX01PacketCommand.Attack, (ushort)damage, (byte)0x1); //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 // todo: call onAttack/onDamageTaken
target.DelHP(action.amount); BattleUtils.DamageTarget(this, target, action, DamageTakenType.Attack);
if (target is BattleNpc)
{
((BattleNpc)target).lastAttacker = this;
((BattleNpc)target).hateContainer.UpdateHate(this, action.amount);
}
AddTP(115); AddTP(115);
target.AddTP(100); target.AddTP(100);
} }
@ -651,13 +684,14 @@ namespace FFXIVClassic_Map_Server.Actors
{ {
var spell = ((MagicState)state).GetSpell(); var spell = ((MagicState)state).GetSpell();
// 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 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) foreach (BattleAction action in actions)
zone.FindActorInArea<Character>(action.targetId).OnDamageTaken(this, action, DamageTakenType.Magic); if (zone.FindActorInArea<Character>(action.targetId) is Character chara)
BattleUtils.DamageTarget(this, chara, action, DamageTakenType.Magic);
if (target is BattleNpc) lua.LuaEngine.GetInstance().OnSignal("spellUsed");
((BattleNpc)target).lastAttacker = this;
} }
public virtual void OnWeaponSkill(State state, BattleAction[] actions, ref BattleAction[] errors) public virtual void OnWeaponSkill(State state, BattleAction[] actions, ref BattleAction[] errors)
@ -666,11 +700,11 @@ namespace FFXIVClassic_Map_Server.Actors
// damage is handled in script // damage is handled in script
this.DelTP(skill.tpCost); this.DelTP(skill.tpCost);
foreach (var action in actions) foreach (BattleAction action in actions)
zone.FindActorInArea<BattleNpc>(action.targetId)?.OnDamageTaken(this, action, DamageTakenType.Weaponskill); if (zone.FindActorInArea<Character>(action.targetId) is Character chara)
BattleUtils.DamageTarget(this, chara, action, DamageTakenType.Weaponskill);
if (target is BattleNpc) lua.LuaEngine.GetInstance().OnSignal("weaponskillUsed");
((BattleNpc)target).lastAttacker = this;
} }
public virtual void OnAbility(State state, BattleAction[] actions, ref BattleAction[] errors) public virtual void OnAbility(State state, BattleAction[] actions, ref BattleAction[] errors)
@ -756,22 +790,22 @@ namespace FFXIVClassic_Map_Server.Actors
public bool IsDiscipleOfWar() public bool IsDiscipleOfWar()
{ {
return currentJob < CLASSID_THM; return GetClass() < CLASSID_THM;
} }
public bool IsDiscipleOfMagic() public bool IsDiscipleOfMagic()
{ {
return currentJob >= CLASSID_THM && currentJob < CLASSID_CRP; return GetClass() >= CLASSID_THM && currentJob < CLASSID_CRP;
} }
public bool IsDiscipleOfHand() public bool IsDiscipleOfHand()
{ {
return currentJob >= CLASSID_CRP && currentJob < CLASSID_MIN; return GetClass() >= CLASSID_CRP && currentJob < CLASSID_MIN;
} }
public bool IsDiscipleOfLand() public bool IsDiscipleOfLand()
{ {
return currentJob >= CLASSID_MIN; return GetClass() >= CLASSID_MIN;
} }
#endregion lua helpers #endregion lua helpers
#endregion ai stuff #endregion ai stuff

View File

@ -5,6 +5,7 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using FFXIVClassic_Map_Server.Actors; using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.actors.chara.npc; using FFXIVClassic_Map_Server.actors.chara.npc;
using FFXIVClassic.Common;
namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
{ {
@ -18,34 +19,61 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
this.owner = owner; this.owner = owner;
} }
protected List<Character> GetContentGroupCharas()
{
List<Character> contentGroupCharas = null;
if (owner.currentContentGroup != 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);
}
}
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 // server really likes to hang whenever scripts iterate area's actorlist
protected override void DoCombatTick(DateTime tick, List<Character> contentGroupCharas = null) protected override void DoCombatTick(DateTime tick, List<Character> contentGroupCharas = null)
{ {
if (owner.currentContentGroup != null) if (contentGroupCharas == null)
{ {
contentGroupCharas = new List<Character>(owner.currentContentGroup.GetMemberCount()); contentGroupCharas = GetContentGroupCharas();
foreach (var charaId in owner.currentContentGroup.GetMembers()) }
{
var chara = owner.zone.FindActorInArea<Character>(charaId);
if (chara != null)
contentGroupCharas.Add(chara);
}
}
base.DoCombatTick(tick, contentGroupCharas); base.DoCombatTick(tick, contentGroupCharas);
} }
protected override void DoRoamTick(DateTime tick, List<Character> contentGroupCharas = null) protected override void DoRoamTick(DateTime tick, List<Character> contentGroupCharas = null)
{ {
if (owner.currentContentGroup != null) if (contentGroupCharas == null)
{ {
contentGroupCharas = new List<Character>(owner.currentContentGroup.GetMemberCount()); contentGroupCharas = GetContentGroupCharas();
foreach (var charaId in owner.currentContentGroup.GetMembers())
{
var chara = owner.zone.FindActorInArea<Character>(charaId);
if (chara != null)
contentGroupCharas.Add(chara);
}
} }
base.DoRoamTick(tick, contentGroupCharas); base.DoRoamTick(tick, contentGroupCharas);
} }

View File

@ -39,12 +39,20 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
public override void Update(DateTime tick) public override void Update(DateTime tick)
{ {
lastUpdate = tick; lastUpdate = tick;
// todo: handle aggro/deaggro and other shit here // todo: handle aggro/deaggro and other shit here
if (owner.aiContainer.IsEngaged()) if (!owner.aiContainer.IsEngaged())
{ {
DoCombatTick(tick); TryAggro(tick);
} }
else if (!owner.IsDead())
if(owner.aiContainer.IsEngaged())
{
//DoCombatTick(tick);
}
//Only move if owner isn't dead and is either too far away from their spawn point or is meant to roam
if (!owner.IsDead() && (owner.isMovingToSpawn || owner.GetMobMod((uint) MobModifier.Roams) > 0))
{ {
DoRoamTick(tick); DoRoamTick(tick);
} }
@ -63,6 +71,38 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
return false; 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) public override bool Engage(Character target)
{ {
var canEngage = this.owner.aiContainer.InternalEngage(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.ChangeState(SetActorStatePacket.MAIN_STATE_ACTIVE);
owner.moveState = 2; owner.moveState = 2;
//owner.SetMod((uint)Modifier.Speed, 5);
lastActionTime = DateTime.Now; lastActionTime = DateTime.Now;
battleStartTime = lastActionTime; battleStartTime = lastActionTime;
// todo: adjust cooldowns with modifiers // todo: adjust cooldowns with modifiers
@ -127,12 +168,6 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
protected virtual void DoRoamTick(DateTime tick, List<Character> contentGroupCharas = null) protected virtual void DoRoamTick(DateTime tick, List<Character> contentGroupCharas = null)
{ {
if (owner.hateContainer.GetHateList().Count > 0)
{
Engage(owner.hateContainer.GetMostHatedTarget());
return;
}
if (tick >= waitTime) if (tick >= waitTime)
{ {
neutralTime = tick.AddSeconds(5); neutralTime = tick.AddSeconds(5);
@ -148,7 +183,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
} }
} }
waitTime = tick.AddSeconds(10); waitTime = tick.AddSeconds(owner.GetMobMod((uint) MobModifier.RoamDelay));
owner.OnRoam(tick); owner.OnRoam(tick);
if (CanMoveForward(0.0f) && !owner.aiContainer.pathFind.IsFollowingPath()) if (CanMoveForward(0.0f) && !owner.aiContainer.pathFind.IsFollowingPath())
@ -157,31 +192,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
owner.aiContainer.pathFind.SetPathFlags(PathFindFlags.None); owner.aiContainer.pathFind.SetPathFlags(PathFindFlags.None);
owner.aiContainer.pathFind.PathInRange(owner.spawnX, owner.spawnY, owner.spawnZ, 1.5f, 50.0f); owner.aiContainer.pathFind.PathInRange(owner.spawnX, owner.spawnY, owner.spawnZ, 1.5f, 50.0f);
} }
lua.LuaEngine.CallLuaBattleFunction(owner, "onRoam", owner, contentGroupCharas); //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;
}
}
}
}
} }
if (owner.aiContainer.pathFind.IsFollowingPath() && owner.aiContainer.CanFollowPath()) if (owner.aiContainer.pathFind.IsFollowingPath() && owner.aiContainer.CanFollowPath())
@ -200,7 +211,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
return; return;
} }
Move(); Move();
if ((tick - lastCombatTickScript).TotalSeconds > 2) if ((tick - lastCombatTickScript).TotalSeconds > 2)
{ {
lua.LuaEngine.CallLuaBattleFunction(owner, "onCombatTick", owner, owner.target, Utils.UnixTimeStampUTC(tick), contentGroupCharas); lua.LuaEngine.CallLuaBattleFunction(owner, "onCombatTick", owner, owner.target, Utils.UnixTimeStampUTC(tick), contentGroupCharas);

View File

@ -159,6 +159,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
/// </summary> /// </summary>
public void FindWithinArea(Character target, ValidTarget flags, TargetFindAOETarget aoeTarget) public void FindWithinArea(Character target, ValidTarget flags, TargetFindAOETarget aoeTarget)
{ {
targets.Clear();
validTarget = flags; validTarget = flags;
// are we creating aoe circles around target or self // are we creating aoe circles around target or self
if (aoeTarget == TargetFindAOETarget.Self) if (aoeTarget == TargetFindAOETarget.Self)
@ -174,6 +175,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
if (masterTarget != null) if (masterTarget != null)
targets.Add(masterTarget); targets.Add(masterTarget);
if (aoeType != TargetFindAOEType.None)
{
if (IsPlayer(owner)) if (IsPlayer(owner))
{ {
if (masterTarget is Player) if (masterTarget is Player)
@ -226,7 +229,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
AddAllInHateList(); AddAllInHateList();
} }
} }
}
if(targets.Count > 16)
targets.RemoveRange(16, targets.Count - 16);
} }
/// <summary> /// <summary>
@ -288,7 +293,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
private void AddAllBattleNpcs(Character target, bool withPet) 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) foreach (BattleNpc actor in actors)
{ {
@ -375,12 +381,13 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
private bool IsWithinCircle(Character target, float maxDistance) private bool IsWithinCircle(Character target, float maxDistance)
{ {
// todo: make y diff modifiable? // 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) if (this.targetPosition == null)
this.targetPosition = aoeTarget == TargetFindAOETarget.Self ? owner.GetPosAsVector3() : masterTarget.GetPosAsVector3(); 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) private bool IsPlayer(Character target)

View File

@ -129,6 +129,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
private bool CanAttack() private bool CanAttack()
{ {
return false;
if (!owner.isAutoAttackEnabled) if (!owner.isAutoAttackEnabled)
{ {
return false; return false;

View File

@ -15,7 +15,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
: base(owner, null) : base(owner, null)
{ {
owner.Disengage(); 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; canInterrupt = false;
startTime = tick; startTime = tick;
despawnTime = startTime.AddSeconds(timeToFadeOut); despawnTime = startTime.AddSeconds(timeToFadeOut);

View File

@ -110,16 +110,16 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
var i = 0; var i = 0;
foreach (var chara in targets) 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); action.amount = (ushort)lua.LuaEngine.CallLuaBattleCommandFunction(owner, spell, "magic", "onMagicFinish", owner, chara, spell, action);
actions[i++] = action; actions[i++] = action;
} }
// todo: this is fuckin stupid, probably only need *one* error packet, not an error for each action // todo: this is fuckin stupid, probably only need *one* error packet, not an error for each action
var errors = (BattleAction[])actions.Clone(); var errors = (BattleAction[])actions.Clone();
owner.OnCast(this, actions, ref errors); owner.OnCast(this, actions, ref errors);
owner.DoBattleAction(spell.id, spell.battleAnimation, actions); owner.DoBattleAction(spell.id, spell.battleAnimation, actions);
} }
public override void TryInterrupt() public override void TryInterrupt()

View File

@ -88,7 +88,6 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
{ {
skill.targetFind.FindWithinArea(target, skill.validTarget, skill.aoeTarget); skill.targetFind.FindWithinArea(target, skill.validTarget, skill.aoeTarget);
isCompleted = true; isCompleted = true;
var targets = skill.targetFind.GetTargets(); var targets = skill.targetFind.GetTargets();
BattleAction[] actions = new BattleAction[targets.Count]; BattleAction[] actions = new BattleAction[targets.Count];
@ -100,11 +99,11 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
// evasion, miss, dodge, etc to be handled in script, calling helpers from scripts/weaponskills.lua // 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); action.amount = (ushort)lua.LuaEngine.CallLuaBattleCommandFunction(owner, skill, "weaponskill", "onSkillFinish", owner, target, skill, action);
actions[i++] = 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 // todo: this is fuckin stupid, probably only need *one* error packet, not an error for each action
var errors = (BattleAction[])actions.Clone(); var errors = (BattleAction[])actions.Clone();
owner.OnWeaponSkill(this, actions, ref errors); owner.OnWeaponSkill(this, actions, ref errors);
owner.DoBattleAction(skill.id, skill.battleAnimation, actions); owner.DoBattleAction(skill.id, skill.battleAnimation, actions);
} }

View File

@ -76,18 +76,24 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.utils
return damage; return damage;
} }
public static void DamageTarget(Character attacker, Character defender, BattleAction action) public static void DamageTarget(Character attacker, Character defender, BattleAction action, DamageTakenType type)
{
if (defender != null)
{ {
// todo: other stuff too // todo: other stuff too
if (defender is BattleNpc) if (defender is BattleNpc)
{ {
if (!((BattleNpc)defender).hateContainer.HasHateForTarget(attacker)) var bnpc = defender as BattleNpc;
if (!bnpc.hateContainer.HasHateForTarget(attacker))
{ {
((BattleNpc)defender).hateContainer.AddBaseHate(attacker); bnpc.hateContainer.AddBaseHate(attacker);
} }
((BattleNpc)defender).hateContainer.UpdateHate(attacker, action.amount); bnpc.hateContainer.UpdateHate(attacker, action.amount);
bnpc.lastAttacker = attacker;
} }
defender.DelHP((short)action.amount); defender.DelHP((short)action.amount);
defender.OnDamageTaken(attacker, action, type);
}
} }
public static int CalculateSpellDamage(Character attacker, Character defender, BattleCommand spell) public static int CalculateSpellDamage(Character attacker, Character defender, BattleCommand spell)

View File

@ -172,7 +172,7 @@ namespace FFXIVClassic_Map_Server.Actors
packets = new List<SubPacket>(); packets = new List<SubPacket>();
if ((updateFlags & ActorUpdateFlags.HpTpMp) != 0) 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.hp[0]");
propPacketUtil.AddProperty("charaWork.parameterSave.hpMax[0]"); propPacketUtil.AddProperty("charaWork.parameterSave.hpMax[0]");
@ -272,6 +272,10 @@ namespace FFXIVClassic_Map_Server.Actors
if (lastAttacker is Player) 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) if (lastAttacker.currentParty != null && lastAttacker.currentParty is Party)
{ {
foreach (var memberId in ((Party)lastAttacker.currentParty).members) foreach (var memberId in ((Party)lastAttacker.currentParty).members)
@ -279,14 +283,9 @@ namespace FFXIVClassic_Map_Server.Actors
var partyMember = zone.FindActorInArea<Player>(memberId); var partyMember = zone.FindActorInArea<Player>(memberId);
// onDeath(monster, player, killer) // onDeath(monster, player, killer)
lua.LuaEngine.CallLuaBattleFunction(this, "onDeath", this, partyMember, lastAttacker); 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 else
@ -298,6 +297,7 @@ namespace FFXIVClassic_Map_Server.Actors
} }
positionUpdates?.Clear(); positionUpdates?.Clear();
aiContainer.InternalDie(tick, despawnTime); aiContainer.InternalDie(tick, despawnTime);
//this.ResetMoveSpeeds();
// todo: reset cooldowns // todo: reset cooldowns
lua.LuaEngine.GetInstance().OnSignal("mobkill"); lua.LuaEngine.GetInstance().OnSignal("mobkill");

View File

@ -32,5 +32,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.npc
AbilityScript = 21, // call my script's onAbility whenever i finish using an ability 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 CallForHelp = 22, // actor with this id outside of target's party with this can attack me
FreeForAll = 23, // any actor 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
} }
} }

View File

@ -557,6 +557,9 @@ namespace FFXIVClassic_Map_Server.Actors
if (currentContentGroup != null) if (currentContentGroup != null)
currentContentGroup.SendGroupPackets(playerSession); currentContentGroup.SendGroupPackets(playerSession);
if (currentParty != null)
currentParty.SendGroupPackets(playerSession);
} }
private void SendRemoveInventoryPackets(List<ushort> slots) private void SendRemoveInventoryPackets(List<ushort> slots)
@ -1714,6 +1717,7 @@ namespace FFXIVClassic_Map_Server.Actors
//currentParty.members.Remove(this); //currentParty.members.Remove(this);
if (partyGroup.members.Count == 0) if (partyGroup.members.Count == 0)
Server.GetWorldManager().NoMembersInParty((Party)currentParty); Server.GetWorldManager().NoMembersInParty((Party)currentParty);
currentParty = null; currentParty = null;
} }
@ -1755,7 +1759,7 @@ namespace FFXIVClassic_Map_Server.Actors
if ((updateFlags & ActorUpdateFlags.HpTpMp) != 0) 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? // todo: should this be using job as index?
propPacketUtil.AddProperty($"charaWork.parameterSave.hp[{0}]"); propPacketUtil.AddProperty($"charaWork.parameterSave.hp[{0}]");
@ -1768,9 +1772,6 @@ namespace FFXIVClassic_Map_Server.Actors
} }
base.PostUpdate(tick, packets); base.PostUpdate(tick, packets);
SetActorPropetyPacket hpInfo = new SetActorPropetyPacket("charaWork/exp");
hpInfo.AddTarget();
QueuePacket(hpInfo.BuildPacket(actorId));
} }
public override void Die(DateTime tick) public override void Die(DateTime tick)
@ -1801,7 +1802,6 @@ namespace FFXIVClassic_Map_Server.Actors
public void UpdateHotbarCommands(List<ushort> slotsToUpdate) public void UpdateHotbarCommands(List<ushort> slotsToUpdate)
{ {
ActorPropertyPacketUtil propPacketUtil = new ActorPropertyPacketUtil("charaWork/command", this); ActorPropertyPacketUtil propPacketUtil = new ActorPropertyPacketUtil("charaWork/command", this);
ActorPropertyPacketUtil compatibiltyUtil = new ActorPropertyPacketUtil("charaWork/commandDetailForSelf", this);
foreach (ushort slot in slotsToUpdate) foreach (ushort slot in slotsToUpdate)
{ {
propPacketUtil.AddProperty($"charaWork.command[{slot}]"); 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) // 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); base.OnCast(state, actions, ref errors);
var spell = ((MagicState)state).GetSpell(); 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); UpdateHotbarTimer(spell.id, spell.recastTimeSeconds);
LuaEngine.GetInstance().OnSignal("spellUse"); LuaEngine.GetInstance().OnSignal("spellUse");
} }
@ -2309,11 +2309,11 @@ namespace FFXIVClassic_Map_Server.Actors
Database.LoadHotbar(this); 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() public byte GetCurrentClassOrJob()
{ {
if (currentJob != 0) if (currentJob != 0)
return (byte) currentJob; return (byte) currentJob;
return charaWork.parameterSave.state_mainSkill[0]; return charaWork.parameterSave.state_mainSkill[0];
} }
@ -2324,12 +2324,8 @@ namespace FFXIVClassic_Map_Server.Actors
mpMaxBase = (ushort)hp; mpMaxBase = (ushort)hp;
charaWork.parameterSave.mpMax = (short)hp; charaWork.parameterSave.mpMax = (short)hp;
charaWork.parameterSave.mp = (short)hp; charaWork.parameterSave.mp = (short)hp;
AddTP(0); AddTP(3000);
//SendCharaExpInfo(); updateFlags |= ActorUpdateFlags.HpTpMp;
//ActorPropertyPacketUtil exp = new ActorPropertyPacketUtil("charaWork/exp", this);
SetActorPropetyPacket hpInfo = new SetActorPropetyPacket("charaWork/exp");
hpInfo.AddTarget();
QueuePacket(hpInfo.BuildPacket(actorId));
} }
} }

View File

@ -161,6 +161,9 @@ namespace FFXIVClassic_Map_Server.actors.director
{ {
members.Add(actor); members.Add(actor);
if (actor is Player)
((Player)actor).AddDirector(this);
if (contentGroup != null) if (contentGroup != null)
contentGroup.AddMember(actor); contentGroup.AddMember(actor);
} }

View File

@ -42,6 +42,7 @@ namespace FFXIVClassic_Map_Server.actors.group
public void Start() public void Start()
{ {
isStarted = true; isStarted = true;
SendGroupPacketsAll(members); SendGroupPacketsAll(members);
} }
@ -50,6 +51,7 @@ namespace FFXIVClassic_Map_Server.actors.group
if (actor == null) if (actor == null)
return; return;
if(!members.Contains(actor.actorId))
members.Add(actor.actorId); members.Add(actor.actorId);
if (actor is Character) if (actor is Character)
@ -121,7 +123,6 @@ namespace FFXIVClassic_Map_Server.actors.group
} }
session.QueuePacket(GroupMembersEndPacket.buildPacket(session.id, session.GetActor().zoneId, time, this)); session.QueuePacket(GroupMembersEndPacket.buildPacket(session.id, session.GetActor().zoneId, time, this));
} }
public override uint GetTypeId() public override uint GetTypeId()

View File

@ -64,11 +64,23 @@ namespace FFXIVClassic_Map_Server.actors.group
groupMembers.Add(new GroupMember(id, -1, 0, false, true, Server.GetWorldManager().GetActorInWorld(id).customDisplayName)); groupMembers.Add(new GroupMember(id, -1, 0, false, true, Server.GetWorldManager().GetActorInWorld(id).customDisplayName));
foreach (uint charaId in members) foreach (uint charaId in members)
{ {
if (charaId != id) var chara = Server.GetWorldManager().GetActorInWorld(charaId);
groupMembers.Add(new GroupMember(charaId, -1, 0, false, true, Server.GetWorldManager().GetActorInWorld(charaId).customDisplayName)); if (charaId != id && chara != null)
groupMembers.Add(new GroupMember(charaId, -1, 0, false, true, chara.customDisplayName));
} }
return groupMembers; return groupMembers;
} }
public void AddMember(uint memberId)
{
members.Add(memberId);
SendGroupPacketsAll(members);
}
public void RemoveMember(uint memberId)
{
members.Remove(memberId);
SendGroupPacketsAll(members);
}
} }
} }

View File

@ -24,7 +24,7 @@ namespace FFXIVClassic_Map_Server.dataobjects
public void FlushQueuedSendPackets() public void FlushQueuedSendPackets()
{ {
if (!socket.Connected) if (socket == null || !socket.Connected)
return; return;
while (SendPacketQueue.Count > 0) while (SendPacketQueue.Count > 0)

View File

@ -477,12 +477,20 @@ namespace FFXIVClassic_Map_Server.lua
if (script != null) if (script != null)
{ {
if (!script.Globals.Get(funcName).IsNil()) if (!script.Globals.Get(funcName).IsNil())
{
try
{ {
Coroutine coroutine = script.CreateCoroutine(script.Globals[funcName]).Coroutine; Coroutine coroutine = script.CreateCoroutine(script.Globals[funcName]).Coroutine;
DynValue value = coroutine.Resume(args2); DynValue value = coroutine.Resume(args2);
ResolveResume(player, coroutine, value); ResolveResume(player, coroutine, value);
}
catch(Exception e)
{
player.SendMessage(0x20, "", e.Message);
player.EndEvent();
} }
}
else else
{ {
if (!optional) if (!optional)

View File

@ -112,7 +112,6 @@ namespace FFXIVClassic_Map_Server.packets.send.actor
{ {
string[] split = name.Split('.'); string[] split = name.Split('.');
int arrayIndex = 0; int arrayIndex = 0;
if (!(split[0].Equals("work") || split[0].Equals("charaWork") || split[0].Equals("playerWork") || split[0].Equals("npcWork") || split[0].Equals("guildleveWork"))) if (!(split[0].Equals("work") || split[0].Equals("charaWork") || split[0].Equals("playerWork") || split[0].Equals("npcWork") || split[0].Equals("guildleveWork")))
return false; return false;

View File

@ -35,27 +35,27 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle
binWriter.Write((UInt16)commandId); binWriter.Write((UInt16)commandId);
binWriter.Write((UInt16)0x810); //? binWriter.Write((UInt16)0x810); //?
binWriter.Seek(0x58, SeekOrigin.Begin); binWriter.Seek(0x28, SeekOrigin.Begin);
for (int i = 0; i < max; i++) for (int i = 0; i < max; i++)
binWriter.Write((UInt32)actionList[listOffset + i].targetId); binWriter.Write((UInt32)actionList[listOffset + i].targetId);
binWriter.Seek(0xA0, SeekOrigin.Begin); binWriter.Seek(0x70, SeekOrigin.Begin);
for (int i = 0; i < max; i++) for (int i = 0; i < max; i++)
binWriter.Write((UInt16)actionList[listOffset + i].amount); binWriter.Write((UInt16)actionList[listOffset + i].amount);
binWriter.Seek(0xC4, SeekOrigin.Begin); binWriter.Seek(0x94, SeekOrigin.Begin);
for (int i = 0; i < max; i++) for (int i = 0; i < max; i++)
binWriter.Write((UInt16)actionList[listOffset + i].worldMasterTextId); binWriter.Write((UInt16)actionList[listOffset + i].worldMasterTextId);
binWriter.Seek(0xE8, SeekOrigin.Begin); binWriter.Seek(0xB8, SeekOrigin.Begin);
for (int i = 0; i < max; i++) for (int i = 0; i < max; i++)
binWriter.Write((UInt32)actionList[listOffset + i].effectId); binWriter.Write((UInt32)actionList[listOffset + i].effectId);
binWriter.Seek(0x130, SeekOrigin.Begin); binWriter.Seek(0x100, SeekOrigin.Begin);
for (int i = 0; i < max; i++) for (int i = 0; i < max; i++)
binWriter.Write((Byte)actionList[listOffset + i].param); binWriter.Write((Byte)actionList[listOffset + i].param);
binWriter.Seek(0x142, SeekOrigin.Begin); binWriter.Seek(0x112, SeekOrigin.Begin);
for (int i = 0; i < max; i++) for (int i = 0; i < max; i++)
binWriter.Write((Byte)actionList[listOffset + i].unknown); binWriter.Write((Byte)actionList[listOffset + i].unknown);

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<startup> <startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1"/>
</startup> </startup>
<system.data> <system.data>
<DbProviderFactories> <DbProviderFactories>

View File

@ -9,7 +9,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>FFXIVClassic_World_Server</RootNamespace> <RootNamespace>FFXIVClassic_World_Server</RootNamespace>
<AssemblyName>FFXIVClassic World Server</AssemblyName> <AssemblyName>FFXIVClassic World Server</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFrameworkProfile /> <TargetFrameworkProfile />
@ -48,6 +48,26 @@
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Cyotek.Collections.Generic.CircularBuffer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=58daa28b0b2de221, processorArchitecture=MSIL"> <Reference Include="Cyotek.Collections.Generic.CircularBuffer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=58daa28b0b2de221, processorArchitecture=MSIL">
<HintPath>..\packages\Cyotek.CircularBuffer.1.0.0.0\lib\net20\Cyotek.Collections.Generic.CircularBuffer.dll</HintPath> <HintPath>..\packages\Cyotek.CircularBuffer.1.0.0.0\lib\net20\Cyotek.Collections.Generic.CircularBuffer.dll</HintPath>
@ -190,7 +210,8 @@
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup> <PropertyGroup>
<PostBuildEvent></PostBuildEvent> <PostBuildEvent>
</PostBuildEvent>
</PropertyGroup> </PropertyGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@ -6,5 +6,5 @@
<package id="NLog" version="4.3.5" targetFramework="net452" /> <package id="NLog" version="4.3.5" targetFramework="net452" />
<package id="NLog.Config" version="4.3.5" targetFramework="net452" /> <package id="NLog.Config" version="4.3.5" targetFramework="net452" />
<package id="NLog.Schema" version="4.3.4" targetFramework="net452" /> <package id="NLog.Schema" version="4.3.4" targetFramework="net452" />
<package id="RabbitMQ.Client" version="4.0.0" targetFramework="net452" requireReinstallation="True" /> <package id="RabbitMQ.Client" version="4.0.0" targetFramework="net452" />
</packages> </packages>

View File

@ -1,7 +1,7 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15 # Visual Studio 15
VisualStudioVersion = 15.0.26430.15 VisualStudioVersion = 15.0.27004.2005
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FFXIVClassic Map Server", "FFXIVClassic Map Server\FFXIVClassic Map Server.csproj", "{E8FA2784-D4B9-4711-8CC6-712A4B1CD54F}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FFXIVClassic Map Server", "FFXIVClassic Map Server\FFXIVClassic Map Server.csproj", "{E8FA2784-D4B9-4711-8CC6-712A4B1CD54F}"
ProjectSection(ProjectDependencies) = postProject ProjectSection(ProjectDependencies) = postProject
@ -23,38 +23,63 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Launcher Editor", "Launcher Editor\Launcher Editor.csproj", "{0FFA9D2F-41C6-443C-99B7-665702CF548F}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Launcher Editor", "Launcher Editor\Launcher Editor.csproj", "{0FFA9D2F-41C6-443C-99B7-665702CF548F}"
EndProject EndProject
Global Global
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Release|Any CPU = Release|Any CPU Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E8FA2784-D4B9-4711-8CC6-712A4B1CD54F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E8FA2784-D4B9-4711-8CC6-712A4B1CD54F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E8FA2784-D4B9-4711-8CC6-712A4B1CD54F}.Debug|Any CPU.Build.0 = Debug|Any CPU {E8FA2784-D4B9-4711-8CC6-712A4B1CD54F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E8FA2784-D4B9-4711-8CC6-712A4B1CD54F}.Debug|x64.ActiveCfg = Debug|x64
{E8FA2784-D4B9-4711-8CC6-712A4B1CD54F}.Debug|x64.Build.0 = Debug|x64
{E8FA2784-D4B9-4711-8CC6-712A4B1CD54F}.Release|Any CPU.ActiveCfg = Release|Any CPU {E8FA2784-D4B9-4711-8CC6-712A4B1CD54F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E8FA2784-D4B9-4711-8CC6-712A4B1CD54F}.Release|Any CPU.Build.0 = Release|Any CPU {E8FA2784-D4B9-4711-8CC6-712A4B1CD54F}.Release|Any CPU.Build.0 = Release|Any CPU
{E8FA2784-D4B9-4711-8CC6-712A4B1CD54F}.Release|x64.ActiveCfg = Release|x64
{E8FA2784-D4B9-4711-8CC6-712A4B1CD54F}.Release|x64.Build.0 = Release|x64
{703091E0-F69C-4177-8FAE-C258AC6A65AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {703091E0-F69C-4177-8FAE-C258AC6A65AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{703091E0-F69C-4177-8FAE-C258AC6A65AA}.Debug|Any CPU.Build.0 = Debug|Any CPU {703091E0-F69C-4177-8FAE-C258AC6A65AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{703091E0-F69C-4177-8FAE-C258AC6A65AA}.Debug|x64.ActiveCfg = Debug|x64
{703091E0-F69C-4177-8FAE-C258AC6A65AA}.Debug|x64.Build.0 = Debug|x64
{703091E0-F69C-4177-8FAE-C258AC6A65AA}.Release|Any CPU.ActiveCfg = Release|Any CPU {703091E0-F69C-4177-8FAE-C258AC6A65AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{703091E0-F69C-4177-8FAE-C258AC6A65AA}.Release|Any CPU.Build.0 = Release|Any CPU {703091E0-F69C-4177-8FAE-C258AC6A65AA}.Release|Any CPU.Build.0 = Release|Any CPU
{703091E0-F69C-4177-8FAE-C258AC6A65AA}.Release|x64.ActiveCfg = Release|x64
{703091E0-F69C-4177-8FAE-C258AC6A65AA}.Release|x64.Build.0 = Release|x64
{3A3D6626-C820-4C18-8C81-64811424F20E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3A3D6626-C820-4C18-8C81-64811424F20E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3A3D6626-C820-4C18-8C81-64811424F20E}.Debug|Any CPU.Build.0 = Debug|Any CPU {3A3D6626-C820-4C18-8C81-64811424F20E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3A3D6626-C820-4C18-8C81-64811424F20E}.Debug|x64.ActiveCfg = Debug|x64
{3A3D6626-C820-4C18-8C81-64811424F20E}.Debug|x64.Build.0 = Debug|x64
{3A3D6626-C820-4C18-8C81-64811424F20E}.Release|Any CPU.ActiveCfg = Release|Any CPU {3A3D6626-C820-4C18-8C81-64811424F20E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3A3D6626-C820-4C18-8C81-64811424F20E}.Release|Any CPU.Build.0 = Release|Any CPU {3A3D6626-C820-4C18-8C81-64811424F20E}.Release|Any CPU.Build.0 = Release|Any CPU
{3A3D6626-C820-4C18-8C81-64811424F20E}.Release|x64.ActiveCfg = Release|x64
{3A3D6626-C820-4C18-8C81-64811424F20E}.Release|x64.Build.0 = Release|x64
{3067889D-8A50-40D6-9CD5-23AA8EA96F26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3067889D-8A50-40D6-9CD5-23AA8EA96F26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3067889D-8A50-40D6-9CD5-23AA8EA96F26}.Debug|Any CPU.Build.0 = Debug|Any CPU {3067889D-8A50-40D6-9CD5-23AA8EA96F26}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3067889D-8A50-40D6-9CD5-23AA8EA96F26}.Debug|x64.ActiveCfg = Debug|x64
{3067889D-8A50-40D6-9CD5-23AA8EA96F26}.Debug|x64.Build.0 = Debug|x64
{3067889D-8A50-40D6-9CD5-23AA8EA96F26}.Release|Any CPU.ActiveCfg = Release|Any CPU {3067889D-8A50-40D6-9CD5-23AA8EA96F26}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3067889D-8A50-40D6-9CD5-23AA8EA96F26}.Release|Any CPU.Build.0 = Release|Any CPU {3067889D-8A50-40D6-9CD5-23AA8EA96F26}.Release|Any CPU.Build.0 = Release|Any CPU
{3067889D-8A50-40D6-9CD5-23AA8EA96F26}.Release|x64.ActiveCfg = Release|x64
{3067889D-8A50-40D6-9CD5-23AA8EA96F26}.Release|x64.Build.0 = Release|x64
{0FFA9D2F-41C6-443C-99B7-665702CF548F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0FFA9D2F-41C6-443C-99B7-665702CF548F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0FFA9D2F-41C6-443C-99B7-665702CF548F}.Debug|Any CPU.Build.0 = Debug|Any CPU {0FFA9D2F-41C6-443C-99B7-665702CF548F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0FFA9D2F-41C6-443C-99B7-665702CF548F}.Debug|x64.ActiveCfg = Debug|x64
{0FFA9D2F-41C6-443C-99B7-665702CF548F}.Debug|x64.Build.0 = Debug|x64
{0FFA9D2F-41C6-443C-99B7-665702CF548F}.Release|Any CPU.ActiveCfg = Release|Any CPU {0FFA9D2F-41C6-443C-99B7-665702CF548F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0FFA9D2F-41C6-443C-99B7-665702CF548F}.Release|Any CPU.Build.0 = Release|Any CPU {0FFA9D2F-41C6-443C-99B7-665702CF548F}.Release|Any CPU.Build.0 = Release|Any CPU
{0FFA9D2F-41C6-443C-99B7-665702CF548F}.Release|x64.ActiveCfg = Release|x64
{0FFA9D2F-41C6-443C-99B7-665702CF548F}.Release|x64.Build.0 = Release|x64
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F350E848-7622-48E1-87DC-4C2B1596122B}
EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
GlobalSection(Performance) = preSolution GlobalSection(Performance) = preSolution
HasPerformanceSessions = true HasPerformanceSessions = true
EndGlobalSection EndGlobalSection

View File

@ -32,6 +32,26 @@
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />

View File

@ -34,24 +34,56 @@ function allyGlobal.onDespawn(ally)
end end
--tryAggro serves the same purpose for now, keeping this around just in case
function allyGlobal.HelpPlayers(ally, contentGroupCharas, pickRandomTarget) function allyGlobal.HelpPlayers(ally, contentGroupCharas, pickRandomTarget)
if contentGroupCharas then if contentGroupCharas and not ally.IsEngaged() then
print("assssss") for chara in contentGroupCharas do
if chara then if chara then
-- probably a player, or another ally -- probably a player, or another ally
-- todo: queue support actions, heal, try pull hate off player etc -- todo: queue support actions, heal, try pull hate off player etc
if chara:IsPlayer() then if chara:IsPlayer() then
-- do stuff -- do stuff
if not ally:IsEngaged() then if not ally.IsEngaged() then
if chara:IsEngaged() then if chara.IsEngaged() then
print("ass") allyGlobal.EngageTarget(ally, chara.target, nil);
allyGlobal.EngageTarget(ally, chara.target, nil) break;
return true
end end
end end
elseif chara:IsMonster() and chara:IsEngaged() then elseif chara.IsMonster() and chara.IsEngaged() then
allyGlobal.EngageTarget(ally, chara, nil) if not ally.IsEngaged() then
return true allyGlobal.EngageTarget(ally, chara, nil);
break;
end
end
end
end
end
end
--Iterate over characters in contentGroup, if a player is in combat, assist them.
function allyGlobal.tryAggro(ally, contentGroupCharas)
local count = 0;
if contentGroupCharas and not ally.IsEngaged() then
for i = 0, #contentGroupCharas - 1 do
if contentGroupCharas[i] and ally then
if contentGroupCharas[i].IsPlayer() then
-- probably a player, or another ally
-- todo: queue support actions, heal, try pull hate off player etc
if contentGroupCharas[i].target then
if ally.aiContainer:GetTargetFind():CanTarget(contentGroupCharas[i].target) and contentGroupCharas[i].target.IsMonster() and contentGroupCharas[i].target.hateContainer:HasHateForTarget(contentGroupCharas[i]) then
-- do stuff
allyGlobal.EngageTarget(ally, contentGroupCharas[i].target, nil);
break;
end
end
--[[
elseif contentGroupCharas[i].IsMonster() and contentGroupCharas[i].IsEngaged() then
if not ally.IsEngaged() then
print("Engaging monster that is engaged");
allyGlobal.EngageTarget(ally, contentGroupCharas[i], nil);
break;
end]]
end end
end end
end end
@ -71,12 +103,13 @@ function allyGlobal.EngageTarget(ally, target, contentGroupCharas)
for chara in contentGroupCharas do for chara in contentGroupCharas do
if chara.IsMonster() then if chara.IsMonster() then
if chara.allegiance ~= ally.allegiance then if chara.allegiance ~= ally.allegiance then
ally:Engage(chara) ally.Engage(chara)
break;
end end
end end
end end
elseif target then elseif target then
ally:Engage(target) ally.Engage(target)
ally.hateContainer:AddBaseHate(target); ally.hateContainer.AddBaseHate(target);
end end
end end

View File

@ -152,8 +152,11 @@ function onTrigger(player, argc, skillName, level)
--local x, y, z = player.GetPos(); --local x, y, z = player.GetPos();
for i = 1, 1 do for i = 1, 1 do
local actor = player.GetZone().SpawnActor(2207303, 'ass', x, y, z, rot, 0, 0, true ); local actor = player.GetZone().SpawnActor(2104001, 'ass', x, y, z, rot, 0, 0, true );
if player.currentContentGroup then
player.currentContentGroup:AddMember(actor.actorId)
end
--actor.FollowTarget(player, 3.2); --actor.FollowTarget(player, 3.2);
end; end;
return; return;

View File

@ -20,8 +20,5 @@ function onMagicFinish(caster, target, spell, action)
-- action.effectId = bit32.bxor(0x8000000, spell.effectAnimation, 15636); -- action.effectId = bit32.bxor(0x8000000, spell.effectAnimation, 15636);
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; return damage;
end; end;

View File

@ -0,0 +1,21 @@
require("magic");
function onMagicPrepare(caster, target, spell)
return 0;
end;
function onMagicStart(caster, target, spell)
return 0;
end;
function onMagicFinish(caster, target, spell, action)
local damage = math.random(10, 100);
action.worldMasterTextId = 0x765D;
-- todo: populate a global script with statuses and modifiers
-- magic.HandleAttackMagic(caster, target, spell, action)
action.effectId = bit32.bxor(0x8000000, spell.effectAnimation, 15636);
return damage;
end;

View File

@ -0,0 +1,24 @@
require("global");
require("magic");
function onMagicPrepare(caster, target, spell)
return 0;
end;
function onMagicStart(caster, target, spell)
return 0;
end;
function onMagicFinish(caster, target, spell, action)
local damage = math.random(1000, 2500);
-- todo: populate a global script with statuses and modifiers
action.worldMasterTextId = 0x765D;
-- todo: populate a global script with statuses and modifiers
-- magic.HandleAttackMagic(caster, target, spell, action)
-- action.effectId = bit32.bxor(0x8000000, spell.effectAnimation, 15636);
action.effectId = bit32.bxor(0x8000000, spell.effectAnimation, 15636);
return damage;
end;

View File

@ -0,0 +1,24 @@
require("global");
require("magic");
function onMagicPrepare(caster, target, spell)
return 0;
end;
function onMagicStart(caster, target, spell)
return 0;
end;
function onMagicFinish(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.HandleAttackMagic(caster, target, spell, action)
-- action.effectId = bit32.bxor(0x8000000, spell.effectAnimation, 15636);
action.effectId = bit32.bxor(0x8000000, spell.effectAnimation, 15636);
return damage;
end;

View File

@ -0,0 +1,24 @@
require("global");
require("magic");
function onMagicPrepare(caster, target, spell)
return 0;
end;
function onMagicStart(caster, target, spell)
return 0;
end;
function onMagicFinish(caster, target, spell, action)
local damage = math.random(1000, 2500);
-- todo: populate a global script with statuses and modifiers
action.worldMasterTextId = 0x765D;
-- todo: populate a global script with statuses and modifiers
-- magic.HandleAttackMagic(caster, target, spell, action)
-- action.effectId = bit32.bxor(0x8000000, spell.effectAnimation, 15636);
action.effectId = bit32.bxor(0x8000000, spell.effectAnimation, 15636);
return damage;
end;

View File

@ -0,0 +1,27 @@
require("global");
require("magic");
function onMagicPrepare(caster, target, spell)
return 0;
end;
function onMagicStart(caster, target, spell)
return 0;
end;
function onMagicFinish(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.HandleAttackMagic(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;

View File

@ -0,0 +1,24 @@
require("global");
require("magic");
function onMagicPrepare(caster, target, spell)
return 0;
end;
function onMagicStart(caster, target, spell)
return 0;
end;
function onMagicFinish(caster, target, spell, action)
local damage = math.random(1000, 2500);
-- todo: populate a global script with statuses and modifiers
action.worldMasterTextId = 0x765D;
-- todo: populate a global script with statuses and modifiers
-- magic.HandleAttackMagic(caster, target, spell, action)
-- action.effectId = bit32.bxor(0x8000000, spell.effectAnimation, 15636);
action.effectId = bit32.bxor(0x8000000, spell.effectAnimation, 15636);
return damage;
end;

View File

@ -0,0 +1,24 @@
require("global");
require("magic");
function onMagicPrepare(caster, target, spell)
return 0;
end;
function onMagicStart(caster, target, spell)
return 0;
end;
function onMagicFinish(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.HandleAttackMagic(caster, target, spell, action)
-- action.effectId = bit32.bxor(0x8000000, spell.effectAnimation, 15636);
action.effectId = bit32.bxor(0x8000000, spell.effectAnimation, 15636);
return damage;
end;

View File

@ -0,0 +1,24 @@
require("global");
require("magic");
function onMagicPrepare(caster, target, spell)
return 0;
end;
function onMagicStart(caster, target, spell)
return 0;
end;
function onMagicFinish(caster, target, spell, action)
local damage = math.random(1000, 2500);
-- todo: populate a global script with statuses and modifiers
action.worldMasterTextId = 0x765D;
-- todo: populate a global script with statuses and modifiers
-- magic.HandleAttackMagic(caster, target, spell, action)
-- action.effectId = bit32.bxor(0x8000000, spell.effectAnimation, 15636);
action.effectId = bit32.bxor(0x8000000, spell.effectAnimation, 15636);
return damage;
end;

View File

@ -0,0 +1,21 @@
require("magic");
function onMagicPrepare(caster, target, spell)
return 0;
end;
function onMagicStart(caster, target, spell)
return 0;
end;
function onMagicFinish(caster, target, spell, action)
local damage = math.random(10, 100);
action.worldMasterTextId = 0x765D;
-- todo: populate a global script with statuses and modifiers
-- magic.HandleAttackMagic(caster, target, spell, action)
action.effectId = bit32.bxor(0x8000000, spell.effectAnimation, 15636);
return damage;
end;

View File

@ -0,0 +1,21 @@
require("magic");
function onMagicPrepare(caster, target, spell)
return 0;
end;
function onMagicStart(caster, target, spell)
return 0;
end;
function onMagicFinish(caster, target, spell, action)
local damage = math.random(10, 100);
action.worldMasterTextId = 0x765D;
-- todo: populate a global script with statuses and modifiers
-- magic.HandleAttackMagic(caster, target, spell, action)
action.effectId = bit32.bxor(0x8000000, spell.effectAnimation, 15636);
return damage;
end;

View File

@ -17,8 +17,5 @@ function onMagicFinish(caster, target, spell, action)
-- magic.HandleAttackMagic(caster, target, spell, action) -- magic.HandleAttackMagic(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; return damage;
end; end;

View File

@ -0,0 +1,26 @@
require("global");
function onSkillPrepare(caster, target, skill)
return 0;
end;
function onSkillStart(caster, target, skill)
return 0;
end;
function onSkillFinish(caster, target, skill, action)
local damage = math.random(0, 0);
-- todo: populate a global script with statuses and modifiers
action.worldMasterTextId = 0x765D;
-- todo: populate a global script with statuses and modifiers
-- magic.HandleAttackMagic(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;

View File

@ -11,12 +11,12 @@ function onCreate(starterPlayer, contentArea, director)
--mob3 = contentArea:SpawnActor(2201407, "mob3", 375.125, 4.4, -703.591, -1.54); --mob3 = contentArea:SpawnActor(2201407, "mob3", 375.125, 4.4, -703.591, -1.54);
yda = GetWorldManager().SpawnBattleNpcById(6, contentArea); yda = GetWorldManager().SpawnBattleNpcById(6, contentArea);
papalymo = GetWorldManager().SpawnBattleNpcById(7, contentArea); papalymo = GetWorldManager().SpawnBattleNpcById(7, contentArea);
yda:ChangeState(2); --yda:ChangeState(2);
mob1 = GetWorldManager().SpawnBattleNpcById(3, contentArea); mob1 = GetWorldManager().SpawnBattleNpcById(3, contentArea);
mob2 = GetWorldManager().SpawnBattleNpcById(4, contentArea); mob2 = GetWorldManager().SpawnBattleNpcById(4, contentArea);
mob3 = GetWorldManager().SpawnBattleNpcById(5, contentArea); mob3 = GetWorldManager().SpawnBattleNpcById(5, contentArea);
starterPlayer.currentParty.members:Add(yda.actorId); starterPlayer.currentParty:AddMember(papalymo.actorId);
starterPlayer.currentParty.members:Add(papalymo.actorId); starterPlayer.currentParty:AddMember(yda.actorId);
starterPlayer:SetMod(modifiersGlobal.MinimumHpLock, 1); starterPlayer:SetMod(modifiersGlobal.MinimumHpLock, 1);
@ -72,6 +72,47 @@ end
function onDestroy() function onDestroy()
end
--Iterating over allies using the for...in syntax throws an except and lags the server.
--This function probably isn't needed either way, it does the smae thing as TryAggro in ally
function onUpdate(tick, area)
if area then
local players = area:GetPlayers()
local mobs = area:GetMonsters()
local allies = area:GetAllies()
local resumeChecks = true
for player in players do
if player then
local exitLoop = false
if allies then
for i = 0, #allies - 1 do
if allies[i] then
if not allies[i]:IsEngaged() then
if player:IsEngaged() and player.target then
allies[i].neutral = false
allies[i].isAutoAttackEnabled = true
allies[i]:SetMod(modifiersGlobal.Speed, 8)
allyGlobal.EngageTarget(allies[i], player.target)
exitLoop = true
break
-- todo: support scripted paths
elseif allies[i]:GetSpeed() > 0 then
end
end
end
end
end
if exitLoop then
resumeChecks = false
break
end
end
end
if not resumeChecks then
return
end
end
end end

View File

@ -10,55 +10,71 @@ function init()
return "/Director/Quest/QuestDirectorMan0g001"; return "/Director/Quest/QuestDirectorMan0g001";
end end
--Should we be using this to spawn mobs and drop Simplecontent?
function onCreateContentArea(players, director, contentArea, contentGroup) function onCreateContentArea(players, director, contentArea, contentGroup)
director:StartContentGroup(); director:StartContentGroup();
end end
function onEventStarted(player, actor, triggerName) function onEventStarted(player, actor, triggerName)
man0g0Quest = player:GetQuest("Man0g0"); man0g0Quest = player:GetQuest("Man0g0");
player:SendMessage(0x20, "", "Starting");
startTutorialMode(player); startTutorialMode(player);
callClientFunction(player, "delegateEvent", player, man0g0Quest, "processTtrBtl001", nil, nil, nil); callClientFunction(player, "delegateEvent", player, man0g0Quest, "processTtrBtl001", nil, nil, nil);
player:EndEvent(); player:EndEvent();
player:SendMessage(0x20, "", "Waiting for player active");
waitForSignal("playerActive"); waitForSignal("playerActive");
player:SendMessage(0x20, "", "player active");
wait(1); --If this isn't here, the scripts bugs out. TODO: Find a better alternative. wait(1); --If this isn't here, the scripts bugs out. TODO: Find a better alternative.
kickEventContinue(player, actor, "noticeEvent", "noticeEvent"); kickEventContinue(player, actor, "noticeEvent", "noticeEvent");
callClientFunction(player, "delegateEvent", player, man0g0Quest, "processTtrBtl002", nil, nil, nil); callClientFunction(player, "delegateEvent", player, man0g0Quest, "processTtrBtl002", nil, nil, nil);
player:SendMessage(0x20, "", "processTtrBtl002 called");
player:EndEvent(); player:EndEvent();
--Combat portion of tutorial
if player:IsDiscipleOfWar() then
waitForSignal("playerAttack"); waitForSignal("playerAttack");
closeTutorialWidget(player); closeTutorialWidget(player);
showTutorialSuccessWidget(player, 9055); --Open TutorialSuccessWidget for attacking enemy showTutorialSuccessWidget(player, 9055); --Open TutorialSuccessWidget for attacking enemy
wait(3);
openTutorialWidget(player, CONTROLLER_KEYBOARD, TUTORIAL_TP); openTutorialWidget(player, CONTROLLER_KEYBOARD, TUTORIAL_TP);
waitForSignal("tpOver1000"); waitForSignal("tpOver1000");
closeTutorialWidget(player); closeTutorialWidget(player);
openTutorialWidget(player, CONTROLLER_KEYBOARD, TUTORIAL_WEAPONSKILLS); openTutorialWidget(player, CONTROLLER_KEYBOARD, TUTORIAL_WEAPONSKILLS);
waitForSignal("weaponskillUsed");
if player:IsDiscipleOfWar() then
waitForSignal("weaponskillUsed"); --Should be wait for weaponskillUsed signal
elseif player:IsDiscipleOfMagic() then
waitForSignal("spellUsed")
elseif player:IsDiscipleOfHand() then
waitForSignal("abilityUsed")
elseif player:IsDiscipleOfLand() then
waitForSignal("abilityUsed")
end
closeTutorialWidget(player); closeTutorialWidget(player);
showTutorialSuccessWidget(player, 9065); --Open TutorialSuccessWidget for weapon skill showTutorialSuccessWidget(player, 9065); --Open TutorialSuccessWidget for weapon skill
elseif player:IsDiscipleOfMagic() then
openTutorialWidget(player, CONTROLLER_KEYBOARD, TUTORIAL_CASTING);
waitForSignal("spellUsed");
closeTutorialWidget(player);
elseif player:IsDiscipleOfHand() then
waitForSignal("abilityUsed");
elseif player:IsDiscipleOfLand() then
waitForSignal("abilityUsed");
end
waitForSignal("mobkill"); --Should be wait for mobkill --Currently this requires the player to pass all the other signals first, need a way for signals to work out of order
waitForSignal("mobkill");
waitForSignal("mobkill"); waitForSignal("mobkill");
waitForSignal("mobkill"); waitForSignal("mobkill");
worldMaster = GetWorldMaster(); worldMaster = GetWorldMaster();
wait(5);--Debug waits, get rid of these later
player:Disengage(0x0000);
wait(5);
man0g0Quest:NextPhase(10);
wait(5);
--This doesn't work
player:RemoveFromCurrentPartyAndCleanup();
player:SendDataPacket("attention", worldMaster, "", 51073, 2); player:SendDataPacket("attention", worldMaster, "", 51073, 2);
wait(7); wait(5);
player:ChangeMusic(7); player:ChangeMusic(7);
player:ChangeState(0); wait(5);
kickEventContinue(player, actor, "noticeEvent", "noticeEvent"); kickEventContinue(player, actor, "noticeEvent", "noticeEvent");
wait(5);
callClientFunction(player, "delegateEvent", player, man0g0Quest, "processEvent020_1", nil, nil, nil); callClientFunction(player, "delegateEvent", player, man0g0Quest, "processEvent020_1", nil, nil, nil);
wait(5);
player:GetZone():ContentFinished(); player:GetZone():ContentFinished();
player:EndEvent(); --player:EndEvent();
GetWorldManager():DoZoneChange(player, 155, "PrivateAreaMasterPast", 1, 15, 175.38, -1.21, -1156.51, -2.1); --GetWorldManager():DoZoneChange(player, 155, "PrivateAreaMasterPast", 1, 15, 175.38, -1.21, -1156.51, -2.1);
--[[ --[[
IF DoW: IF DoW:
OpenWidget (TP) OpenWidget (TP)
@ -72,10 +88,9 @@ function onEventStarted(player, actor, triggerName)
OpenWidget (DEFEAT ENEMY) OpenWidget (DEFEAT ENEMY)
]] ]]
--man0g0Quest:NextPhase(10); player:EndEvent();
--player:EndEvent(); wait(5);
GetWorldManager():DoZoneChange(player, 155, "PrivateAreaMasterPast", 1, 15, 175.38, -1.21, -1156.51, -2.1);
--GetWorldManager():DoZoneChange(player, 155, "PrivateAreaMasterPast", 1, 15, 175.38, -1.21, -1156.51, -2.1);
end end

View File

@ -74,4 +74,6 @@ mobModifiersGlobal =
AbilityScript = 21, -- call my script's onAbility whenever i finish using an ability 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 CallForHelp = 22, -- actor with this id outside of target's party with this can attack me
FreeForAll = 23, -- any actor 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
} }

View File

@ -7,5 +7,22 @@ function onSpawn(ally)
ally:SetHP(ally:GetMaxHP()) ally:SetHP(ally:GetMaxHP())
ally.isAutoAttackEnabled = false; ally.isAutoAttackEnabled = false;
ally.neutral = false ally.neutral = false
ally:SetMod(modifiersGlobal.Speed, 0) end
function onCombatTick(ally, target, tick, contentGroupCharas)
allyGlobal.onCombatTick(ally, target, tick, contentGroupCharas);
end
function onRoam(ally, contentGroupCharas)
ally.detectionType = 0xFF
ally.isMovingToSpawn = false
ally.neutral = false
ally.animationId = 0
allyGlobal.onCombatTick(ally, nil, nil, contentGroupCharas)
end
function tryAggro(ally, contentGroupCharas)
allyGlobal.tryAggro(ally, contentGroupCharas)
end end

View File

@ -8,3 +8,19 @@ function onSpawn(ally)
ally.neutral = false ally.neutral = false
ally:SetMod(modifiersGlobal.Speed, 0) ally:SetMod(modifiersGlobal.Speed, 0)
end end
function onCombatTick(ally, target, tick, contentGroupCharas)
allyGlobal.onCombatTick(ally, target, tick, contentGroupCharas)
end
function tryAggro(ally, contentGroupCharas)
allyGlobal.tryAggro(ally, contentGroupCharas)
end
function onRoam(ally, contentGroupCharas)
ally.detectionType = 0xFF
ally.isMovingToSpawn = false
ally.neutral = false
ally.animationId = 0
--allyGlobal.onCombatTick(ally, contentGroupCharas)
end

View File

@ -7,10 +7,9 @@ end
function onEventStarted(player, npc, triggerName) function onEventStarted(player, npc, triggerName)
man0g0Quest = player:GetQuest("Man0g0"); man0g0Quest = player:GetQuest("Man0g0");
print("hi"); print("Got Quest Man0g0");
if (man0g0Quest ~= nil) then if (man0g0Quest ~= nil) then
print("Man0g0Quest is not nil");
print("hi2");
if (triggerName == "pushDefault") then if (triggerName == "pushDefault") then
callClientFunction(player, "delegateEvent", player, man0g0Quest, "processTtrNomal002", nil, nil, nil); callClientFunction(player, "delegateEvent", player, man0g0Quest, "processTtrNomal002", nil, nil, nil);
elseif (triggerName == "talkDefault") then elseif (triggerName == "talkDefault") then
@ -23,8 +22,8 @@ function onEventStarted(player, npc, triggerName)
man0g0Quest:SaveData(); man0g0Quest:SaveData();
player:GetDirector("OpeningDirector"):onTalkEvent(player, npc); player:GetDirector("OpeningDirector"):onTalkEvent(player, npc);
--Was she talked to after papalymo? --Was she talked to after papalymo?
print("hi3");
else else
print("Making content area");
if (man0g0Quest:GetQuestFlag(MAN0G0_FLAG_MINITUT_DONE1) == true) then if (man0g0Quest:GetQuestFlag(MAN0G0_FLAG_MINITUT_DONE1) == true) then
player:EndEvent(); player:EndEvent();
@ -43,8 +42,9 @@ function onEventStarted(player, npc, triggerName)
player:KickEvent(director, "noticeEvent", true); player:KickEvent(director, "noticeEvent", true);
player:SetLoginDirector(director); player:SetLoginDirector(director);
print("hi5"); print("Content area and director made");
GetWorldManager():DoZoneChangeContent(player, contentArea, 362.4087, 4, -703.8168, 1.5419, 16); GetWorldManager():DoZoneChangeContent(player, contentArea, 362.4087, 4, -703.8168, 1.5419, 16);
print("Zone Change");
return; return;
else else
callClientFunction(player, "delegateEvent", player, man0g0Quest, "processEvent000_1", nil, nil, nil); callClientFunction(player, "delegateEvent", player, man0g0Quest, "processEvent000_1", nil, nil, nil);