Index: src/game/ArenaTeam.cpp =================================================================== --- src/game/ArenaTeam.cpp (revision 5306) +++ src/game/ArenaTeam.cpp (working copy) @@ -88,11 +88,21 @@ std::string plName; uint8 plClass; + if(GetMembersSize() >= GetType() * 2) + { + // arena team is full (can't have more than type * 2 players!) + // return false + return false; + } + if(!objmgr.GetPlayerNameByGUID(PlayerGuid, plName)) // player doesnt exist return false; // player already in arenateam of that size - if(Player::GetArenaTeamIdFromDB(PlayerGuid, GetSlot()) != 0) + if(Player::GetArenaTeamIdFromDB(PlayerGuid, GetType()) != 0) + { + sLog.outError("Arena::AddMember() : player already in this sized team"); return false; + } // remove all player signs from another petitions // this will be prevent attempt joining player to many arenateams and corrupt arena team data integrity Index: src/game/ArenaTeamHandler.cpp =================================================================== --- src/game/ArenaTeamHandler.cpp (revision 5306) +++ src/game/ArenaTeamHandler.cpp (working copy) @@ -111,7 +111,7 @@ return; } - if(player->getLevel() != 70) + if(player->getLevel() < 70) { //SendArenaTeamCommandResult(ARENA_TEAM_INVITE_SS,"",Invitedname,ARENA_TEAM_PLAYER_NOT_FOUND_S); // can't find related opcode @@ -148,6 +148,14 @@ return; } + if(arenateam->GetMembersSize() >= arenateam->GetType() * 2) + { + // should send an "arena team is full" or the likes message, I just don't know the proper values so... ERR_INTERNAL +// SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_INTERNAL); + SendNotification("Your arena team is full, %s cannot join it.", player->GetName()); + return; + } + sLog.outDebug("Player %s Invited %s to Join his ArenaTeam", GetPlayer()->GetName(), Invitedname.c_str()); player->SetArenaTeamIdInvited(GetPlayer()->GetArenaTeamId(team_slot)); Index: src/game/PetitionsHandler.cpp =================================================================== --- src/game/PetitionsHandler.cpp (revision 5306) +++ src/game/PetitionsHandler.cpp (working copy) @@ -49,9 +49,6 @@ { CHECK_PACKET_SIZE(recv_data, 8+8+4+1+5*8+2+1+4+4); - if(_player->GetGuildId()) - return; - sLog.outDebug("Received opcode CMSG_PETITION_BUY"); //recv_data.hexlike(); @@ -95,6 +92,11 @@ uint32 type = 0; if(pCreature->isTabardDesigner()) { + // if tabard designer, then trying to buy a guild charter. + // do not let if already in guild. + if(_player->GetGuildId()) + return; + charterid = GUILD_CHARTER; cost = GUILD_CHARTER_COST; type = 9; @@ -102,7 +104,7 @@ else { // TODO: find correct opcode - if(_player->getLevel() != 70) + if(_player->getLevel() < 70) { SendNotification(objmgr.GetMangosString(LANG_ARENA_ONE_TOOLOW, GetSessionLocaleIndex()), 70); return; @@ -188,10 +190,31 @@ charter->SetState(ITEM_CHANGED, _player); _player->SendNewItem(charter, 1, true, false); + // a petition is invalid, if both the owner and the type matches + QueryResult *result = CharacterDatabase.PQuery("SELECT petitionguid FROM petition WHERE ownerguid = '%u' AND type = '%u'", _player->GetGUIDLow(), type); + + std::ostringstream ssInvalidPetitionGUIDs; + + if (result) + { + + do + { + Field *fields = result->Fetch(); + ssInvalidPetitionGUIDs << "'" << fields[0].GetUInt32() << "' , "; + } while (result->NextRow()); + + delete result; + } + + // delete petitions with the same guid as this one + ssInvalidPetitionGUIDs << "'" << charter->GetGUIDLow() << "'"; + + sLog.outDebug("Invalid petition GUIDs: %s", ssInvalidPetitionGUIDs.str().c_str()); CharacterDatabase.escape_string(name); CharacterDatabase.BeginTransaction(); - CharacterDatabase.PExecute("DELETE FROM petition WHERE ownerguid = '%u' OR petitionguid = '%u' and type = '%u'", _player->GetGUIDLow(), charter->GetGUIDLow(),type); - CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE ownerguid = '%u' or petitionguid = '%u'", _player->GetGUIDLow(), charter->GetGUIDLow()); + CharacterDatabase.PExecute("DELETE FROM petition WHERE petitionguid IN ( %s )", ssInvalidPetitionGUIDs.str().c_str()); + CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE petitionguid IN ( %s )", ssInvalidPetitionGUIDs.str().c_str()); CharacterDatabase.PExecute("INSERT INTO petition (ownerguid, petitionguid, name, type) VALUES ('%u', '%u', '%s', '%u')", _player->GetGUIDLow(), charter->GetGUIDLow(), name.c_str(), type); CharacterDatabase.CommitTransaction(); @@ -205,9 +228,6 @@ sLog.outDebug("Received opcode CMSG_PETITION_SHOW_SIGNATURES"); //recv_data.hexlike(); - if(_player->GetGuildId()) - return; - uint8 signs = 0; uint64 petitionguid; recv_data >> petitionguid; // petition guid @@ -215,14 +235,18 @@ // solve (possible) some strange compile problems with explicit use GUID_LOPART(petitionguid) at some GCC versions (wrong code optimization in compiler?) uint32 petitionguid_low = GUID_LOPART(petitionguid); - QueryResult *result = CharacterDatabase.PQuery("SELECT petitionguid FROM petition WHERE petitionguid = '%u'", petitionguid_low); + QueryResult *result = CharacterDatabase.PQuery("SELECT petitionguid, type FROM petition WHERE petitionguid = '%u'", petitionguid_low); if(!result) { sLog.outError("any petition on server..."); return; } - + Field *fields = result->Fetch(); + uint32 type = fields[1].GetUInt32(); delete result; + // if guild petition and has guild => error, return; + if(type==9 && _player->GetGuildId()) + return; result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE petitionguid = '%u'", petitionguid_low); @@ -317,13 +341,14 @@ { data << uint32(9); data << uint32(9); + data << uint32(0); // bypass client - side limitation, a different value is needed here for each petition } else { data << type-1; data << type-1; + data << type; // bypass client - side limitation, a different value is needed here for each petition } - data << uint32(0); // 4 data << uint32(0); // 5 data << uint32(0); // 6 data << uint32(0); // 7 @@ -457,13 +482,20 @@ return; } + if(type != 9 && _player->getLevel() < 70) + { + // player is too low level to join an arena team + SendNotification("You must be level 70 to join an arena team!"); + return; + } + signs += 1; if(signs > type) // client signs maximum return; //client doesn't allow to sign petition two times by one character, but not check sign by another character from same account //not allow sign another player from already sign player account - result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE player_account = '%u'", GetAccountId()); + result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE player_account = '%u' AND petitionguid = '%u'", GetAccountId(), GUID_LOPART(petitionguid)); if(result) { @@ -638,16 +670,29 @@ } else { - for(uint8 i = 0; i < 3; i++) + uint32 type_slot; + switch(type) { - if(_player->GetArenaTeamId(i)) - { + case ARENA_TEAM_2v2: + type_slot = 0; + break; + case ARENA_TEAM_3v3: + type_slot = 1; + break; + case ARENA_TEAM_5v5: + type_slot = 2; + break; + default: + type_slot = 0; + break; + } + if(_player->GetArenaTeamId(type_slot)) + { //data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4); //data << (uint32)PETITION_TURN_ALREADY_IN_GUILD; // already in guild //_player->GetSession()->SendPacket(&data); SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ALREADY_IN_ARENA_TEAM); return; - } } } @@ -735,6 +780,7 @@ ArenaTeam* at = new ArenaTeam; if(!at->create(_player->GetGUID(), type, name)) { + sLog.outError("PetitionsHandler: arena team create failed."); delete at; delete result; return; @@ -748,11 +794,13 @@ // register team and add captain objmgr.AddArenaTeam(at); + sLog.outDebug("PetitonsHandler: arena team added to objmrg"); // add members for(uint8 i = 0; i < signs; ++i) { Field* fields = result->Fetch(); + sLog.outDebug("PetitionsHandler: adding arena member %u", fields[0].GetUInt64()); at->AddMember(fields[0].GetUInt64()); result->NextRow(); } @@ -820,21 +868,21 @@ data << uint32(ARENA_TEAM_CHARTER_2v2); // charter entry data << uint32(16161); // charter display id data << uint32(ARENA_TEAM_CHARTER_2v2_COST); // charter cost - data << uint32(0); // unknown + data << uint32(2); // unknown data << uint32(2); // required signs? // 3v3 data << uint32(2); // index data << uint32(ARENA_TEAM_CHARTER_3v3); // charter entry data << uint32(16161); // charter display id data << uint32(ARENA_TEAM_CHARTER_3v3_COST); // charter cost - data << uint32(0); // unknown + data << uint32(3); // unknown data << uint32(3); // required signs? // 5v5 data << uint32(3); // index data << uint32(ARENA_TEAM_CHARTER_5v5); // charter entry data << uint32(16161); // charter display id data << uint32(ARENA_TEAM_CHARTER_5v5_COST); // charter cost - data << uint32(0); // unknown + data << uint32(5); // unknown data << uint32(5); // required signs? } //for(uint8 i = 0; i < count; i++) Index: src/game/Player.cpp =================================================================== --- src/game/Player.cpp (revision 5306) +++ src/game/Player.cpp (working copy) @@ -5659,27 +5659,33 @@ return 0; } -uint32 Player::GetArenaTeamIdFromDB(uint64 guid, uint8 slot) +uint32 Player::GetArenaTeamIdFromDB(uint64 guid, uint8 type) { // need fix it! QueryResult *result = CharacterDatabase.PQuery("SELECT arenateamid FROM arena_team_member WHERE guid='%u'", GUID_LOPART(guid)); if(result) { - uint32 id = (*result)[0].GetUInt32(); + // init id to 0, check the arena type before assigning a value to id + uint32 id = 0; do { QueryResult *result2 = CharacterDatabase.PQuery("SELECT type FROM arena_team WHERE arenateamid='%u'", id); if(result2) { - uint8 dbslot = (*result2)[0].GetUInt32(); + uint8 dbtype = (*result2)[0].GetUInt32(); delete result2; - if(dbslot == slot) + if(dbtype == type) + { + // if the type matches, we've found the id + id = (*result)[0].GetUInt32(); break; + } } } while(result->NextRow()); delete result; return id; } + // no arenateam for the specified guid, return 0 return 0; } @@ -14894,11 +14900,15 @@ void Player::RemovePetitionsAndSigns(uint64 guid, uint32 type) { - QueryResult *result = CharacterDatabase.PQuery("SELECT ownerguid,petitionguid FROM petition_sign WHERE playerguid = '%u'", GUID_LOPART(guid)); + QueryResult *result = NULL; + if(type==10) + result = CharacterDatabase.PQuery("SELECT ownerguid,petitionguid FROM petition_sign WHERE playerguid = '%u'", GUID_LOPART(guid)); + else + result = CharacterDatabase.PQuery("SELECT ownerguid,petitionguid FROM petition_sign WHERE playerguid = '%u' AND type = '%u'", GUID_LOPART(guid), type); if(result) { - do - { + do // this part effectively does nothing, since the deletion / modification only takes place _after_ the PetitionQuery. Though I don't know if the result remains intact if I execute the delete query beforehand. + { // and SendPetitionQueryOpcode reads data from the DB Field *fields = result->Fetch(); uint64 ownerguid = MAKE_GUID(fields[0].GetUInt32(), HIGHGUID_PLAYER); uint64 petitionguid = MAKE_GUID(fields[1].GetUInt32(), HIGHGUID_ITEM); @@ -14912,15 +14922,23 @@ delete result; - CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE playerguid = '%u'", GUID_LOPART(guid)); + if(type==10) + CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE playerguid = '%u'", GUID_LOPART(guid)); + else + CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE playerguid = '%u' AND type = '%u'", GUID_LOPART(guid), type); } CharacterDatabase.BeginTransaction(); if(type == 10) + { CharacterDatabase.PExecute("DELETE FROM petition WHERE ownerguid = '%u'", GUID_LOPART(guid)); + CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE ownerguid = '%u'", GUID_LOPART(guid)); + } else + { CharacterDatabase.PExecute("DELETE FROM petition WHERE ownerguid = '%u' AND type = '%u'", GUID_LOPART(guid), type); - CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE ownerguid = '%u'", GUID_LOPART(guid)); + CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE ownerguid = '%u' AND type = '%u'", GUID_LOPART(guid), type); + } CharacterDatabase.CommitTransaction(); }