[Bug Fix] Remove possible Duel exploit. (#1911)

* [Duels] Cleanup duel response/request logic.

* Fixes and function name cleanup.

* Patch file name changes.
This commit is contained in:
Kinglykrab 2022-01-02 22:06:31 -05:00 committed by GitHub
parent 9815f50efa
commit 645251992d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 89 additions and 46 deletions

View File

@ -129,8 +129,8 @@ N(OP_DisciplineTimer),
N(OP_DisciplineUpdate), N(OP_DisciplineUpdate),
N(OP_DiscordMerchantInventory), N(OP_DiscordMerchantInventory),
N(OP_DoGroupLeadershipAbility), N(OP_DoGroupLeadershipAbility),
N(OP_DuelResponse), N(OP_DuelDecline),
N(OP_DuelResponse2), N(OP_DuelAccept),
N(OP_DumpName), N(OP_DumpName),
N(OP_Dye), N(OP_Dye),
N(OP_DynamicWall), N(OP_DynamicWall),

View File

@ -115,8 +115,8 @@ IN(OP_GMTraining, GMTrainee_Struct);
IN(OP_GMEndTraining, GMTrainEnd_Struct); IN(OP_GMEndTraining, GMTrainEnd_Struct);
IN(OP_GMTrainSkill, GMSkillChange_Struct); IN(OP_GMTrainSkill, GMSkillChange_Struct);
IN(OP_RequestDuel, Duel_Struct); IN(OP_RequestDuel, Duel_Struct);
IN(OP_DuelResponse, DuelResponse_Struct); IN(OP_DuelDecline, DuelResponse_Struct);
IN(OP_DuelResponse2, Duel_Struct); IN(OP_DuelAccept, Duel_Struct);
IN(OP_SpawnAppearance, SpawnAppearance_Struct); IN(OP_SpawnAppearance, SpawnAppearance_Struct);
IN(OP_BazaarInspect, BazaarInspect_Struct); IN(OP_BazaarInspect, BazaarInspect_Struct);
IN(OP_Death, Death_Struct); IN(OP_Death, Death_Struct);

View File

@ -240,8 +240,8 @@ void load_opcode_names()
opcode_map[0x00a1] = "LiveOP_SaveOnZoneReq"; opcode_map[0x00a1] = "LiveOP_SaveOnZoneReq";
opcode_map[0x0185] = "LiveOP_Logout"; opcode_map[0x0185] = "LiveOP_Logout";
opcode_map[0x0298] = "LiveOP_RequestDuel"; opcode_map[0x0298] = "LiveOP_RequestDuel";
opcode_map[0x0a5d] = "LiveOP_DuelResponse"; opcode_map[0x0a5d] = "LiveOP_DuelDecline";
opcode_map[0x016e] = "LiveOP_DuelResponse2"; opcode_map[0x016e] = "LiveOP_DuelAccept";
opcode_map[0x007c] = "LiveOP_InstillDoubt"; opcode_map[0x007c] = "LiveOP_InstillDoubt";
opcode_map[0x00ac] = "LiveOP_SafeFallSuccess"; opcode_map[0x00ac] = "LiveOP_SafeFallSuccess";
opcode_map[0x02fb] = "LiveOP_DisciplineUpdate"; opcode_map[0x02fb] = "LiveOP_DisciplineUpdate";

View File

@ -307,8 +307,8 @@ OP_RecipeAutoCombine=0x0353
OP_TradeSkillCombine=0x0b40 OP_TradeSkillCombine=0x0b40
OP_RequestDuel=0x0000 OP_RequestDuel=0x0000
OP_DuelResponse=0x0000 OP_DuelDecline=0x0000
OP_DuelResponse2=0x0000 #when accepted OP_DuelAccept=0x0000 #when accepted
OP_RezzComplete=0x0000 #packet wrong on this OP_RezzComplete=0x0000 #packet wrong on this
OP_RezzRequest=0x0000 #packet wrong on this OP_RezzRequest=0x0000 #packet wrong on this

View File

@ -288,8 +288,8 @@ OP_YellForHelp=0x0017
OP_LoadSpellSet=0x38b4 OP_LoadSpellSet=0x38b4
OP_Bandolier=0x2b6f OP_Bandolier=0x2b6f
OP_PotionBelt=0x2d1b # Was 0x4d3b OP_PotionBelt=0x2d1b # Was 0x4d3b
OP_DuelResponse=0x0dee OP_DuelDecline=0x0dee
OP_DuelResponse2=0x5e04 OP_DuelAccept=0x5e04
OP_SaveOnZoneReq=0x36b1 OP_SaveOnZoneReq=0x36b1
OP_ReadBook=0x383c OP_ReadBook=0x383c
OP_Dye=0x62d8 OP_Dye=0x62d8

View File

@ -287,8 +287,8 @@ OP_YellForHelp=0x4e56
OP_LoadSpellSet=0x261d OP_LoadSpellSet=0x261d
OP_Bandolier=0x7677 OP_Bandolier=0x7677
OP_PotionBelt=0x1a3e OP_PotionBelt=0x1a3e
OP_DuelResponse=0x6a46 OP_DuelDecline=0x6a46
OP_DuelResponse2=0x68d3 OP_DuelAccept=0x68d3
OP_SaveOnZoneReq=0x600d OP_SaveOnZoneReq=0x600d
OP_ReadBook=0x72df OP_ReadBook=0x72df
OP_Dye=0x23b9 OP_Dye=0x23b9

View File

@ -281,7 +281,7 @@ OP_YellForHelp=0x6f79 # C
OP_LoadSpellSet=0x7113 # C OP_LoadSpellSet=0x7113 # C
OP_Bandolier=0x441c # C OP_Bandolier=0x441c # C
OP_PotionBelt=0x5db5 # C OP_PotionBelt=0x5db5 # C
OP_DuelResponse=0x1ebb # C OP_DuelDecline=0x1ebb # C
OP_SaveOnZoneReq=0x6eff # C OP_SaveOnZoneReq=0x6eff # C
OP_ReadBook=0x2444 # C OP_ReadBook=0x2444 # C
OP_Dye=0x3672 # C OP_Dye=0x3672 # C
@ -299,7 +299,7 @@ OP_DoGroupLeadershipAbility=0x540b # C
OP_GroupLeadershipAAUpdate=0x0c33 OP_GroupLeadershipAAUpdate=0x0c33
OP_DelegateAbility=0x0322 # C OP_DelegateAbility=0x0322 # C
OP_SetGroupTarget=0x521c # C OP_SetGroupTarget=0x521c # C
OP_DuelResponse2=0x52b5 # C OP_DuelAccept=0x52b5 # C
OP_Charm=0x7108 # C OP_Charm=0x7108 # C
OP_Stun=0x2a6d # C OP_Stun=0x2a6d # C
OP_SendFindableNPCs=0x5360 OP_SendFindableNPCs=0x5360

View File

@ -275,7 +275,7 @@ OP_YellForHelp=0x4F4A #Trevius 03/19/09
OP_LoadSpellSet=0x05B5 #Trevius 03/19/09 OP_LoadSpellSet=0x05B5 #Trevius 03/19/09
OP_Bandolier=0x3FD4 #Trevius 03/19/09 OP_Bandolier=0x3FD4 #Trevius 03/19/09
OP_PotionBelt=0x16F3 #Trevius 03/19/09 OP_PotionBelt=0x16F3 #Trevius 03/19/09
OP_DuelResponse=0x5E59 #Derision 2009 OP_DuelDecline=0x5E59 #Derision 2009
OP_SaveOnZoneReq=0x1103 #Trevius 03/20/09 OP_SaveOnZoneReq=0x1103 #Trevius 03/20/09
OP_ReadBook=0x424a #Xinu 03/19/09 OP_ReadBook=0x424a #Xinu 03/19/09
OP_Dye=0x3611 #Xinu 03/19/09 OP_Dye=0x3611 #Xinu 03/19/09
@ -292,7 +292,7 @@ OP_ClearRaidNPCMarks=0x56a9 #
OP_DoGroupLeadershipAbility=0x5a64 #Derision 2009 OP_DoGroupLeadershipAbility=0x5a64 #Derision 2009
OP_DelegateAbility=0x57e3 #Derision 2009 OP_DelegateAbility=0x57e3 #Derision 2009
OP_SetGroupTarget=0x1651 #Derision 2009 OP_SetGroupTarget=0x1651 #Derision 2009
OP_DuelResponse2=0x2A85 #Derision 2009 OP_DuelAccept=0x2A85 #Derision 2009
OP_Charm=0x2F32 #Derision 2009 OP_Charm=0x2F32 #Derision 2009
OP_Stun=0x55BF #Derision 2009 OP_Stun=0x55BF #Derision 2009
OP_FindPersonRequest=0x07F0 #Derision 2009 OP_FindPersonRequest=0x07F0 #Derision 2009

View File

@ -356,8 +356,8 @@ OP_RecipeAutoCombine=0x0353
OP_TradeSkillCombine=0x0b40 OP_TradeSkillCombine=0x0b40
OP_RequestDuel=0x28e1 OP_RequestDuel=0x28e1
OP_DuelResponse=0x3bad OP_DuelDecline=0x3bad
OP_DuelResponse2=0x1b09 #when accepted OP_DuelAccept=0x1b09 #when accepted
OP_RezzComplete=0x4b05 OP_RezzComplete=0x4b05
OP_RezzRequest=0x1035 OP_RezzRequest=0x1035

View File

@ -290,8 +290,8 @@ OP_YellForHelp=0x55a8 # C
OP_LoadSpellSet=0x6617 # C OP_LoadSpellSet=0x6617 # C
OP_Bandolier=0x510c # C OP_Bandolier=0x510c # C
OP_PotionBelt=0x0651 # C OP_PotionBelt=0x0651 # C
OP_DuelResponse=0x41a6 # C OP_DuelDecline=0x41a6 # C
OP_DuelResponse2=0x6d60 # C OP_DuelAccept=0x6d60 # C
OP_SaveOnZoneReq=0x2913 # C OP_SaveOnZoneReq=0x2913 # C
OP_ReadBook=0x465e # C OP_ReadBook=0x465e # C
OP_Dye=0x2137 # C OP_Dye=0x2137 # C

View File

@ -783,9 +783,9 @@ public:
void GMKill(); void GMKill();
inline bool IsMedding() const {return medding;} inline bool IsMedding() const {return medding;}
inline uint16 GetDuelTarget() const { return duel_target; } inline uint32 GetDuelTarget() const { return duel_target; }
inline bool IsDueling() const { return duelaccepted; } inline bool IsDueling() const { return duelaccepted; }
inline void SetDuelTarget(uint16 set_id) { duel_target=set_id; } inline void SetDuelTarget(uint32 set_id) { duel_target = set_id; }
inline void SetDueling(bool duel) { duelaccepted = duel; } inline void SetDueling(bool duel) { duelaccepted = duel; }
// use this one instead // use this one instead
void MemSpell(uint16 spell_id, int slot, bool update_client = true); void MemSpell(uint16 spell_id, int slot, bool update_client = true);

View File

@ -194,8 +194,8 @@ void MapOpcodes()
ConnectedOpcodes[OP_Disarm] = &Client::Handle_OP_Disarm; ConnectedOpcodes[OP_Disarm] = &Client::Handle_OP_Disarm;
ConnectedOpcodes[OP_DisarmTraps] = &Client::Handle_OP_DisarmTraps; ConnectedOpcodes[OP_DisarmTraps] = &Client::Handle_OP_DisarmTraps;
ConnectedOpcodes[OP_DoGroupLeadershipAbility] = &Client::Handle_OP_DoGroupLeadershipAbility; ConnectedOpcodes[OP_DoGroupLeadershipAbility] = &Client::Handle_OP_DoGroupLeadershipAbility;
ConnectedOpcodes[OP_DuelResponse] = &Client::Handle_OP_DuelResponse; ConnectedOpcodes[OP_DuelDecline] = &Client::Handle_OP_DuelDecline;
ConnectedOpcodes[OP_DuelResponse2] = &Client::Handle_OP_DuelResponse2; ConnectedOpcodes[OP_DuelAccept] = &Client::Handle_OP_DuelAccept;
ConnectedOpcodes[OP_DumpName] = &Client::Handle_OP_DumpName; ConnectedOpcodes[OP_DumpName] = &Client::Handle_OP_DumpName;
ConnectedOpcodes[OP_Dye] = &Client::Handle_OP_Dye; ConnectedOpcodes[OP_Dye] = &Client::Handle_OP_Dye;
ConnectedOpcodes[OP_DzAddPlayer] = &Client::Handle_OP_DzAddPlayer; ConnectedOpcodes[OP_DzAddPlayer] = &Client::Handle_OP_DzAddPlayer;
@ -5543,37 +5543,57 @@ void Client::Handle_OP_DoGroupLeadershipAbility(const EQApplicationPacket *app)
} }
} }
void Client::Handle_OP_DuelResponse(const EQApplicationPacket *app) void Client::Handle_OP_DuelDecline(const EQApplicationPacket *app)
{ {
if (app->size != sizeof(DuelResponse_Struct)) if (app->size != sizeof(DuelResponse_Struct)) {
return; return;
}
DuelResponse_Struct* ds = (DuelResponse_Struct*)app->pBuffer; DuelResponse_Struct* ds = (DuelResponse_Struct*)app->pBuffer;
if (!ds->target_id || !ds->entity_id) {
return;
}
Entity* entity = entity_list.GetID(ds->target_id); Entity* entity = entity_list.GetID(ds->target_id);
Entity* initiator = entity_list.GetID(ds->entity_id); Entity* initiator = entity_list.GetID(ds->entity_id);
if (!entity->IsClient() || !initiator->IsClient()) if (!entity->IsClient() || !initiator->IsClient()) {
return; return;
}
entity->CastToClient()->SetDuelTarget(0); entity->CastToClient()->SetDuelTarget(0);
entity->CastToClient()->SetDueling(false); entity->CastToClient()->SetDueling(false);
initiator->CastToClient()->SetDuelTarget(0); initiator->CastToClient()->SetDuelTarget(0);
initiator->CastToClient()->SetDueling(false); initiator->CastToClient()->SetDueling(false);
if (GetID() == initiator->GetID()) if (GetID() == initiator->GetID()) {
entity->CastToClient()->MessageString(Chat::NPCQuestSay, DUEL_DECLINE, initiator->GetName()); entity->CastToClient()->MessageString(Chat::NPCQuestSay, DUEL_DECLINE, initiator->GetName());
else } else {
initiator->CastToClient()->MessageString(Chat::NPCQuestSay, DUEL_DECLINE, entity->GetName()); initiator->CastToClient()->MessageString(Chat::NPCQuestSay, DUEL_DECLINE, entity->GetName());
}
return; return;
} }
void Client::Handle_OP_DuelResponse2(const EQApplicationPacket *app) void Client::Handle_OP_DuelAccept(const EQApplicationPacket *app)
{ {
if (app->size != sizeof(Duel_Struct)) if (app->size != sizeof(Duel_Struct)) {
return; return;
}
Duel_Struct* ds = (Duel_Struct*)app->pBuffer; Duel_Struct* ds = (Duel_Struct*)app->pBuffer;
if (!ds->duel_initiator || !ds->duel_target) {
return;
}
Entity* entity = entity_list.GetID(ds->duel_target); Entity* entity = entity_list.GetID(ds->duel_target);
Entity* initiator = entity_list.GetID(ds->duel_initiator); Entity* initiator = entity_list.GetID(ds->duel_initiator);
if (!entity || !initiator) {
return;
}
if (entity && initiator && entity == this && initiator->IsClient()) { if (GetDuelTarget() != ds->duel_initiator || IsDueling()) {
return;
}
if (entity == this && initiator->IsClient()) {
auto outapp = new EQApplicationPacket(OP_RequestDuel, sizeof(Duel_Struct)); auto outapp = new EQApplicationPacket(OP_RequestDuel, sizeof(Duel_Struct));
Duel_Struct* ds2 = (Duel_Struct*)outapp->pBuffer; Duel_Struct* ds2 = (Duel_Struct*)outapp->pBuffer;
@ -5581,7 +5601,7 @@ void Client::Handle_OP_DuelResponse2(const EQApplicationPacket *app)
ds2->duel_target = entity->GetID(); ds2->duel_target = entity->GetID();
initiator->CastToClient()->QueuePacket(outapp); initiator->CastToClient()->QueuePacket(outapp);
outapp->SetOpcode(OP_DuelResponse2); outapp->SetOpcode(OP_DuelAccept);
ds2->duel_initiator = initiator->GetID(); ds2->duel_initiator = initiator->GetID();
initiator->CastToClient()->QueuePacket(outapp); initiator->CastToClient()->QueuePacket(outapp);
@ -5592,10 +5612,13 @@ void Client::Handle_OP_DuelResponse2(const EQApplicationPacket *app)
SetDuelTarget(ds->duel_initiator); SetDuelTarget(ds->duel_initiator);
safe_delete(outapp); safe_delete(outapp);
if (IsCasting()) if (IsCasting()) {
InterruptSpell(); InterruptSpell();
if (initiator->CastToClient()->IsCasting()) }
if (initiator->CastToClient()->IsCasting()) {
initiator->CastToClient()->InterruptSpell(); initiator->CastToClient()->InterruptSpell();
}
} }
return; return;
} }
@ -12455,34 +12478,54 @@ void Client::Handle_OP_Report(const EQApplicationPacket *app)
void Client::Handle_OP_RequestDuel(const EQApplicationPacket *app) void Client::Handle_OP_RequestDuel(const EQApplicationPacket *app)
{ {
if (app->size != sizeof(Duel_Struct)) if (app->size != sizeof(Duel_Struct)) {
return; return;
}
EQApplicationPacket* outapp = app->Copy(); EQApplicationPacket* outapp = app->Copy();
Duel_Struct* ds = (Duel_Struct*)outapp->pBuffer; Duel_Struct* ds = (Duel_Struct*)outapp->pBuffer;
if (!ds->duel_initiator || !ds->duel_target) {
return;
}
uint32 duel = ds->duel_initiator; uint32 duel = ds->duel_initiator;
ds->duel_initiator = ds->duel_target; ds->duel_initiator = ds->duel_target;
ds->duel_target = duel; ds->duel_target = duel;
Entity* entity = entity_list.GetID(ds->duel_target); Entity* entity = entity_list.GetID(ds->duel_target);
if (GetID() != ds->duel_target && entity->IsClient() && (entity->CastToClient()->IsDueling() && entity->CastToClient()->GetDuelTarget() != 0)) {
if (
GetID() != ds->duel_target &&
entity->IsClient() &&
entity->CastToClient()->IsDueling() &&
entity->CastToClient()->GetDuelTarget()
) {
MessageString(Chat::NPCQuestSay, DUEL_CONSIDERING, entity->GetName()); MessageString(Chat::NPCQuestSay, DUEL_CONSIDERING, entity->GetName());
return; return;
} }
if (IsDueling()) { if (IsDueling()) {
MessageString(Chat::NPCQuestSay, DUEL_INPROGRESS); MessageString(Chat::NPCQuestSay, DUEL_INPROGRESS);
return; return;
} }
if (GetID() != ds->duel_target && entity->IsClient() && GetDuelTarget() == 0 && !IsDueling() && !entity->CastToClient()->IsDueling() && entity->CastToClient()->GetDuelTarget() == 0) { if (
GetID() != ds->duel_target &&
entity->IsClient() &&
!GetDuelTarget() &&
!IsDueling() &&
!entity->CastToClient()->IsDueling() &&
!entity->CastToClient()->GetDuelTarget()
) {
SetDuelTarget(ds->duel_target); SetDuelTarget(ds->duel_target);
entity->CastToClient()->SetDuelTarget(GetID()); entity->CastToClient()->SetDuelTarget(GetID());
ds->duel_target = ds->duel_initiator; ds->duel_target = ds->duel_initiator;
entity->CastToClient()->FastQueuePacket(&outapp); entity->CastToClient()->FastQueuePacket(&outapp);
entity->CastToClient()->SetDueling(false); entity->CastToClient()->SetDueling(false);
SetDueling(false); SetDueling(false);
} } else {
else
safe_delete(outapp); safe_delete(outapp);
}
return; return;
} }

