Skip to content

Commit

Permalink
Merge pull request #510 from RyanYappert/feat/training-room
Browse files Browse the repository at this point in the history
Feature: Implement traning (sic) room.
  • Loading branch information
RyanYappert authored Sep 2, 2024
2 parents e67e87b + 1644f59 commit 8c8ab0e
Show file tree
Hide file tree
Showing 15 changed files with 289 additions and 112 deletions.
2 changes: 2 additions & 0 deletions Arrowgene.Ddon.GameServer/DdonGameServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,8 @@ private void LoadPacketHandler()
AddHandler(new InstanceCharacterStartBadStatusHandler(this));
AddHandler(new InstancePlTouchOmHandler(this));
AddHandler(new InstanceGetOmInstantKeyValueAllHandler(this));
AddHandler(new InstanceTraningRoomGetEnemyListHandler(this));
AddHandler(new InstanceTraningRoomSetEnemyHandler(this));

AddHandler(new ItemConsumeStorageItemHandler(this));
AddHandler(new ItemGetStorageItemListHandler(this));
Expand Down
13 changes: 13 additions & 0 deletions Arrowgene.Ddon.GameServer/Handler/InstanceEnemyKillHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ public class InstanceEnemyKillHandler : StructurePacketHandler<GameClient, C2SIn

private readonly DdonGameServer _gameServer;

private readonly HashSet<uint> _ignoreKillsInStageIds = new HashSet<uint>()
{
349, //White Dragon Temple, Training Room
};