View File

@ -97,8 +97,8 @@
void Handle_OP_Disarm(const EQApplicationPacket *app); void Handle_OP_Disarm(const EQApplicationPacket *app);
void Handle_OP_DisarmTraps(const EQApplicationPacket *app); void Handle_OP_DisarmTraps(const EQApplicationPacket *app);
void Handle_OP_DoGroupLeadershipAbility(const EQApplicationPacket *app); void Handle_OP_DoGroupLeadershipAbility(const EQApplicationPacket *app);
void Handle_OP_DuelResponse(const EQApplicationPacket *app); void Handle_OP_DuelDecline(const EQApplicationPacket *app);
void Handle_OP_DuelResponse2(const EQApplicationPacket *app); void Handle_OP_DuelAccept(const EQApplicationPacket *app);
void Handle_OP_DumpName(const EQApplicationPacket *app); void Handle_OP_DumpName(const EQApplicationPacket *app);
void Handle_OP_Dye(const EQApplicationPacket *app); void Handle_OP_Dye(const EQApplicationPacket *app);
void Handle_OP_DzAddPlayer(const EQApplicationPacket *app); void Handle_OP_DzAddPlayer(const EQApplicationPacket *app);

View File

@ -582,7 +582,7 @@ luabind::scope lua_register_packet_opcodes() {
luabind::value("Logout", static_cast<int>(OP_Logout)), luabind::value("Logout", static_cast<int>(OP_Logout)),
luabind::value("LogoutReply", static_cast<int>(OP_LogoutReply)), luabind::value("LogoutReply", static_cast<int>(OP_LogoutReply)),
luabind::value("PreLogoutReply", static_cast<int>(OP_PreLogoutReply)), luabind::value("PreLogoutReply", static_cast<int>(OP_PreLogoutReply)),
luabind::value("DuelResponse2", static_cast<int>(OP_DuelResponse2)), luabind::value("DuelAccept", static_cast<int>(OP_DuelAccept)),
luabind::value("InstillDoubt", static_cast<int>(OP_InstillDoubt)), luabind::value("InstillDoubt", static_cast<int>(OP_InstillDoubt)),
luabind::value("SafeFallSuccess", static_cast<int>(OP_SafeFallSuccess)), luabind::value("SafeFallSuccess", static_cast<int>(OP_SafeFallSuccess)),
luabind::value("DisciplineUpdate", static_cast<int>(OP_DisciplineUpdate)), luabind::value("DisciplineUpdate", static_cast<int>(OP_DisciplineUpdate)),
@ -659,7 +659,7 @@ luabind::scope lua_register_packet_opcodes() {
luabind::value("TraderDelItem", static_cast<int>(OP_TraderDelItem)), luabind::value("TraderDelItem", static_cast<int>(OP_TraderDelItem)),
luabind::value("AdventureMerchantPurchase", static_cast<int>(OP_AdventureMerchantPurchase)), luabind::value("AdventureMerchantPurchase", static_cast<int>(OP_AdventureMerchantPurchase)),
luabind::value("TestBuff", static_cast<int>(OP_TestBuff)), luabind::value("TestBuff", static_cast<int>(OP_TestBuff)),
luabind::value("DuelResponse", static_cast<int>(OP_DuelResponse)), luabind::value("DuelDecline", static_cast<int>(OP_DuelDecline)),
luabind::value("RequestDuel", static_cast<int>(OP_RequestDuel)), luabind::value("RequestDuel", static_cast<int>(OP_RequestDuel)),
luabind::value("BazaarInspect", static_cast<int>(OP_BazaarInspect)), luabind::value("BazaarInspect", static_cast<int>(OP_BazaarInspect)),
luabind::value("ClickDoor", static_cast<int>(OP_ClickDoor)), luabind::value("ClickDoor", static_cast<int>(OP_ClickDoor)),

View File

@ -1753,7 +1753,7 @@ XS(XS_Client_GetDuelTarget) {
Perl_croak(aTHX_ "Usage: Client::GetDuelTarget(THIS)"); // @categories Account and Character, Script Utility Perl_croak(aTHX_ "Usage: Client::GetDuelTarget(THIS)"); // @categories Account and Character, Script Utility
{ {
Client *THIS; Client *THIS;
uint16 RETVAL; uint32 RETVAL;
dXSTARG; dXSTARG;
VALIDATE_THIS_IS_CLIENT; VALIDATE_THIS_IS_CLIENT;
RETVAL = THIS->GetDuelTarget(); RETVAL = THIS->GetDuelTarget();
@ -1786,7 +1786,7 @@ XS(XS_Client_SetDuelTarget) {
Perl_croak(aTHX_ "Usage: Client::SetDuelTarget(THIS, set_id)"); // @categories Account and Character Perl_croak(aTHX_ "Usage: Client::SetDuelTarget(THIS, set_id)"); // @categories Account and Character
{ {
Client *THIS; Client *THIS;
uint16 set_id = (uint16) SvUV(ST(1)); uint32 set_id = (uint32) SvUV(ST(1));
VALIDATE_THIS_IS_CLIENT; VALIDATE_THIS_IS_CLIENT;
THIS->SetDuelTarget(set_id); THIS->SetDuelTarget(set_id);
} }