public InstanceEnemyKillHandler(DdonGameServer server) : base(server)
{
_gameServer = server;
Expand All @@ -32,6 +37,14 @@ public override void Handle(GameClient client, StructurePacket<C2SInstanceEnemyK
StageId stageId = StageId.FromStageLayoutId(layoutId);
ushort subGroupId = client.Party.InstanceEnemyManager.GetInstanceSubgroupId(stageId);

// The training room uses special handling to produce enemies that don't exist in the QuestState or InstanceEnemyManager.
// Return an empty response here to not break the rest of the handling.
if (_ignoreKillsInStageIds.Contains(stageId.Id))
{
client.Send(new S2CInstanceEnemyKillRes());
return;
}

Quest quest = null;
bool IsQuestControlled = false;
foreach (var questId in client.Party.QuestState.StageQuests(stageId))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using Arrowgene.Ddon.Server;
using Arrowgene.Ddon.Shared.Entity.PacketStructure;
using Arrowgene.Ddon.Shared.Entity.Structure;
using Arrowgene.Logging;
using System.Collections.Generic;

namespace Arrowgene.Ddon.GameServer.Handler
{
public class InstanceTraningRoomGetEnemyListHandler : GameRequestPacketHandler<C2SInstanceTraningRoomGetEnemyListReq, S2CInstanceTraningRoomGetEnemyListRes>
{
private static readonly ServerLogger Logger = LogProvider.Logger<ServerLogger>(typeof(QuestGetQuestCompletedListHandler));


public InstanceTraningRoomGetEnemyListHandler(DdonGameServer server) : base(server)
{
}

public override S2CInstanceTraningRoomGetEnemyListRes Handle(GameClient client, C2SInstanceTraningRoomGetEnemyListReq request)
{
// These OptionIds are intepreted in InstanceTraningRoomSetEnemyHandler.
return new S2CInstanceTraningRoomGetEnemyListRes()
{
MaxLv = 100,
InfoList = new List<CDataTraningRoomEnemyHeader>()
{
new CDataTraningRoomEnemyHeader()
{
OptionId = 1,
Name = "Orc Soldiers"
},
new CDataTraningRoomEnemyHeader()
{
OptionId = 2,
Name = "Cyclops"
},
new CDataTraningRoomEnemyHeader()
{
OptionId = 3,
Name = "Ogre"
},
new CDataTraningRoomEnemyHeader()
{
OptionId = 4,
Name = "Training Dummy Zuhl"
},
}
};
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
using Arrowgene.Ddon.Shared.Entity.PacketStructure;
using Arrowgene.Ddon.Shared.Entity.Structure;
using Arrowgene.Ddon.Shared.Network;
using System.Threading.Tasks;

namespace Arrowgene.Ddon.GameServer.Handler
{
public class InstanceTraningRoomSetEnemyHandler : GameStructurePacketHandler<C2SInstanceTraningRoomSetEnemyReq>
{
public InstanceTraningRoomSetEnemyHandler(DdonGameServer server) : base(server)
{
}

private static readonly CDataStageLayoutId TrainingRoomLayout = new CDataStageLayoutId(349, 0, 1);
private static readonly int RepopDelay = 2000; // ms

public override void Handle(GameClient client, StructurePacket<C2SInstanceTraningRoomSetEnemyReq> packet)
{

// TODO: Enemies that share the same positionIndex sometimes spawn with the wrong HP.
// To avoid this in the meantime, each enemy must have its own unique positionIndex.
// But the training room layout only has 6 (0-5) indices, so you can only have six different spawns.

client.Send(new S2CInstanceTraningRoomSetEnemyRes());

client.Party.SendToAll(new S2CInstanceEnemyGroupResetNtc()
{
LayoutId = TrainingRoomLayout
});

ushort level = (ushort)packet.Structure.Lv;

Task.Delay(RepopDelay).ContinueWith(_ => {
switch (packet.Structure.OptionId)
{
case 1: // Two orc soldiers
client.Party.SendToAll(new S2CInstanceEnemyRepopNtc()
{
LayoutId = TrainingRoomLayout,
EnemyData = new CDataLayoutEnemyData()
{
PositionIndex = 0,
EnemyInfo = new CDataStageLayoutEnemyPresetEnemyInfoClient()
{
EnemyId = 0x15800,
NamedEnemyParamsId = 47, // Training <name>
Lv = level,
RepopCount = 10,
Scale = 100,
IsBossGauge = true,
}
},
WaitSecond = 0,
});
client.Party.SendToAll(new S2CInstanceEnemyRepopNtc()
{
LayoutId = TrainingRoomLayout,
EnemyData = new CDataLayoutEnemyData()
{
PositionIndex = 1,
EnemyInfo = new CDataStageLayoutEnemyPresetEnemyInfoClient()
{
EnemyId = 0x15800,
NamedEnemyParamsId = 47, // Training <name>
Lv = level,
RepopCount = 10,
Scale = 100,
IsBossGauge = true,
}
},
WaitSecond = 0,
});
break;
case 2: // Cyclops
client.Party.SendToAll(new S2CInstanceEnemyRepopNtc()
{
LayoutId = TrainingRoomLayout,
EnemyData = new CDataLayoutEnemyData()
{
PositionIndex = 2,
EnemyInfo = new CDataStageLayoutEnemyPresetEnemyInfoClient()
{
EnemyId = 0x15000,
NamedEnemyParamsId = 47, // Training <name>
Lv = level,
RepopCount = 10,
Scale = 100,
IsBossGauge = true,
}
},
WaitSecond = 0,
});
break;
case 3: //Ogre
client.Party.SendToAll(new S2CInstanceEnemyRepopNtc()
{
LayoutId = TrainingRoomLayout,
EnemyData = new CDataLayoutEnemyData()
{
PositionIndex = 3,
EnemyInfo = new CDataStageLayoutEnemyPresetEnemyInfoClient()
{
EnemyId = 0x15500,
NamedEnemyParamsId = 47, // Training <name>
Lv = level,
RepopCount = 10,
Scale = 100,
IsBossGauge = true,
}
},
WaitSecond = 0,
});
break;
case 4: //Passive Zuhl
client.Party.SendToAll(new S2CInstanceEnemyRepopNtc()
{
LayoutId = TrainingRoomLayout,
EnemyData = new CDataLayoutEnemyData()
{
PositionIndex = 4,
EnemyInfo = new CDataStageLayoutEnemyPresetEnemyInfoClient()
{
EnemyId = 0x100101,
NamedEnemyParamsId = 722, // Practice <name>, has extra HP.
Lv = level,
RepopCount = 10,
Scale = 75,
IsBossGauge = true,
}
},
WaitSecond = 0,
});
break;
}
});
}
}
}
8 changes: 4 additions & 4 deletions Arrowgene.Ddon.Shared/Entity/EntitySerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -649,8 +649,8 @@ static EntitySerializer()
Create(new C2SSetCommunicationShortcutReq.Serializer());
Create(new C2SStageAreaChangeReq.Serializer());
Create(new C2SStageGetStageListReq.Serializer());
Create(new C2STraningRoomGetEnemyListReq.Serializer());
Create(new C2STrainingRoomSetEnemyReq.Serializer());
Create(new C2SInstanceTraningRoomGetEnemyListReq.Serializer());
Create(new C2SInstanceTraningRoomSetEnemyReq.Serializer());
Create(new C2SWarpAreaWarpReq.Serializer());
Create(new C2SWarpGetFavoriteWarpPointListReq.Serializer());
Create(new C2SWarpGetReleaseWarpPointListReq.Serializer());
Expand Down Expand Up @@ -1113,8 +1113,8 @@ static EntitySerializer()
Create(new S2CShopGetShopGoodsListRes.Serializer());
Create(new S2CStageAreaChangeRes.Serializer());
Create(new S2CStageGetStageListRes.Serializer());
Create(new S2CTraningRoomGetEnemyListRes.Serializer());
Create(new S2CTraningRoomSetEnemyRes.Serializer());
Create(new S2CInstanceTraningRoomGetEnemyListRes.Serializer());
Create(new S2CInstanceTraningRoomSetEnemyRes.Serializer());
Create(new S2CUserListJoinNtc.Serializer());
Create(new S2CUserListLeaveNtc.Serializer());
Create(new S2CWarpAreaWarpRes.Serializer());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Arrowgene.Buffers;
using Arrowgene.Ddon.Shared.Network;

namespace Arrowgene.Ddon.Shared.Entity.PacketStructure
{
public class C2SInstanceTraningRoomGetEnemyListReq : IPacketStructure
{
public PacketId Id => PacketId.C2S_INSTANCE_TRANING_ROOM_GET_ENEMY_LIST_REQ;
public class Serializer : PacketEntitySerializer<C2SInstanceTraningRoomGetEnemyListReq>
{

public override void Write(IBuffer buffer, C2SInstanceTraningRoomGetEnemyListReq obj)
{
}

public override C2SInstanceTraningRoomGetEnemyListReq Read(IBuffer buffer)
{
return new C2SInstanceTraningRoomGetEnemyListReq();
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using Arrowgene.Buffers;
using Arrowgene.Ddon.Shared.Network;

namespace Arrowgene.Ddon.Shared.Entity.PacketStructure
{
public class C2SInstanceTraningRoomSetEnemyReq : IPacketStructure
{
public PacketId Id => PacketId.C2S_INSTANCE_TRANING_ROOM_SET_ENEMY_REQ;

/// <summary>
/// Value returned from the TraningRoomGetEnemyList dialog.
/// </summary>
public uint OptionId { get; set; }
public uint Lv { get; set; }

public C2SInstanceTraningRoomSetEnemyReq()
{
OptionId = 0;
Lv = 0;
}

public class Serializer : PacketEntitySerializer<C2SInstanceTraningRoomSetEnemyReq>
{

public override void Write(IBuffer buffer, C2SInstanceTraningRoomSetEnemyReq obj)
{
WriteUInt32(buffer, obj.OptionId);
WriteUInt32(buffer, obj.Lv);
}

public override C2SInstanceTraningRoomSetEnemyReq Read(IBuffer buffer)
{
C2SInstanceTraningRoomSetEnemyReq obj = new C2SInstanceTraningRoomSetEnemyReq();
obj.OptionId = ReadUInt32(buffer);
obj.Lv = ReadUInt32(buffer);
return obj;
}
}
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using Arrowgene.Buffers;
using Arrowgene.Ddon.Shared.Entity.Structure;
using Arrowgene.Ddon.Shared.Network;
using System;

namespace Arrowgene.Ddon.Shared.Entity.PacketStructure
{
Expand All @@ -10,7 +9,7 @@ public class S2CInstanceEnemyDieNtc : IPacketStructure
public PacketId Id => PacketId.S2C_INSTANCE_ENEMY_DIE_NTC;

public CDataStageLayoutId LayoutId { get; set; }
public UInt32 SetId { get; set; }
public uint SetId { get; set; }

public class Serializer : PacketEntitySerializer<S2CInstanceEnemyDieNtc>
{
Expand Down
Loading

0 comments on commit 8c8ab0e

Please sign in to comment.