void Reset() { events.Reset(); ClearCastQueue(); events.ScheduleEvent(EVENT_SHADOW_VOLLEY, 3000); events.ScheduleEvent(EVENT_CLEAVE, 5000); events.ScheduleEvent(EVENT_THUNDER_CLAP, urand(12000, 20000)); events.ScheduleEvent(EVENT_VOID_BOLT, 30000); events.ScheduleEvent(EVENT_MARKOFKAZZAK, 25000); events.ScheduleEvent(EVENT_TWIST_REFLECT, 33000); events.ScheduleEvent(EVENT_ENRAGE, 60000); QueryResultAutoPtr resultWorldBossRespawn = QueryResultAutoPtr(NULL); resultWorldBossRespawn = GameDataDatabase.PQuery("SELECT RespawnTime FROM worldboss_respawn WHERE BossEntry = %i", m_creature->GetEntry()); if (resultWorldBossRespawn) { Field* fieldsWBR = resultWorldBossRespawn->Fetch(); uint64 last_time_killed = fieldsWBR[0].GetUInt64(); last_time_killed += 259200; if (last_time_killed >= time(0)) me->DisappearAndDie(); } }
/// Reconnect Challenge command handler bool AuthSocket::_HandleReconnectChallenge() { DEBUG_LOG("Entering _HandleReconnectChallenge"); if (recv_len() < sizeof(sAuthLogonChallenge_C)) return false; ///- Read the first 4 bytes (header) to get the length of the remaining of the packet std::vector<uint8> buf; buf.resize(4); recv((char *)&buf[0], 4); EndianConvert(*((uint16*)(buf[0]))); uint16 remaining = ((sAuthLogonChallenge_C *)&buf[0])->size; DEBUG_LOG("[ReconnectChallenge] got header, body is %#04x bytes", remaining); if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (recv_len() < remaining)) return false; //No big fear of memory outage (size is int16, i.e. < 65536) buf.resize(remaining + buf.size() + 1); buf[buf.size() - 1] = 0; sAuthLogonChallenge_C *ch = (sAuthLogonChallenge_C*)&buf[0]; ///- Read the remaining of the packet recv((char *)&buf[4], remaining); DEBUG_LOG("[ReconnectChallenge] got full packet, %#04x bytes", ch->size); DEBUG_LOG("[ReconnectChallenge] name(%d): '%s'", ch->I_len, ch->I); _login = (const char*)ch->I; _safelogin = _login; AccountsDatabase.escape_string(_safelogin); EndianConvert(ch->build); _build = ch->build; QueryResultAutoPtr result = AccountsDatabase.PQuery("SELECT session_key FROM account JOIN account_session ON account.account_id = account_session.account_id WHERE username = '******'", _safelogin.c_str()); // Stop if the account is not found if (!result) { sLog.outLog(LOG_DEFAULT, "ERROR: [ERROR] user %s tried to login and we cannot find his session key in the database.", _login.c_str()); close_connection(); return false; } Field* fields = result->Fetch (); K.SetHexStr (fields[0].GetString ()); ///- Sending response ByteBuffer pkt; pkt << uint8(CMD_AUTH_RECONNECT_CHALLENGE); pkt << uint8(0x00); _reconnectProof.SetRand(16 * 8); pkt.append(_reconnectProof.AsByteArray(16),16); // 16 bytes random pkt << uint64(0x00) << uint64(0x00); // 16 bytes zeros send((char const*)pkt.contents(), pkt.size()); return true; }
void WorldSession::HandlePetitionDeclineOpcode(WorldPacket & recv_data) { CHECK_PACKET_SIZE(recv_data, 8); sLog.outDebug("Received opcode MSG_PETITION_DECLINE"); // ok //recv_data.hexlike(); uint64 petitionguid; uint64 ownerguid; recv_data >> petitionguid; // petition guid sLog.outDebug("Petition %u declined by %u", GUID_LOPART(petitionguid), _player->GetGUIDLow()); QueryResultAutoPtr result = RealmDataDatabase.PQuery("SELECT ownerguid FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); if (!result) return; Field *fields = result->Fetch(); ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); Player *owner = sObjectMgr.GetPlayer(ownerguid); if (owner) // petition owner online { WorldPacket data(MSG_PETITION_DECLINE, 8); data << _player->GetGUID(); owner->SendPacketToSelf(&data); } }
void GuildMgr::LoadGuildAnnCooldowns() { uint32 count = 0; QueryResultAutoPtr result = RealmDataDatabase.Query("SELECT guild_id, cooldown_end FROM guild_announce_cooldown"); if (!result) { BarGoLink bar(1); bar.step(); sLog.outString(); sLog.outString(">> Loaded 0 guildann_cooldowns."); return; } BarGoLink bar(result->GetRowCount()); do { Field *fields = result->Fetch(); bar.step(); uint32 guild_id = fields[0].GetUInt32(); uint64 respawn_time = fields[1].GetUInt64(); m_guildCooldownTimes[guild_id] = time_t(respawn_time); ++count; } while (result->NextRow()); sLog.outString(">> Loaded %u guild ann cooldowns.", m_guildCooldownTimes.size()); sLog.outString(); }
void WorldSession::SendPetitionQueryOpcode(uint64 petitionguid) { uint64 ownerguid = 0; uint32 type; std::string name = "NO_NAME_FOR_GUID"; uint8 signs = 0; QueryResultAutoPtr result = RealmDataDatabase.PQuery( "SELECT ownerguid, name, " " (SELECT COUNT(playerguid) FROM petition_sign WHERE petition_sign.petitionguid = '%u') AS signs, " " type " "FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid), GUID_LOPART(petitionguid)); if (result) { Field* fields = result->Fetch(); ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); name = fields[1].GetCppString(); signs = fields[2].GetUInt8(); type = fields[3].GetUInt32(); } else { sLog.outDebug("CMSG_PETITION_QUERY failed for petition (GUID: %u)", GUID_LOPART(petitionguid)); return; } WorldPacket data(SMSG_PETITION_QUERY_RESPONSE, (4+8+name.size()+1+1+4*13)); data << GUID_LOPART(petitionguid); // guild/team guid (in Trinity always same as GUID_LOPART(petition guid) data << ownerguid; // charter owner guid data << name; // name (guild/arena team) data << uint8(0); // 1 if (type == 9) { 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); // 5 data << uint32(0); // 6 data << uint32(0); // 7 data << uint32(0); // 8 data << uint16(0); // 9 2 bytes field data << uint32(0); // 10 data << uint32(0); // 11 data << uint32(0); // 13 count of next strings? data << uint32(0); // 14 if (type == 9) data << uint32(0); // 15 0 - guild, 1 - arena team else data << uint32(1); SendPacket(&data); }
void MapManager::InitMaxInstanceId() { i_MaxInstanceId = 0; QueryResultAutoPtr result = RealmDataDatabase.Query("SELECT MAX(id) FROM instance"); if (result) i_MaxInstanceId = result->Fetch()[0].GetUInt32(); }
void WorldSession::HandlePetitionShowSignOpcode(WorldPacket & recv_data) { CHECK_PACKET_SIZE(recv_data, 8); // ok sLog.outDebug("Received opcode CMSG_PETITION_SHOW_SIGNATURES"); //recv_data.hexlike(); uint8 signs = 0; uint64 petitionguid; recv_data >> petitionguid; // petition guid // 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); QueryResultAutoPtr result = RealmDataDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", petitionguid_low); if (!result) { sLog.outLog(LOG_DEFAULT, "ERROR: any petition on server..."); return; } Field *fields = result->Fetch(); uint32 type = fields[0].GetUInt32(); // if guild petition and has guild => error, return; if (type==9 && _player->GetGuildId()) return; result = RealmDataDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE petitionguid = '%u'", petitionguid_low); // result==NULL also correct in case no sign yet if (result) signs = result->GetRowCount(); sLog.outDebug("CMSG_PETITION_SHOW_SIGNATURES petition entry: '%u'", petitionguid_low); WorldPacket data(SMSG_PETITION_SHOW_SIGNATURES, (8+8+4+1+signs*12)); data << petitionguid; // petition guid data << _player->GetGUID(); // owner guid data << petitionguid_low; // guild guid (in Trinity always same as GUID_LOPART(petitionguid) data << signs; // sign's count for (uint8 i = 1; i <= signs; i++) { Field *fields2 = result->Fetch(); uint64 plguid = fields2[0].GetUInt64(); data << plguid; // Player GUID data << (uint32)0; // there 0 ... result->NextRow(); } SendPacket(&data); }
void WorldSession::HandleCharDeleteOpcode(WorldPacket & recv_data) { CHECK_PACKET_SIZE(recv_data,8); uint64 guid; recv_data >> guid; // can't delete loaded character if (sObjectMgr.GetPlayer(guid)) return; uint32 accountId = 0; std::string name; // is guild leader if (sGuildMgr.GetGuildByLeader(guid)) { WorldPacket data(SMSG_CHAR_DELETE, 1); data << (uint8)CHAR_DELETE_FAILED_GUILD_LEADER; SendPacket(&data); return; } // is arena team captain if (sObjectMgr.GetArenaTeamByCaptain(guid)) { WorldPacket data(SMSG_CHAR_DELETE, 1); data << (uint8)CHAR_DELETE_FAILED_ARENA_CAPTAIN; SendPacket(&data); return; } QueryResultAutoPtr result = RealmDataDatabase.PQuery("SELECT account,name FROM characters WHERE guid='%u'", GUID_LOPART(guid)); if (result) { Field *fields = result->Fetch(); accountId = fields[0].GetUInt32(); name = fields[1].GetCppString(); } // prevent deleting other players' characters using cheating tools if (accountId != GetAccountId()) return; std::string IP_str = GetRemoteAddress(); sLog.outDetail("Account: %d (IP: %s) Delete Character:[%s] (guid:%u)",GetAccountId(),IP_str.c_str(),name.c_str(),GUID_LOPART(guid)); sLog.outLog(LOG_CHAR, "Account: %d (IP: %s) Delete Character:[%s] (guid: %u)",GetAccountId(),IP_str.c_str(),name.c_str(),GUID_LOPART(guid)); Player::DeleteFromDB(guid, GetAccountId()); WorldPacket data(SMSG_CHAR_DELETE, 1); data << (uint8)CHAR_DELETE_SUCCESS; SendPacket(&data); }
void ReputationMgr::LoadFromDB(QueryResultAutoPtr result) { // Set initial reputations (so everything is nifty before DB data load) Initialize(); //QueryResult *result = CharacterDatabase.PQuery("SELECT faction,standing,flags FROM character_reputation WHERE guid = '%u'",GetGUIDLow()); if (result) { do { Field *fields = result->Fetch(); FactionEntry const *factionEntry = sFactionStore.LookupEntry(fields[0].GetUInt32()); if (factionEntry && (factionEntry->reputationListID >= 0)) { FactionState* faction = &m_factions[factionEntry->reputationListID]; // update standing to current faction->Standing = int32(fields[1].GetUInt32()); uint32 dbFactionFlags = fields[2].GetUInt32(); if (dbFactionFlags & FACTION_FLAG_VISIBLE) SetVisible(faction); // have internal checks for forced invisibility if (dbFactionFlags & FACTION_FLAG_INACTIVE) SetInactive(faction, true); // have internal checks for visibility requirement if (dbFactionFlags & FACTION_FLAG_AT_WAR) // DB at war SetAtWar(faction, true); // have internal checks for FACTION_FLAG_PEACE_FORCED else // DB not at war { // allow remove if visible (and then not FACTION_FLAG_INVISIBLE_FORCED or FACTION_FLAG_HIDDEN) if (faction->Flags & FACTION_FLAG_VISIBLE) SetAtWar(faction, false); // have internal checks for FACTION_FLAG_PEACE_FORCED } // set atWar for hostile if (GetRank(factionEntry) <= REP_HOSTILE) SetAtWar(faction,true); // reset changed flag if values similar to saved in DB if (faction->Flags==dbFactionFlags) { faction->needSend = false; faction->needSave = false; } } } while(result->NextRow()); } }
void GuildMgr::LoadGuilds() { Guild *newguild; uint32 count = 0; QueryResultAutoPtr result = RealmDataDatabase.Query("SELECT guildid FROM guild"); if (!result) { BarGoLink bar(1); bar.step(); sLog.outString(); sLog.outString(">> Loaded %u guild definitions", count); return; } BarGoLink bar(result->GetRowCount()); do { Field *fields = result->Fetch(); bar.step(); ++count; newguild = new Guild; if ( !newguild->LoadGuildFromDB( fields[0].GetUInt32() ) ) { newguild->Disband(); delete newguild; continue; } AddGuild(newguild); } while ( result->NextRow( )); result = RealmDataDatabase.Query("SELECT MAX(guildid) FROM guild"); if (result) m_guildId = (*result)[0].GetUInt32()+1; sLog.outString(); sLog.outString(">> Loaded %u guild definitions, next guild ID: %u", count, m_guildId); }
void WaypointMgr::UpdatePath(uint32 id) { if (_waypointPathMap.find(id)!= _waypointPathMap.end()) _waypointPathMap[id]->clear(); QueryResultAutoPtr result = GameDataDatabase.PQuery("SELECT `id`,`point`,`position_x`,`position_y`,`position_z`,`move_type`,`delay`,`action`,`action_chance` FROM `waypoint_data` WHERE id = %u ORDER BY `point`", id); if (!result) return; WaypointPath* path_data; path_data = new WaypointPath; Field *fields; do { fields = result->Fetch(); uint32 id = fields[0].GetUInt32(); WaypointData *wp = new WaypointData; float x,y,z; x = fields[2].GetFloat(); y = fields[3].GetFloat(); z = fields[4].GetFloat(); Looking4group::NormalizeMapCoord(x); Looking4group::NormalizeMapCoord(y); wp->id = fields[1].GetUInt32(); wp->x = x; wp->y = y; wp->z = z; wp->moveType = WaypointMoveType(fields[5].GetUInt8()); wp->delay = fields[6].GetUInt32(); wp->event_id = fields[7].GetUInt32(); wp->event_chance = fields[8].GetUInt8(); path_data->push_back(wp); } while (result->NextRow()); _waypointPathMap[id] = path_data; }
void WorldSession::HandleCharEnum(QueryResultAutoPtr result) { // keys can be non cleared if player open realm list and close it by 'cancel' static SqlStatementID clearKeys; SqlStatement stmt = AccountsDatabase.CreateStatement(clearKeys, "UPDATE account_session SET v = '0', s = '0' WHERE account_id = ?"); stmt.PExecute(GetAccountId()); WorldPacket data(SMSG_CHAR_ENUM, 100); // we guess size uint8 num = 0; data << num; if (result) { do { uint32 guidlow = (*result)[0].GetUInt32(); sLog.outDetail("Loading char guid %u from account %u.", guidlow, GetAccountId()); if (Player::BuildEnumData(result, &data)) ++num; } while (result->NextRow()); } data.put<uint8>(0, num); SendPacket(&data); }
bool ChatHandler::HandleAccountWhispLogCommand(const char* args) { if(!*args) return false; if (uint32 account_id = AccountMgr::GetId(args)) { QueryResultAutoPtr result = AccountsDatabase.PQuery("SELECT account_flags FROM account WHERE account_id = '%u'", account_id); if (!result) return false; Field * fields = result->Fetch(); uint64 accFlags = fields[0].GetUInt64(); if (WorldSession *session = sWorld.FindSession(account_id)) { if (accFlags & ACC_WHISPER_LOG) session->RemoveAccountFlag(ACC_WHISPER_LOG); else session->AddAccountFlag(ACC_WHISPER_LOG); } else { if (accFlags & ACC_WHISPER_LOG) WorldSession::SaveAccountFlags(account_id, accFlags &= ~ACC_WHISPER_LOG); else WorldSession::SaveAccountFlags(account_id, accFlags |= ACC_WHISPER_LOG); } if (accFlags & ACC_WHISPER_LOG) PSendSysMessage("WhispLog have been disabled for account: %u.", account_id); else PSendSysMessage("WhispLog have been enabled for account: %u.", account_id); } else { PSendSysMessage("Specified account not found."); SetSentErrorMessage(true); return false; } return true; }
void WorldSession::HandleChangePlayerNameOpcodeCallBack(QueryResultAutoPtr result, uint32 accountId, std::string newname) { WorldSession * session = sWorld.FindSession(accountId); if (!session) return; if (!result) { WorldPacket data(SMSG_CHAR_RENAME, 1); data << uint8(CHAR_CREATE_ERROR); session->SendPacket(&data); return; } uint32 guidLow = result->Fetch()[0].GetUInt32(); uint64 guid = MAKE_NEW_GUID(guidLow, 0, HIGHGUID_PLAYER); std::string oldname = result->Fetch()[1].GetCppString(); static SqlStatementID changeCharName; static SqlStatementID deleteDeclinedName; RealmDataDatabase.BeginTransaction(); SqlStatement stmt = RealmDataDatabase.CreateStatement(changeCharName, "UPDATE characters set name = ?, at_login = at_login & ~ ? WHERE guid = ?"); stmt.addString(newname); stmt.addUInt32(uint32(AT_LOGIN_RENAME)); stmt.addUInt32(guidLow); stmt.Execute(); stmt = RealmDataDatabase.CreateStatement(deleteDeclinedName, "DELETE FROM character_declinedname WHERE guid = ?"); stmt.PExecute(guidLow); RealmDataDatabase.CommitTransaction(); sLog.outLog(LOG_CHAR, "Account: %d (IP: %s) Character:[%s] (guid:%u) Changed name to: %s", session->GetAccountId(), session->GetRemoteAddress().c_str(), oldname.c_str(), guidLow, newname.c_str()); WorldPacket data(SMSG_CHAR_RENAME, 1+8+(newname.size()+1)); data << uint8(RESPONSE_SUCCESS); data << uint64(guid); data << newname; session->SendPacket(&data); }
/// Display info on users currently in the realm bool ChatHandler::HandleAccountOnlineListCommand(const char* args) { ///- Get the list of accounts ID logged to the realm QueryResultAutoPtr resultDB = RealmDataDatabase.Query("SELECT name, account FROM characters WHERE online > 0"); if (!resultDB) return true; ///- Display the list of account/characters online SendSysMessage("====================================================================="); SendSysMessage(LANG_ACCOUNT_LIST_HEADER); SendSysMessage("====================================================================="); ///- Circle through accounts do { Field *fieldsDB = resultDB->Fetch(); std::string name = fieldsDB[0].GetCppString(); uint32 account = fieldsDB[1].GetUInt32(); ///- Get the username, last IP and GM level of each account // No SQL injection. account is uint32. // 0 1 2 3 QueryResultAutoPtr resultLogin = AccountsDatabase.PQuery("SELECT username, last_ip, permission_mask, expansion_id " "FROM account JOIN account_permissions ON account.account_id = account_permissions.account_id " "WHERE account_id = '%u' AND realm_id = '%u'", account, realmID); if(resultLogin) { Field *fieldsLogin = resultLogin->Fetch(); PSendSysMessage("|%15s| %20s | %15s |%4d|%5d|", fieldsLogin[0].GetString(),name.c_str(),fieldsLogin[1].GetString(),fieldsLogin[2].GetUInt32(),fieldsLogin[3].GetUInt32()); } else PSendSysMessage(LANG_ACCOUNT_LIST_ERROR, name.c_str()); } while(resultDB->NextRow()); SendSysMessage("====================================================================="); return true; }
void Reset() { Enrage_Timer = 0; Armor_Timer = 5000 + rand()%8000; Chain_Timer = 10000 + rand()%20000; Quake_Timer = 25000 + rand()%10000; Overrun_Timer = 30000 + rand()%15000; InEnrage = false; QueryResultAutoPtr resultWorldBossRespawn = QueryResultAutoPtr(NULL); resultWorldBossRespawn = GameDataDatabase.PQuery("SELECT RespawnTime FROM worldboss_respawn WHERE BossEntry = %i", m_creature->GetEntry()); if (resultWorldBossRespawn) { Field* fieldsWBR = resultWorldBossRespawn->Fetch(); uint64 last_time_killed = fieldsWBR[0].GetUInt64(); last_time_killed += 259200; if (last_time_killed >= time(0)) me->DisappearAndDie(); } }
void LoadRandomEnchantmentsTable() { RandomItemEnch.clear(); // for reload case EnchantmentStore::iterator tab; uint32 entry, ench; float chance; uint32 count = 0; QueryResultAutoPtr result = GameDataDatabase.Query("SELECT entry, ench, chance FROM item_enchantment_template"); if (result) { BarGoLink bar(result->GetRowCount()); do { Field *fields = result->Fetch(); bar.step(); entry = fields[0].GetUInt32(); ench = fields[1].GetUInt32(); chance = fields[2].GetFloat(); if (chance > 0.000001f && chance <= 100.0f) RandomItemEnch[entry].push_back(EnchStoreItem(ench, chance)); ++count; } while (result->NextRow()); sLog.outString(); sLog.outString(">> Loaded %u Item Enchantment definitions", count); } else { sLog.outString(); sLog.outLog(LOG_DB_ERR, ">> Loaded 0 Item Enchantment definitions. DB table `item_enchantment_template` is empty."); } }
bool Corpse::LoadFromDB(uint32 guid, QueryResultAutoPtr result, uint32 InstanceId) { if (! result) // 0 1 2 3 4 5 6 7 8 result = RealmDataDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map,data,time,corpse_type,instance FROM corpse WHERE guid = '%u'",guid); if (! result) { sLog.outLog(LOG_DEFAULT, "ERROR: Corpse (GUID: %u) not found in table `corpse`, can't load. ",guid); return false; } Field *fields = result->Fetch(); if (!LoadFromDB(guid,fields)) return false; return true; }
void PoolManager::LoadFromDB() { QueryResultAutoPtr result = GameDataDatabase.Query("SELECT MAX(entry) FROM pool_template"); if (!result) { sLog.outString(">> Table pool_template is empty."); sLog.outString(); return; } else { Field *fields = result->Fetch(); max_pool_id = fields[0].GetUInt16(); } mPoolTemplate.resize(max_pool_id + 1); result = GameDataDatabase.Query("SELECT entry,max_limit FROM pool_template"); if (!result) { mPoolTemplate.clear(); sLog.outString(">> Table pool_template is empty:"); sLog.outString(); return; } uint32 count = 0; BarGoLink bar((int)result->GetRowCount()); do { ++count; Field *fields = result->Fetch(); bar.step(); uint16 pool_id = fields[0].GetUInt16(); PoolTemplateData& pPoolTemplate = mPoolTemplate[pool_id]; pPoolTemplate.MaxLimit = fields[1].GetUInt32(); pPoolTemplate.AutoSpawn = true; // will update and later data loading } while (result->NextRow()); sLog.outString(); sLog.outString( ">> Loaded %u objects pools", count ); PoolMapChecker mapChecker; // Creatures mPoolCreatureGroups.resize(max_pool_id + 1); mCreatureSearchMap.clear(); // 1 2 3 result = GameDataDatabase.Query("SELECT guid, pool_entry, chance FROM pool_creature"); count = 0; if (!result) { BarGoLink bar2(1); bar2.step(); sLog.outString(); sLog.outString(">> Loaded %u creatures in pools", count ); } else { BarGoLink bar2((int)result->GetRowCount()); do { Field *fields = result->Fetch(); bar2.step(); uint32 guid = fields[0].GetUInt32(); uint16 pool_id = fields[1].GetUInt16(); float chance = fields[2].GetFloat(); CreatureData const* data = sObjectMgr.GetCreatureData(guid); if (!data) { sLog.outLog(LOG_DB_ERR, "`pool_creature` has a non existing creature spawn (GUID: %u) defined for pool id (%u), skipped.", guid, pool_id ); continue; } if (pool_id > max_pool_id) { sLog.outLog(LOG_DB_ERR, "`pool_creature` pool id (%i) is out of range compared to max pool id in `pool_template`, skipped.",pool_id); continue; } if (chance < 0 || chance > 100) { sLog.outLog(LOG_DB_ERR, "`pool_creature` has an invalid chance (%f) for creature guid (%u) in pool id (%i), skipped.", chance, guid, pool_id); continue; } if (!mapChecker.CheckAndRemember(data->mapid, pool_id, "pool_creature", "creature guid")) continue; PoolTemplateData *pPoolTemplate = &mPoolTemplate[pool_id]; ++count; PoolObject plObject = PoolObject(guid, chance); PoolGroup<Creature>& cregroup = mPoolCreatureGroups[pool_id]; cregroup.SetPoolId(pool_id); cregroup.AddEntry(plObject, pPoolTemplate->MaxLimit); SearchPair p(guid, pool_id); mCreatureSearchMap.insert(p); } while (result->NextRow()); sLog.outString(); sLog.outString( ">> Loaded %u creatures in pools", count ); } // Gameobjects mPoolGameobjectGroups.resize(max_pool_id + 1); mGameobjectSearchMap.clear(); // 1 2 3 result = GameDataDatabase.Query("SELECT guid, pool_entry, chance FROM pool_gameobject"); count = 0; if (!result) { BarGoLink bar2(1); bar2.step(); sLog.outString(); sLog.outString(">> Loaded %u gameobject in pools", count ); } else { BarGoLink bar2((int)result->GetRowCount()); do { Field *fields = result->Fetch(); bar2.step(); uint32 guid = fields[0].GetUInt32(); uint16 pool_id = fields[1].GetUInt16(); float chance = fields[2].GetFloat(); GameObjectData const* data = sObjectMgr.GetGOData(guid); if (!data) { sLog.outLog(LOG_DB_ERR, "`pool_gameobject` has a non existing gameobject spawn (GUID: %u) defined for pool id (%u), skipped.", guid, pool_id ); continue; } GameObjectInfo const* goinfo = ObjectMgr::GetGameObjectInfo(data->id); if (goinfo->type != GAMEOBJECT_TYPE_CHEST && goinfo->type != GAMEOBJECT_TYPE_GOOBER && goinfo->type != GAMEOBJECT_TYPE_FISHINGHOLE) { sLog.outLog(LOG_DB_ERR, "`pool_gameobject` has a not lootable gameobject spawn (GUID: %u, type: %u) defined for pool id (%u), skipped.", guid, goinfo->type, pool_id ); continue; } if (pool_id > max_pool_id) { sLog.outLog(LOG_DB_ERR, "`pool_gameobject` pool id (%i) is out of range compared to max pool id in `pool_template`, skipped.",pool_id); continue; } if (chance < 0 || chance > 100) { sLog.outLog(LOG_DB_ERR, "`pool_gameobject` has an invalid chance (%f) for gameobject guid (%u) in pool id (%i), skipped.", chance, guid, pool_id); continue; } if (!mapChecker.CheckAndRemember(data->mapid, pool_id, "pool_gameobject", "gameobject guid")) continue; PoolTemplateData *pPoolTemplate = &mPoolTemplate[pool_id]; ++count; PoolObject plObject = PoolObject(guid, chance); PoolGroup<GameObject>& gogroup = mPoolGameobjectGroups[pool_id]; gogroup.SetPoolId(pool_id); gogroup.AddEntry(plObject, pPoolTemplate->MaxLimit); SearchPair p(guid, pool_id); mGameobjectSearchMap.insert(p); } while( result->NextRow() ); sLog.outString(); sLog.outString( ">> Loaded %u gameobject in pools", count ); } // Pool of pools mPoolPoolGroups.resize(max_pool_id + 1); // 1 2 3 result = GameDataDatabase.Query("SELECT pool_id, mother_pool, chance FROM pool_pool"); count = 0; if( !result ) { BarGoLink bar2(1); bar2.step(); sLog.outString(); sLog.outString(">> Loaded %u pools in pools", count ); } else { BarGoLink bar2( (int)result->GetRowCount() ); do { Field *fields = result->Fetch(); bar2.step(); uint16 child_pool_id = fields[0].GetUInt16(); uint16 mother_pool_id = fields[1].GetUInt16(); float chance = fields[2].GetFloat(); if (mother_pool_id > max_pool_id) { sLog.outLog(LOG_DB_ERR, "`pool_pool` mother_pool id (%i) is out of range compared to max pool id in `pool_template`, skipped.",mother_pool_id); continue; } if (child_pool_id > max_pool_id) { sLog.outLog(LOG_DB_ERR, "`pool_pool` included pool_id (%i) is out of range compared to max pool id in `pool_template`, skipped.",child_pool_id); continue; } if (mother_pool_id == child_pool_id) { sLog.outLog(LOG_DB_ERR, "`pool_pool` pool_id (%i) includes itself, dead-lock detected, skipped.",child_pool_id); continue; } if (chance < 0 || chance > 100) { sLog.outLog(LOG_DB_ERR, "`pool_pool` has an invalid chance (%f) for pool id (%u) in mother pool id (%i), skipped.", chance, child_pool_id, mother_pool_id); continue; } PoolTemplateData *pPoolTemplateMother = &mPoolTemplate[mother_pool_id]; ++count; PoolObject plObject = PoolObject(child_pool_id, chance); PoolGroup<Pool>& plgroup = mPoolPoolGroups[mother_pool_id]; plgroup.SetPoolId(mother_pool_id); plgroup.AddEntry(plObject, pPoolTemplateMother->MaxLimit); SearchPair p(child_pool_id, mother_pool_id); mPoolSearchMap.insert(p); // update top independent pool flag mPoolTemplate[child_pool_id].AutoSpawn = false; } while( result->NextRow() ); // Now check for circular reference for(uint16 i=0; i<max_pool_id; ++i) { std::set<uint16> checkedPools; for(SearchMap::iterator poolItr = mPoolSearchMap.find(i); poolItr != mPoolSearchMap.end(); poolItr = mPoolSearchMap.find(poolItr->second)) { // if child pool not have map data then it empty or have not checked child then will checked and all line later if (MapEntry const* childMapEntry = mapChecker.GetPoolMapEntry(poolItr->first)) { if (!mapChecker.CheckAndRemember(childMapEntry->MapID, poolItr->second, "pool_pool", "pool with creature/gameobject")) { mPoolPoolGroups[poolItr->second].RemoveOneRelation(poolItr->first); mPoolSearchMap.erase(poolItr); --count; break; } } checkedPools.insert(poolItr->first); if(checkedPools.find(poolItr->second) != checkedPools.end()) { std::ostringstream ss; ss<< "The pool(s) "; for (std::set<uint16>::const_iterator itr=checkedPools.begin(); itr!=checkedPools.end(); ++itr) ss << *itr << " "; ss << "create(s) a circular reference, which can cause the server to freeze.\nRemoving the last link between mother pool " << poolItr->first << " and child pool " << poolItr->second; sLog.outLog(LOG_DB_ERR, "%s", ss.str().c_str()); mPoolPoolGroups[poolItr->second].RemoveOneRelation(poolItr->first); mPoolSearchMap.erase(poolItr); --count; break; } } } sLog.outString(); sLog.outString( ">> Loaded %u pools in mother pools", count ); } }
void WorldSession::HandleSendMail(WorldPacket & recv_data) { CHECK_PACKET_SIZE(recv_data,8+1+1+1+4+4+1+4+4+8+1); ObjectGuid mailboxGuid; uint64 unk3; std::string receiver, subject, body; uint32 unk1, unk2, money, COD; uint8 unk4; recv_data >> mailboxGuid; recv_data >> receiver; // recheck CHECK_PACKET_SIZE(recv_data, 8+(receiver.size()+1)+1+1+4+4+1+4+4+8+1); recv_data >> subject; // recheck CHECK_PACKET_SIZE(recv_data, 8+(receiver.size()+1)+(subject.size()+1)+1+4+4+1+4+4+8+1); recv_data >> body; // recheck CHECK_PACKET_SIZE(recv_data, 8+(receiver.size()+1)+(subject.size()+1)+(body.size()+1)+4+4+1+4+4+8+1); recv_data >> unk1; // stationery? recv_data >> unk2; // 0x00000000 uint8 items_count; recv_data >> items_count; // attached items count if (items_count > MAX_MAIL_ITEMS) // client limit { GetPlayer()->SendMailResult(0, MAIL_SEND, MAIL_ERR_TOO_MANY_ATTACHMENTS); recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam return; } // recheck CHECK_PACKET_SIZE(recv_data, 8+(receiver.size()+1)+(subject.size()+1)+(body.size()+1)+4+4+1+items_count*(1+8)+4+4+8+1); ObjectGuid itemGuids[MAX_MAIL_ITEMS]; for (uint8 i = 0; i < items_count; ++i) { recv_data.read_skip<uint8>(); // item slot in mail, not used recv_data >> itemGuids[i]; } recv_data >> money >> COD; // money and cod recv_data >> unk3; // const 0 recv_data >> unk4; // const 0 // packet read complete, now do check if (!CheckMailBox(mailboxGuid)) return; items_count = 0; // remove duplicates, after this items_count will contains real items count { ObjectGuid tmpItemGuids[MAX_MAIL_ITEMS]; bool inTable = false; for (uint8 i = 0; i < MAX_MAIL_ITEMS; ++i) { if (itemGuids[i].IsEmpty()) continue; inTable = false; for (uint8 j = 0; j < MAX_MAIL_ITEMS; ++j) { if (tmpItemGuids[j].IsEmpty()) break; if (tmpItemGuids[j] == itemGuids[i]) { inTable = true; break; } } if (!inTable) { tmpItemGuids[items_count] = itemGuids[i]; ++items_count; } itemGuids[i].Clear(); } for (uint8 i = 0; i < items_count; ++i) itemGuids[i] = tmpItemGuids[i]; } if (receiver.empty()) return; Player* pl = _player; ObjectGuid rc; if (normalizePlayerName(receiver)) rc = sObjectMgr.GetPlayerGUIDByName(receiver); if (!rc) { sLog.outDetail("Player %u is sending mail to %s (GUID: not existed!) with subject %s and body %s includes %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", pl->GetGUIDLow(), receiver.c_str(), subject.c_str(), body.c_str(), items_count, money, COD, unk1, unk2); pl->SendMailResult(0, 0, MAIL_ERR_RECIPIENT_NOT_FOUND); return; } sLog.outDetail("Player %u is sending mail to %s (GUID: %u) with subject %s and body %s includes %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", pl->GetGUIDLow(), receiver.c_str(), GUID_LOPART(rc), subject.c_str(), body.c_str(), items_count, money, COD, unk1, unk2); if (pl->GetGUID() == rc) { pl->SendMailResult(0, 0, MAIL_ERR_CANNOT_SEND_TO_SELF); return; } uint32 reqmoney = money + 30; if (items_count) reqmoney = money + (30 * items_count); if (pl->GetMoney() < reqmoney) { pl->SendMailResult(0, 0, MAIL_ERR_NOT_ENOUGH_MONEY); return; } Player *receive = sObjectMgr.GetPlayer(rc); uint32 rc_team = 0; uint8 mails_count = 0; //do not allow to send to one player more than 100 mails if (receive) { rc_team = receive->GetTeam(); mails_count = receive->GetMailSize(); } else { rc_team = sObjectMgr.GetPlayerTeamByGUID(rc); QueryResultAutoPtr result = RealmDataDatabase.PQuery("SELECT COUNT(*) FROM mail WHERE receiver = '%u'", GUID_LOPART(rc)); if (result) { Field *fields = result->Fetch(); mails_count = fields[0].GetUInt32(); } } //do not allow to have more than 100 mails in mailbox.. mails count is in opcode uint8!!! - so max can be 255.. if (mails_count > 100) { pl->SendMailResult(0, 0, MAIL_ERR_INTERNAL_ERROR); return; } // test the receiver's Faction... if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_MAIL) && pl->GetTeam() != rc_team && !HasPermissions(PERM_GMT)) { pl->SendMailResult(0, 0, MAIL_ERR_NOT_YOUR_TEAM); return; } Item* items[MAX_MAIL_ITEMS]; for(uint8 i = 0; i < items_count; ++i) { if (!itemGuids[i].IsItem()) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } if (!itemGuids[i].GetCounter()) { pl->SendMailResult(0, 0, MAIL_ERR_INTERNAL_ERROR); return; } Item* item = pl->GetItemByGuid(itemGuids[i]); // prevent sending bag with items (cheat: can be placed in bag after adding equipped empty bag to mail) if(!item) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } if (!item->CanBeTraded()) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); return; } if ((item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_CONJURED) || item->GetUInt32Value(ITEM_FIELD_DURATION))) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); return; } if (COD && item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED)) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANT_SEND_WRAPPED_COD); return; } if (item->IsBag() && !((Bag*)item)->IsEmpty()) { pl->SendMailResult(0, 0, MAIL_ERR_INTERNAL_ERROR); return; } items[i] = item; } pl->SendMailResult(0, MAIL_SEND, MAIL_OK); pl->ModifyMoney(-int32(reqmoney)); bool needItemDelay = false; MailDraft draft(subject, body); uint32 rc_account = 0; if (receive) rc_account = receive->GetSession()->GetAccountId(); else rc_account = sObjectMgr.GetPlayerAccountIdByGUID(rc); if (items_count > 0 || money > 0) { if (items_count > 0) { for(uint8 i = 0; i < items_count; ++i) { Item* item = items[i]; if (!item) continue; if (HasPermissions(PERM_GMT) && sWorld.getConfig(CONFIG_GM_LOG_TRADE)) { sLog.outCommand(GetAccountId(), "GM %s (Account: %u) mail item: %s (Entry: %u Count: %u) to player: %s (Account: %u)", GetPlayerName(), GetAccountId(), item->GetProto()->Name1, item->GetEntry(), item->GetCount(), receiver.c_str(), rc_account); } sLog.outLog(LOG_TRADE, "Player %s (Account: %u) mail item: %s (Entry: %u Count: %u) to player: %s (Account: %u)", GetPlayerName(), GetAccountId(), item->GetProto()->Name1, item->GetEntry(), item->GetCount(), receiver.c_str(), rc_account); pl->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true); RealmDataDatabase.BeginTransaction(); item->DeleteFromInventoryDB(); //deletes item from character's inventory item->SaveToDB(); // recursive and not have transaction guard into self, item not in inventory and can be save standalone // owner in data will set at mail receive and item extracting RealmDataDatabase.PExecute("UPDATE item_instance SET owner_guid = '%u' WHERE guid='%u'", rc.GetCounter(), item->GetGUIDLow()); RealmDataDatabase.CommitTransaction(); draft.AddItem(item); } // if item send to character at another account, then apply item delivery delay needItemDelay = pl->GetSession()->GetAccountId() != rc_account; } if (money > 0) { if (HasPermissions(PERM_GMT) && sWorld.getConfig(CONFIG_GM_LOG_TRADE)) { sLog.outCommand(GetAccountId(),"GM %s (Account: %u) mail money: %u to player: %s (Account: %u)", GetPlayerName(), GetAccountId(), money, receiver.c_str(), rc_account); } if (_player->GetSession()->IsAccountFlagged(ACC_SPECIAL_LOG)) { sLog.outLog(LOG_SPECIAL, "Player %s (Account: %u) mail money: %u to player: %s (Account: %u)", GetPlayerName(), GetAccountId(), money, receiver.c_str(), rc_account); } sLog.outLog(LOG_TRADE, "Player %s (Account: %u) mail money: %u to player: %s (Account: %u)", GetPlayerName(), GetAccountId(), money, receiver.c_str(), rc_account); } } sLog.outLog(LOG_MAIL, "Player %s (Account: %u) sent mail to player: %s (Account: %u) with subject: %s and body: %s", GetPlayerName(), GetAccountId(), receiver.c_str(), rc_account, subject.c_str(), body.c_str()); // If theres is an item, there is a one hour delivery delay if sent to another account's character. uint32 deliver_delay = needItemDelay ? sWorld.getConfig(CONFIG_MAIL_DELIVERY_DELAY) : 0; // If GM sends mail to player - deliver_delay must be zero if (deliver_delay && HasPermissions(PERM_GMT) && sWorld.getConfig(CONFIG_GM_MAIL)) deliver_delay = 0; // will delete item or place to receiver mail list draft .SetMoney(money) .SetCOD(COD) .SendMailTo(MailReceiver(receive, rc), pl, body.empty() ? MAIL_CHECK_MASK_COPIED : MAIL_CHECK_MASK_HAS_BODY, deliver_delay); RealmDataDatabase.BeginTransaction(); pl->SaveInventoryAndGoldToDB(); RealmDataDatabase.CommitTransaction(); }
void WorldSession::HandleTurnInPetitionOpcode(WorldPacket & recv_data) { CHECK_PACKET_SIZE(recv_data, 8); sLog.outDebug("Received opcode CMSG_TURN_IN_PETITION"); // ok //recv_data.hexlike(); WorldPacket data; uint64 petitionguid; uint32 ownerguidlo; uint32 type; std::string name; recv_data >> petitionguid; sLog.outDebug("Petition %u turned in by %u", GUID_LOPART(petitionguid), _player->GetGUIDLow()); // data QueryResultAutoPtr result = RealmDataDatabase.PQuery("SELECT ownerguid, name, type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); if (result) { Field *fields = result->Fetch(); ownerguidlo = fields[0].GetUInt32(); name = fields[1].GetCppString(); type = fields[2].GetUInt32(); } else { sLog.outLog(LOG_DEFAULT, "ERROR: petition table has broken data!"); return; } if (type == 9) { if (_player->GetGuildId()) { data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4); data << (uint32)PETITION_TURN_ALREADY_IN_GUILD; // already in guild _player->SendPacketToSelf(&data); return; } } else { uint8 slot = ArenaTeam::GetSlotByType(type); if (slot >= MAX_ARENA_SLOT) return; if (_player->GetArenaTeamId(slot)) { //data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4); //data << (uint32)PETITION_TURN_ALREADY_IN_GUILD; // already in guild //_player->BroadcastPacketToSelf(&data); SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ALREADY_IN_ARENA_TEAM); return; } } if (_player->GetGUIDLow() != ownerguidlo) return; // signs uint8 signs; result = RealmDataDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); if (result) signs = result->GetRowCount(); else signs = 0; uint32 count; //if(signs < sWorld.getConfig(CONFIG_MIN_PETITION_SIGNS)) if (type == 9) count = sWorld.getConfig(CONFIG_MIN_PETITION_SIGNS); else count = type-1; if (signs < count) { data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4); data << (uint32)PETITION_TURN_NEED_MORE_SIGNATURES; // need more signatures... SendPacket(&data); return; } if (type == 9) { if (sGuildMgr.GetGuildByName(name)) { SendGuildCommandResult(GUILD_CREATE_S, name, GUILD_NAME_EXISTS); return; } } else { if (sObjectMgr.GetArenaTeamByName(name)) { SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_EXISTS_S); return; } } // and at last charter item check Item *item = _player->GetItemByGuid(petitionguid); if (!item) return; // OK! // delete charter item _player->DestroyItem(item->GetBagSlot(),item->GetSlot(), true); if (type == 9) // create guild { Guild* guild = new Guild; if (!guild->create(_player->GetGUID(), name)) { delete guild; return; } // register guild and add guildmaster sGuildMgr.AddGuild(guild); // add members for (uint8 i = 0; i < signs; ++i) { Field* fields = result->Fetch(); guild->AddMember(fields[0].GetUInt64(), guild->GetLowestRank()); result->NextRow(); } } else // or arena team { ArenaTeam* at = new ArenaTeam; if (!at->Create(_player->GetGUID(), type, name)) { sLog.outLog(LOG_DEFAULT, "ERROR: PetitionsHandler: arena team create failed."); delete at; return; } CHECK_PACKET_SIZE(recv_data, 8+5*4); uint32 icon, iconcolor, border, bordercolor, backgroud; recv_data >> backgroud >> icon >> iconcolor >> border >> bordercolor; at->SetEmblem(backgroud, icon, iconcolor, border, bordercolor); // register team and add captain sObjectMgr.AddArenaTeam(at); sLog.outDebug("PetitonsHandler: arena team added to objmrg"); // add members for (uint8 i = 0; i < signs; ++i) { Field* fields = result->Fetch(); uint64 memberGUID = fields[0].GetUInt64(); sLog.outDebug("PetitionsHandler: adding arena member %u", GUID_LOPART(memberGUID)); at->AddMember(memberGUID); result->NextRow(); } } RealmDataDatabase.BeginTransaction(); RealmDataDatabase.PExecute("DELETE FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); RealmDataDatabase.PExecute("DELETE FROM petition_sign WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); RealmDataDatabase.CommitTransaction(); // created sLog.outDebug("TURN IN PETITION GUID %u", GUID_LOPART(petitionguid)); data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4); data << (uint32)PETITION_TURN_OK; SendPacket(&data); }
void WorldSession::HandleOfferPetitionOpcode(WorldPacket & recv_data) { CHECK_PACKET_SIZE(recv_data, 4+8+8); sLog.outDebug("Received opcode CMSG_OFFER_PETITION"); // ok //recv_data.hexlike(); uint8 signs = 0; uint64 petitionguid, plguid; uint32 type, junk; Player *player; recv_data >> junk; // this is not petition type! recv_data >> petitionguid; // petition guid recv_data >> plguid; // player guid player = ObjectAccessor::FindPlayer(plguid); if (!player) return; QueryResultAutoPtr result = RealmDataDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); if (!result) return; Field *fields = result->Fetch(); type = fields[0].GetUInt32(); sLog.outDebug("OFFER PETITION: type %u, GUID1 %u, to player id: %u", type, GUID_LOPART(petitionguid), GUID_LOPART(plguid)); if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != player->GetTeam()) { if (type != 9) SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED); else SendGuildCommandResult(GUILD_CREATE_S, "", GUILD_NOT_ALLIED); return; } if (type != 9) { if (player->getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) { // player is too low level to join an arena team SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, player->GetName(), "", ERR_ARENA_TEAM_PLAYER_TO_LOW); return; } uint8 slot = ArenaTeam::GetSlotByType(type); if (slot >= MAX_ARENA_SLOT) return; if (player->GetArenaTeamId(slot)) { // player is already in an arena team SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, player->GetName(), "", ERR_ALREADY_IN_ARENA_TEAM_S); return; } if (player->GetArenaTeamIdInvited()) { SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", _player->GetName(), ERR_ALREADY_INVITED_TO_ARENA_TEAM_S); return; } } else { if (player->GetGuildId()) { SendGuildCommandResult(GUILD_INVITE_S, _player->GetName(), ALREADY_IN_GUILD); return; } if (player->GetGuildIdInvited()) { SendGuildCommandResult(GUILD_INVITE_S, _player->GetName(), ALREADY_INVITED_TO_GUILD); return; } } result = RealmDataDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); // result==NULL also correct charter without signs if (result) signs = result->GetRowCount(); WorldPacket data(SMSG_PETITION_SHOW_SIGNATURES, (8+8+4+signs+signs*12)); data << petitionguid; // petition guid data << _player->GetGUID(); // owner guid data << GUID_LOPART(petitionguid); // guild guid (in Trinity always same as GUID_LOPART(petition guid) data << signs; // sign's count for (uint8 i = 1; i <= signs; i++) { Field *fields2 = result->Fetch(); uint64 plguid = fields2[0].GetUInt64(); data << plguid; // Player GUID data << (uint32)0; // there 0 ... result->NextRow(); } player->SendPacketToSelf(&data); }
void WorldSession::HandlePetitionBuyOpcode(WorldPacket & recv_data) { CHECK_PACKET_SIZE(recv_data, 8+8+4+1+5*8+2+1+4+4); sLog.outDebug("Received opcode CMSG_PETITION_BUY"); //recv_data.hexlike(); uint64 guidNPC; uint64 unk1, unk3, unk4, unk5, unk6, unk7; uint32 unk2; std::string name; uint16 unk8; uint8 unk9; uint32 unk10; // selected index uint32 unk11; recv_data >> guidNPC; // NPC GUID recv_data >> unk1; // 0 recv_data >> unk2; // 0 recv_data >> name; // name // recheck CHECK_PACKET_SIZE(recv_data, 8+8+4+(name.size()+1)+5*8+2+1+4+4); recv_data >> unk3; // 0 recv_data >> unk4; // 0 recv_data >> unk5; // 0 recv_data >> unk6; // 0 recv_data >> unk7; // 0 recv_data >> unk8; // 0 recv_data >> unk9; // 0 recv_data >> unk10; // index recv_data >> unk11; // 0 sLog.outDebug("Petitioner with GUID %u tried sell petition: name %s", GUID_LOPART(guidNPC), name.c_str()); // prevent cheating Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guidNPC, UNIT_NPC_FLAG_PETITIONER); if (!pCreature) { sLog.outDebug("WORLD: HandlePetitionBuyOpcode - Unit (GUID: %u) not found or you can't interact with him.", GUID_LOPART(guidNPC)); return; } // remove fake death if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); uint32 charterid = 0; uint32 cost = 0; 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; } else { // TODO: find correct opcode if (_player->getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) { SendNotification(LANG_ARENA_ONE_TOOLOW, sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)); return; } switch (unk10) { case 1: charterid = ARENA_TEAM_CHARTER_2v2; cost = ARENA_TEAM_CHARTER_2v2_COST; type = 2; // 2v2 break; case 2: charterid = ARENA_TEAM_CHARTER_3v3; cost = ARENA_TEAM_CHARTER_3v3_COST; type = 3; // 3v3 break; case 3: charterid = ARENA_TEAM_CHARTER_5v5; cost = ARENA_TEAM_CHARTER_5v5_COST; type = 5; // 5v5 break; default: sLog.outDebug("unknown selection at buy petition: %u", unk10); return; } if (_player->GetArenaTeamId(unk10-1)) { SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ALREADY_IN_ARENA_TEAM); return; } } if (type == 9) { if (sGuildMgr.GetGuildByName(name)) { SendGuildCommandResult(GUILD_CREATE_S, name, GUILD_NAME_EXISTS); return; } if (sObjectMgr.IsReservedName(name) || !ObjectMgr::IsValidCharterName(name)) { SendGuildCommandResult(GUILD_CREATE_S, name, GUILD_NAME_INVALID); return; } } else { if (sObjectMgr.GetArenaTeamByName(name)) { SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_EXISTS_S); return; } if (sObjectMgr.IsReservedName(name) || !ObjectMgr::IsValidCharterName(name)) { SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_INVALID); return; } } ItemPrototype const *pProto = ObjectMgr::GetItemPrototype(charterid); if (!pProto) { _player->SendBuyError(BUY_ERR_CANT_FIND_ITEM, NULL, charterid, 0); return; } if (_player->GetMoney() < cost) { //player hasn't got enough money _player->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, charterid, 0); return; } ItemPosCountVec dest; uint8 msg = _player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, charterid, pProto->BuyCount); if (msg != EQUIP_ERR_OK) { _player->SendBuyError(msg, pCreature, charterid, 0); return; } _player->ModifyMoney(-(int32)cost); Item *charter = _player->StoreNewItem(dest, charterid, true); if (!charter) return; charter->SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1, charter->GetGUIDLow()); // ITEM_FIELD_ENCHANTMENT_1_1 is guild/arenateam id // ITEM_FIELD_ENCHANTMENT_1_1+1 is current signatures count (showed on item) charter->SetState(ITEM_CHANGED, _player); _player->SendNewItem(charter, 1, true, false); // a petition is invalid, if both the owner and the type matches // we checked above, if this player is in an arenateam, so this must be // datacorruption QueryResultAutoPtr result = RealmDataDatabase.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 petitions with the same guid as this one ssInvalidPetitionGUIDs << "'" << charter->GetGUIDLow() << "'"; sLog.outDebug("Invalid petition GUIDs: %s", ssInvalidPetitionGUIDs.str().c_str()); RealmDataDatabase.escape_string(name); RealmDataDatabase.BeginTransaction(); RealmDataDatabase.PExecute("DELETE FROM petition WHERE petitionguid IN (%s)", ssInvalidPetitionGUIDs.str().c_str()); RealmDataDatabase.PExecute("DELETE FROM petition_sign WHERE petitionguid IN (%s)", ssInvalidPetitionGUIDs.str().c_str()); RealmDataDatabase.PExecute("INSERT INTO petition (ownerguid, petitionguid, name, type) VALUES ('%u', '%u', '%s', '%u')", _player->GetGUIDLow(), charter->GetGUIDLow(), name.c_str(), type); RealmDataDatabase.CommitTransaction(); }
void WorldSession::HandlePetitionSignOpcode(WorldPacket & recv_data) { CHECK_PACKET_SIZE(recv_data, 8+1); sLog.outDebug("Received opcode CMSG_PETITION_SIGN"); // ok //recv_data.hexlike(); Field *fields; uint64 petitionguid; uint8 unk; recv_data >> petitionguid; // petition guid recv_data >> unk; QueryResultAutoPtr result = RealmDataDatabase.PQuery( "SELECT ownerguid, " " (SELECT COUNT(playerguid) FROM petition_sign WHERE petition_sign.petitionguid = '%u') AS signs, " " type " "FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid), GUID_LOPART(petitionguid)); if (!result) { sLog.outLog(LOG_DEFAULT, "ERROR: any petition on server..."); return; } fields = result->Fetch(); uint64 ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); uint8 signs = fields[1].GetUInt8(); uint32 type = fields[2].GetUInt32(); uint32 plguidlo = _player->GetGUIDLow(); if (GUID_LOPART(ownerguid) == plguidlo) return; // not let enemies sign guild charter if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != sObjectMgr.GetPlayerTeamByGUID(ownerguid)) { if (type != 9) SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED); else SendGuildCommandResult(GUILD_CREATE_S, "", GUILD_NOT_ALLIED); return; } if (type != 9) { if (_player->getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) { SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", _player->GetName(), ERR_ARENA_TEAM_PLAYER_TO_LOW); return; } uint8 slot = ArenaTeam::GetSlotByType(type); if (slot >= MAX_ARENA_SLOT) return; if (_player->GetArenaTeamId(slot)) { SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", _player->GetName(), ERR_ALREADY_IN_ARENA_TEAM_S); return; } if (_player->GetArenaTeamIdInvited()) { SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", _player->GetName(), ERR_ALREADY_INVITED_TO_ARENA_TEAM_S); return; } } else { if (_player->GetGuildId()) { SendGuildCommandResult(GUILD_INVITE_S, _player->GetName(), ALREADY_IN_GUILD); return; } if (_player->GetGuildIdInvited()) { SendGuildCommandResult(GUILD_INVITE_S, _player->GetName(), ALREADY_INVITED_TO_GUILD); return; } } 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 = RealmDataDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE player_account = '%u' AND petitionguid = '%u'", GetAccountId(), GUID_LOPART(petitionguid)); if (result) { WorldPacket data(SMSG_PETITION_SIGN_RESULTS, (8+8+4)); data << petitionguid; data << _player->GetGUID(); data << (uint32)PETITION_SIGN_ALREADY_SIGNED; // close at signer side SendPacket(&data); // update for owner if online if (Player *owner = sObjectMgr.GetPlayer(ownerguid)) owner->SendPacketToSelf(&data); return; } RealmDataDatabase.PExecute("INSERT INTO petition_sign (ownerguid,petitionguid, playerguid, player_account) VALUES ('%u', '%u', '%u','%u')", GUID_LOPART(ownerguid),GUID_LOPART(petitionguid), plguidlo,GetAccountId()); sLog.outDebug("PETITION SIGN: GUID %u by player: %s (GUID: %u Account: %u)", GUID_LOPART(petitionguid), _player->GetName(),plguidlo,GetAccountId()); WorldPacket data(SMSG_PETITION_SIGN_RESULTS, (8+8+4)); data << petitionguid; data << _player->GetGUID(); data << (uint32)PETITION_SIGN_OK; // close at signer side SendPacket(&data); // update signs count on charter, required testing... //Item *item = _player->GetItemByGuid(petitionguid)); //if(item) // item->SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1+1, signs); // update for owner if online if (Player *owner = sObjectMgr.GetPlayer(ownerguid)) owner->SendPacketToSelf(&data); }
void WorldSession::HandlePetitionRenameOpcode(WorldPacket & recv_data) { CHECK_PACKET_SIZE(recv_data, 8+1); sLog.outDebug("Received opcode MSG_PETITION_RENAME"); // ok //recv_data.hexlike(); uint64 petitionguid; uint32 type; std::string newname; recv_data >> petitionguid; // guid recv_data >> newname; // new name Item *item = _player->GetItemByGuid(petitionguid); if (!item) return; QueryResultAutoPtr result = RealmDataDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); if (result) { Field* fields = result->Fetch(); type = fields[0].GetUInt32(); } else { sLog.outDebug("CMSG_PETITION_QUERY failed for petition (GUID: %u)", GUID_LOPART(petitionguid)); return; } if (type == 9) { if (sGuildMgr.GetGuildByName(newname)) { SendGuildCommandResult(GUILD_CREATE_S, newname, GUILD_NAME_EXISTS); return; } if (sObjectMgr.IsReservedName(newname) || !ObjectMgr::IsValidCharterName(newname)) { SendGuildCommandResult(GUILD_CREATE_S, newname, GUILD_NAME_INVALID); return; } } else { if (sObjectMgr.GetArenaTeamByName(newname)) { SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newname, "", ERR_ARENA_TEAM_NAME_EXISTS_S); return; } if (sObjectMgr.IsReservedName(newname) || !ObjectMgr::IsValidCharterName(newname)) { SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newname, "", ERR_ARENA_TEAM_NAME_INVALID); return; } } std::string db_newname = newname; RealmDataDatabase.escape_string(db_newname); RealmDataDatabase.PExecute("UPDATE petition SET name = '%s' WHERE petitionguid = '%u'", db_newname.c_str(), GUID_LOPART(petitionguid)); sLog.outDebug("Petition (GUID: %u) renamed to '%s'", GUID_LOPART(petitionguid), newname.c_str()); WorldPacket data(MSG_PETITION_RENAME, (8+newname.size()+1)); data << petitionguid; data << newname; SendPacket(&data); }
/// Logon Challenge command handler bool AuthSocket::_HandleLogonChallenge() { DEBUG_LOG("Entering _HandleLogonChallenge"); if (recv_len() < sizeof(sAuthLogonChallenge_C)) return false; ///- Read the first 4 bytes (header) to get the length of the remaining of the packet std::vector<uint8> buf; buf.resize(4); recv((char *)&buf[0], 4); EndianConvert(*((uint16*)(buf[0]))); uint16 remaining = ((sAuthLogonChallenge_C *)&buf[0])->size; DEBUG_LOG("[AuthChallenge] got header, body is %#04x bytes", remaining); if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (recv_len() < remaining)) return false; //No big fear of memory outage (size is int16, i.e. < 65536) buf.resize(remaining + buf.size() + 1); buf[buf.size() - 1] = 0; sAuthLogonChallenge_C *ch = (sAuthLogonChallenge_C*)&buf[0]; ///- Read the remaining of the packet recv((char *)&buf[4], remaining); DEBUG_LOG("[AuthChallenge] got full packet, %#04x bytes", ch->size); DEBUG_LOG("[AuthChallenge] name(%d): '%s'", ch->I_len, ch->I); // BigEndian code, nop in little endian case // size already converted EndianConvert(*((uint32*)(&ch->gamename[0]))); EndianConvert(ch->build); EndianConvert(*((uint32*)(&ch->platform[0]))); EndianConvert(*((uint32*)(&ch->os[0]))); EndianConvert(*((uint32*)(&ch->country[0]))); EndianConvert(ch->timezone_bias); EndianConvert(*((uint32*)(&ch->ip[0]))); std::stringstream tmpLocalIp; tmpLocalIp << (uint32)ch->ip[0] << "." << (uint32)ch->ip[1] << "." << (uint32)ch->ip[2] << "." << (uint32)ch->ip[3]; localIp_ = tmpLocalIp.str(); ByteBuffer pkt; _login = (const char*)ch->I; _build = ch->build; operatingSystem_ = (const char*)ch->os; // Restore string order as its byte order is reversed std::reverse(operatingSystem_.begin(), operatingSystem_.end()); if (operatingSystem_.size() > 4 || (operatingSystem_ != "Win" && operatingSystem_ != "OSX" && (sRealmList.ChatboxOsName == "" || operatingSystem_ != sRealmList.ChatboxOsName))){ sLog.outLog(LOG_WARDEN, "Client %s got unsupported operating system (%s)", _login.c_str(), operatingSystem_.c_str()); return false; } ///- Normalize account name //utf8ToUpperOnlyLatin(_login); -- client already send account in expected form //Escape the user login to avoid further SQL injection //Memory will be freed on AuthSocket object destruction _safelogin = _login; AccountsDatabase.escape_string(_safelogin); pkt << (uint8) CMD_AUTH_LOGON_CHALLENGE; pkt << (uint8) 0x00; std::string address = get_remote_address(); #ifdef REGEX_NAMESPACE for (PatternList::const_iterator i = pattern_banned.begin(); i != pattern_banned.end(); ++i) { if (REGEX_NAMESPACE::regex_match(address.c_str(), i->first) && REGEX_NAMESPACE::regex_match(localIp_.c_str(), i->second)) { pkt<< (uint8) WOW_FAIL_UNKNOWN_ACCOUNT; send((char const*)pkt.contents(), pkt.size()); return true; } } #endif ///- Verify that this IP is not in the ip_banned table // No SQL injection possible (paste the IP address as passed by the socket) AccountsDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); AccountsDatabase.escape_string(address); //Delete ViP AccountsDatabase.Execute("UPDATE account_permissions SET permission_mask = 1 WHERE unsetdate<=UNIX_TIMESTAMP() AND unsetdate<>setdate"); QueryResultAutoPtr result = AccountsDatabase.PQuery("SELECT * FROM ip_banned WHERE ip = '%s'", address.c_str()); if (result) // ip banned { sLog.outBasic("[AuthChallenge] Banned ip %s tries to login!", get_remote_address().c_str()); pkt << uint8(WOW_FAIL_BANNED); send((char const*)pkt.contents(), pkt.size()); return true; } ///- Get the account details from the account table // No SQL injection (escaped user name) result = AccountsDatabase.PQuery("SELECT pass_hash, account.account_id, account_state_id, last_ip, permission_mask, email " "FROM account JOIN account_permissions ON account.account_id = account_permissions.account_id " "WHERE username = '******'", _safelogin.c_str()); if (!result) // account not exists { pkt<< uint8(WOW_FAIL_UNKNOWN_ACCOUNT); send((char const*)pkt.contents(), pkt.size()); return true; } Field * fields = result->Fetch(); ///- If the IP is 'locked', check that the player comes indeed from the correct IP address switch (fields[2].GetUInt8()) { case ACCOUNT_STATE_IP_LOCKED: { DEBUG_LOG("[AuthChallenge] Account '%s' is locked to IP - '%s'", _login.c_str(), (*result)[3].GetString()); DEBUG_LOG("[AuthChallenge] Player address is '%s'", get_remote_address().c_str()); if (strcmp(fields[4].GetString(), get_remote_address().c_str())) { DEBUG_LOG("[AuthChallenge] Account IP differs"); pkt << (uint8) WOW_FAIL_LOCKED_ENFORCED; send((char const*)pkt.contents(), pkt.size()); return true; } else { DEBUG_LOG("[AuthChallenge] Account IP matches"); } break; } case ACCOUNT_STATE_FROZEN: { pkt << uint8(WOW_FAIL_SUSPENDED); send((char const*)pkt.contents(), pkt.size()); return true; } default: DEBUG_LOG("[AuthChallenge] Account '%s' is not locked to ip or frozen", _login.c_str()); break; } ///- If the account is banned, reject the logon attempt QueryResultAutoPtr banresult = AccountsDatabase.PQuery("SELECT punishment_date, expiration_date " "FROM account_punishment " "WHERE account_id = '%u' AND punishment_type_id = '%u' AND (punishment_date = expiration_date OR expiration_date > UNIX_TIMESTAMP())", (*result)[1].GetUInt32(), PUNISHMENT_BAN); if (banresult) { if((*banresult)[0].GetUInt64() == (*banresult)[1].GetUInt64()) { pkt << uint8(WOW_FAIL_BANNED); sLog.outBasic("[AuthChallenge] Banned account %s tries to login!", _login.c_str ()); } else { pkt << uint8(WOW_FAIL_SUSPENDED); sLog.outBasic("[AuthChallenge] Temporarily banned account %s tries to login!", _login.c_str ()); } send((char const*)pkt.contents(), pkt.size()); return true; } QueryResultAutoPtr emailbanresult = AccountsDatabase.PQuery("SELECT email FROM email_banned WHERE email = '%s'", (*result)[5].GetString()); if (emailbanresult) { pkt << uint8(WOW_FAIL_BANNED); sLog.outBasic("[AuthChallenge] Account %s with banned email %s tries to login!", _login.c_str (), (*emailbanresult)[0].GetString()); send((char const*)pkt.contents(), pkt.size()); return true; } ///- Get the password from the account table, upper it, and make the SRP6 calculation std::string rI = fields[0].GetCppString(); _SetVSFields(rI); b.SetRand(19 * 8); BigNumber gmod = g.ModExp(b, N); B = ((v * 3) + gmod) % N; ASSERT(gmod.GetNumBytes() <= 32); BigNumber unk3; unk3.SetRand(16 * 8); ///- Fill the response packet with the result pkt << uint8(WOW_SUCCESS); // B may be calculated < 32B so we force minimal length to 32B pkt.append(B.AsByteArray(32), 32); // 32 bytes pkt << uint8(1); pkt.append(g.AsByteArray(), 1); pkt << uint8(32); pkt.append(N.AsByteArray(32), 32); pkt.append(s.AsByteArray(), s.GetNumBytes());// 32 bytes pkt.append(unk3.AsByteArray(16), 16); uint8 securityFlags = 0; pkt << uint8(securityFlags); // security flags (0x0...0x04) if (securityFlags & 0x01) // PIN input { pkt << uint32(0); pkt << uint64(0) << uint64(0); // 16 bytes hash? } if (securityFlags & 0x02) // Matrix input { pkt << uint8(0); pkt << uint8(0); pkt << uint8(0); pkt << uint8(0); pkt << uint64(0); } if (securityFlags & 0x04) // Security token input pkt << uint8(1); accountPermissionMask_ = fields[4].GetUInt64(); _localizationName.resize(4); for (int i = 0; i < 4; ++i) _localizationName[i] = ch->country[4-i-1]; sLog.outBasic("[AuthChallenge] account %s is using '%c%c%c%c' locale (%u)", _login.c_str (), ch->country[3], ch->country[2], ch->country[1], ch->country[0], GetLocaleByName(_localizationName)); send((char const*)pkt.contents(), pkt.size()); return true; }
/// Logon Proof command handler bool AuthSocket::_HandleLogonProof() { DEBUG_LOG("Entering _HandleLogonProof"); ///- Read the packet sAuthLogonProof_C lp; if(!recv((char *)&lp, sizeof(sAuthLogonProof_C))) return false; ///- Check if the client has one of the expected version numbers bool valid_version = FindBuildInfo(_build) != NULL; /// <ul><li> If the client has no valid version if(!valid_version) { if (this->patch_ != ACE_INVALID_HANDLE) return false; ///- Check if we have the apropriate patch on the disk // file looks like: 65535enGB.mpq char tmp[64]; snprintf(tmp, 24, "./patches/%d%s.mpq", _build, _localizationName.c_str()); char filename[PATH_MAX]; if (ACE_OS::realpath(tmp, filename) != NULL) { patch_ = ACE_OS::open(filename, GENERIC_READ | FILE_FLAG_SEQUENTIAL_SCAN); } if (patch_ == ACE_INVALID_HANDLE) { // no patch found ByteBuffer pkt; pkt << (uint8) CMD_AUTH_LOGON_CHALLENGE; pkt << (uint8) 0x00; pkt << (uint8) WOW_FAIL_VERSION_INVALID; DEBUG_LOG("[AuthChallenge] %u is not a valid client version!", _build); DEBUG_LOG("[AuthChallenge] Patch %s not found", tmp); send((char const*)pkt.contents(), pkt.size()); return true; } XFER_INIT xferh; ACE_OFF_T file_size = ACE_OS::filesize(this->patch_); if (file_size == -1) { close_connection(); return false; } if (!PatchCache::instance()->GetHash(tmp, (uint8*)&xferh.md5)) { // calculate patch md5, happens if patch was added while realmd was running PatchCache::instance()->LoadPatchMD5(tmp); PatchCache::instance()->GetHash(tmp, (uint8*)&xferh.md5); } uint8 data[2] = { CMD_AUTH_LOGON_PROOF, WOW_FAIL_VERSION_UPDATE}; send((const char*)data, sizeof(data)); memcpy(&xferh, "0\x05Patch", 7); xferh.cmd = CMD_XFER_INITIATE; xferh.file_size = file_size; send((const char*)&xferh, sizeof(xferh)); return true; } /// </ul> ///- Continue the SRP6 calculation based on data received from the client BigNumber A; A.SetBinary(lp.A, 32); // SRP safeguard: abort if A==0 if (A.isZero()) return false; Sha1Hash sha; sha.UpdateBigNumbers(&A, &B, NULL); sha.Finalize(); BigNumber u; u.SetBinary(sha.GetDigest(), 20); BigNumber S = (A * (v.ModExp(u, N))).ModExp(b, N); uint8 t[32]; uint8 t1[16]; uint8 vK[40]; memcpy(t, S.AsByteArray(32), 32); for (int i = 0; i < 16; ++i) { t1[i] = t[i * 2]; } sha.Initialize(); sha.UpdateData(t1, 16); sha.Finalize(); for (int i = 0; i < 20; ++i) { vK[i * 2] = sha.GetDigest()[i]; } for (int i = 0; i < 16; ++i) { t1[i] = t[i * 2 + 1]; } sha.Initialize(); sha.UpdateData(t1, 16); sha.Finalize(); for (int i = 0; i < 20; ++i) { vK[i * 2 + 1] = sha.GetDigest()[i]; } K.SetBinary(vK, 40); uint8 hash[20]; sha.Initialize(); sha.UpdateBigNumbers(&N, NULL); sha.Finalize(); memcpy(hash, sha.GetDigest(), 20); sha.Initialize(); sha.UpdateBigNumbers(&g, NULL); sha.Finalize(); for (int i = 0; i < 20; ++i) { hash[i] ^= sha.GetDigest()[i]; } BigNumber t3; t3.SetBinary(hash, 20); sha.Initialize(); sha.UpdateData(_login); sha.Finalize(); uint8 t4[SHA_DIGEST_LENGTH]; memcpy(t4, sha.GetDigest(), SHA_DIGEST_LENGTH); sha.Initialize(); sha.UpdateBigNumbers(&t3, NULL); sha.UpdateData(t4, SHA_DIGEST_LENGTH); sha.UpdateBigNumbers(&s, &A, &B, &K, NULL); sha.Finalize(); BigNumber M; M.SetBinary(sha.GetDigest(), 20); ///- Check if SRP6 results match (password is correct), else send an error if (!memcmp(M.AsByteArray(), lp.M1, 20)) { sLog.outBasic("User '%s' successfully authenticated", _login.c_str()); uint8 OS; if (!strcmp(operatingSystem_.c_str(), "Win")) OS = CLIENT_OS_WIN; else if (!strcmp(operatingSystem_.c_str(), "OSX")) OS = CLIENT_OS_OSX; else if (!strcmp(operatingSystem_.c_str(), "CHA") || !strcmp(operatingSystem_.c_str(), "CHAT")) OS = CLIENT_OS_CHAT; else { OS = CLIENT_OS_UNKNOWN; AccountsDatabase.escape_string(operatingSystem_); sLog.outLog(LOG_WARDEN, "Client %s got unsupported operating system (%s)", _safelogin.c_str(), operatingSystem_.c_str()); } ///- Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account // No SQL injection (escaped user name) and IP address as received by socket const char* K_hex = K.AsHexStr(); QueryResultAutoPtr result = AccountsDatabase.PQuery("SELECT account_id FROM account WHERE username = '******'", _safelogin.c_str()); if (!result) { if (_build > 6005) // > 1.12.2 { char data[4] = { CMD_AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0}; send(data, sizeof(data)); } else { // 1.x not react incorrectly at 4-byte message use 3 as real error char data[2] = { CMD_AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT}; send(data, sizeof(data)); } return true; } uint32 accId = result->Fetch()->GetUInt32(); // direct to be sure that values will be set before character choose, this will slow down logging in a bit ;p AccountsDatabase.DirectPExecute("UPDATE account_session SET session_key = '%s' WHERE account_id = '%u'", K_hex, accId); static SqlStatementID updateAccount; SqlStatement stmt = AccountsDatabase.CreateStatement(updateAccount, "UPDATE account SET last_ip = ?, last_local_ip = ?, last_login = NOW(), locale_id = ?, failed_logins = 0, client_os_version_id = ? WHERE account_id = ?"); std::string tmpIp = get_remote_address(); stmt.addString(tmpIp.c_str()); stmt.addString(localIp_.c_str()); stmt.addUInt8(uint8(GetLocaleByName(_localizationName))); stmt.addUInt8(OS); stmt.addUInt32(accId); stmt.DirectExecute(); OPENSSL_free((void*)K_hex); ///- Finish SRP6 and send the final result to the client sha.Initialize(); sha.UpdateBigNumbers(&A, &M, &K, NULL); sha.Finalize(); SendProof(sha); ///- Set _authed to true! _authed = true; } else { if (_build > 6005) // > 1.12.2 { char data[4] = { CMD_AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0}; send(data, sizeof(data)); } else { // 1.x not react incorrectly at 4-byte message use 3 as real error char data[2] = { CMD_AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT}; send(data, sizeof(data)); } sLog.outBasic("[AuthChallenge] account %s tried to login with wrong password!",_login.c_str ()); uint32 MaxWrongPassCount = sConfig.GetIntDefault("WrongPass.MaxCount", 0); if (MaxWrongPassCount > 0) { static SqlStatementID updateAccountFailedLogins; //Increment number of failed logins by one and if it reaches the limit temporarily ban that account or IP SqlStatement stmt = AccountsDatabase.CreateStatement(updateAccountFailedLogins, "UPDATE account SET failed_logins = failed_logins + 1 WHERE username = ?"); stmt.addString(_login); stmt.Execute(); if (QueryResultAutoPtr loginfail = AccountsDatabase.PQuery("SELECT account_id, failed_logins FROM account WHERE username = '******'", _safelogin.c_str())) { Field* fields = loginfail->Fetch(); uint32 failed_logins = fields[1].GetUInt32(); if (failed_logins >= MaxWrongPassCount) { uint32 WrongPassBanTime = sConfig.GetIntDefault("WrongPass.BanTime", 600); bool WrongPassBanType = sConfig.GetBoolDefault("WrongPass.BanType", false); if (WrongPassBanType) { uint32 acc_id = fields[0].GetUInt32(); AccountsDatabase.PExecute("INSERT INTO account_punishment VALUES ('%u', '%u', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+%u, 'Realm', 'Incorrect password for: %u times. Ban for: %u seconds')", acc_id, PUNISHMENT_BAN, WrongPassBanTime, failed_logins, WrongPassBanTime); sLog.outBasic("[AuthChallenge] account %s got banned for '%u' seconds because it failed to authenticate '%u' times", _login.c_str(), WrongPassBanTime, failed_logins); } else { std::string current_ip = get_remote_address(); AccountsDatabase.escape_string(current_ip); AccountsDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','Realm','Incorrect password for: %u times. Ban for: %u seconds')", current_ip.c_str(), WrongPassBanTime, failed_logins, WrongPassBanTime); sLog.outBasic("[AuthChallenge] IP %s got banned for '%u' seconds because account %s failed to authenticate '%u' times", current_ip.c_str(), WrongPassBanTime, _login.c_str(), failed_logins); } } } } } return true; }
void AuthSocket::LoadRealmlist(ByteBuffer &pkt, uint32 acctid) { switch (_build) { case 5875: // 1.12.1 case 6005: // 1.12.2 { pkt << uint32(0); // unused value pkt << uint8(sRealmList.size()); for (RealmList::RealmMap::const_iterator i = sRealmList.begin(); i != sRealmList.end(); ++i) { uint8 AmountOfCharacters; // No SQL injection. id of realm is controlled by the database. QueryResultAutoPtr result = AccountsDatabase.PQuery( "SELECT characters_count FROM realm_characters WHERE realm_id = '%u' AND account_id = '%u'", i->second.m_ID, acctid); if (result) { Field *fields = result->Fetch(); AmountOfCharacters = fields[0].GetUInt8(); } else AmountOfCharacters = 0; bool ok_build = std::find(i->second.realmbuilds.begin(), i->second.realmbuilds.end(), _build) != i->second.realmbuilds.end(); RealmBuildInfo const* buildInfo = ok_build ? FindBuildInfo(_build) : NULL; if (!buildInfo) buildInfo = &i->second.realmBuildInfo; RealmFlags realmflags = i->second.realmflags; // 1.x clients not support explicitly REALM_FLAG_SPECIFYBUILD, so manually form similar name as show in more recent clients std::string name = i->first; if (realmflags & REALM_FLAG_SPECIFYBUILD) { char buf[20]; snprintf(buf, 20," (%u,%u,%u)", buildInfo->major_version, buildInfo->minor_version, buildInfo->bugfix_version); name += buf; } // Show offline state for unsupported client builds and locked realms (1.x clients not support locked state show) if (!ok_build || !(i->second.requiredPermissionMask & accountPermissionMask_)) realmflags = RealmFlags(realmflags | REALM_FLAG_OFFLINE); pkt << uint32(i->second.icon); // realm type pkt << uint8(realmflags); // realmflags pkt << name; // name pkt << i->second.address; // address pkt << float(i->second.populationLevel); pkt << uint8(AmountOfCharacters); pkt << uint8(i->second.timezone); // realm category pkt << uint8(0x00); // unk, may be realm number/id? } pkt << uint16(0x0002); // unused value (why 2?) break; } case 8606: // 2.4.3 case 10505: // 3.2.2a case 11159: // 3.3.0a case 11403: // 3.3.2 case 11723: // 3.3.3a case 12340: // 3.3.5a default: // and later { pkt << uint32(0); // unused value pkt << uint16(sRealmList.size()); for (RealmList::RealmMap::const_iterator i = sRealmList.begin(); i != sRealmList.end(); ++i) { uint8 AmountOfCharacters; // No SQL injection. id of realm is controlled by the database. QueryResultAutoPtr result = AccountsDatabase.PQuery("SELECT characters_count FROM realm_characters WHERE realm_id = '%u' AND account_id = '%u'", i->second.m_ID, acctid); if (result) { Field *fields = result->Fetch(); AmountOfCharacters = fields[0].GetUInt8(); } else AmountOfCharacters = 0; bool ok_build = std::find(i->second.realmbuilds.begin(), i->second.realmbuilds.end(), _build) != i->second.realmbuilds.end(); RealmBuildInfo const* buildInfo = ok_build ? FindBuildInfo(_build) : NULL; if (!buildInfo) buildInfo = &i->second.realmBuildInfo; uint8 lock = (i->second.requiredPermissionMask & accountPermissionMask_) ? 0 : 1; RealmFlags realmFlags = i->second.realmflags; // Show offline state for unsupported client builds if (!ok_build) realmFlags = RealmFlags(realmFlags | REALM_FLAG_OFFLINE); if (!buildInfo) realmFlags = RealmFlags(realmFlags & ~REALM_FLAG_SPECIFYBUILD); pkt << uint8(i->second.icon); // realm type (this is second column in Cfg_Configs.dbc) pkt << uint8(lock); // flags, if 0x01, then realm locked pkt << uint8(realmFlags); // see enum RealmFlags pkt << i->first; // name pkt << i->second.address; // address pkt << float(i->second.populationLevel); pkt << uint8(AmountOfCharacters); pkt << uint8(i->second.timezone); // realm category (Cfg_Categories.dbc) pkt << uint8(0x2C); // unk, may be realm number/id? if (realmFlags & REALM_FLAG_SPECIFYBUILD) { pkt << uint8(buildInfo->major_version); pkt << uint8(buildInfo->minor_version); pkt << uint8(buildInfo->bugfix_version); pkt << uint16(_build); } } pkt << uint16(0x0010); // unused value (why 10?) break; } } }
bool GossipSelect_custom_gossip_codebox(Player* Player, Creature* Creature, uint32 /*sender*/, uint32 action) { uint32 professions = 0; switch (action) { case GOSSIP_ACTION_INFO_DEF + 2: Player->ADD_GOSSIP_ITEM(0, "Weiter", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); Player->PlayerTalkClass->SendGossipMenu(30001, Creature->GetGUID()); break; case GOSSIP_ACTION_INFO_DEF + 3: Player->ADD_GOSSIP_ITEM(0, "Weiter", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); Player->PlayerTalkClass->SendGossipMenu(30002, Creature->GetGUID()); break; case GOSSIP_ACTION_INFO_DEF + 4: Player->ADD_GOSSIP_ITEM(0, "Weiter", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); Player->PlayerTalkClass->SendGossipMenu(30003, Creature->GetGUID()); break; case GOSSIP_ACTION_INFO_DEF + 5: Player->ADD_GOSSIP_ITEM(0, "Weiter", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); Player->PlayerTalkClass->SendGossipMenu(30004, Creature->GetGUID()); break; case GOSSIP_ACTION_INFO_DEF + 6: Player->ADD_GOSSIP_ITEM(0, "Weiter", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); Player->PlayerTalkClass->SendGossipMenu(30005, Creature->GetGUID()); break; case GOSSIP_ACTION_INFO_DEF + 7: Player->ADD_GOSSIP_ITEM(0, "Weiter", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); Player->PlayerTalkClass->SendGossipMenu(30006, Creature->GetGUID()); break; case GOSSIP_ACTION_INFO_DEF + 8: Player->ADD_GOSSIP_ITEM(0, "Weiter", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); Player->PlayerTalkClass->SendGossipMenu(30007, Creature->GetGUID()); break; case GOSSIP_ACTION_INFO_DEF + 9: Player->ADD_GOSSIP_ITEM(0, "Weiter", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); Player->PlayerTalkClass->SendGossipMenu(30008, Creature->GetGUID()); break; case GOSSIP_ACTION_INFO_DEF + 10: { switch(Player->GetValidForPush()) { case 0: // zu hohes level aber noch einen char frei fuer push { Player->ADD_GOSSIP_ITEM(0, "Schliessen", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 111); Player->PlayerTalkClass->SendGossipMenu(30014, Creature->GetGUID()); return true; } case 1: // zu hohes level und sowieso bereits 2 ueber 60 { Player->ADD_GOSSIP_ITEM(0, "Schliessen", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 111); Player->PlayerTalkClass->SendGossipMenu(30015, Creature->GetGUID()); return true; } case 2: // bereits zu viele auf zu hohem level { Player->ADD_GOSSIP_ITEM(0, "Schliessen", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 111); Player->PlayerTalkClass->SendGossipMenu(30010, Creature->GetGUID()); return true; } case 3: // alles okay, gib feuer { Player->ADD_GOSSIP_ITEM(0, "Setz mich auf Level 60", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); Player->PlayerTalkClass->SendGossipMenu(30009, Creature->GetGUID()); return true; } case 4: // Second Account { Player->ADD_GOSSIP_ITEM(0, "Schliessen", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 111); Player->PlayerTalkClass->SendGossipMenu(30020, Creature->GetGUID()); return true; } default: return false; } } case GOSSIP_ACTION_INFO_DEF + 11: Player->Push(); Player->ADD_GOSSIP_ITEM(0, "Weiter", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 12); Player->PlayerTalkClass->SendGossipMenu(30011, Creature->GetGUID()); break; case GOSSIP_ACTION_INFO_DEF + 111: Player->PlayerTalkClass->CloseGossip(); return false; case GOSSIP_ACTION_INFO_DEF + 12: switch (Player->getClass()) { case CLASS_WARRIOR: Player->ADD_GOSSIP_ITEM(0, "Schadenverursacher", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 13); Player->ADD_GOSSIP_ITEM(0, "Tank", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 14); break; case CLASS_PALADIN: Player->ADD_GOSSIP_ITEM(0, "Schadenverursacher", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 15); // do we realy need a shokadin? // Player->ADD_GOSSIP_ITEM(0, "DD - Shocka", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+151); Player->ADD_GOSSIP_ITEM(0, "Tank", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 16); Player->ADD_GOSSIP_ITEM(0, "Heiler", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 17); break; case CLASS_HUNTER: Player->ADD_GOSSIP_ITEM(0, "Schadenverursacher", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 18); break; case CLASS_ROGUE: Player->ADD_GOSSIP_ITEM(0, "Schadenverursacher", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 19); break; case CLASS_PRIEST: Player->ADD_GOSSIP_ITEM(0, "Schadenverursacher", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 20); Player->ADD_GOSSIP_ITEM(0, "Heiler", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 21); break; case CLASS_SHAMAN: Player->ADD_GOSSIP_ITEM(0, "Schadenverursacher - Verstaerker", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 22); Player->ADD_GOSSIP_ITEM(0, "Schadenverursacher - Elementar", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 23); Player->ADD_GOSSIP_ITEM(0, "Heiler", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 24); break; case CLASS_MAGE: Player->ADD_GOSSIP_ITEM(0, "Schadenverursacher", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 25); break; case CLASS_WARLOCK: Player->ADD_GOSSIP_ITEM(0, "Schadenverursacher", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 26); break; case CLASS_DRUID: Player->ADD_GOSSIP_ITEM(0, "Schadenverursacher - Katze", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 27); Player->ADD_GOSSIP_ITEM(0, "Schadenverursacher - Eule", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 28); Player->ADD_GOSSIP_ITEM(0, "Heiler", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 29); Player->ADD_GOSSIP_ITEM(0, "Tank", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 30); break; } Player->PlayerTalkClass->SendGossipMenu(30012, Creature->GetGUID()); break; case GOSSIP_ACTION_INFO_DEF + 13: { // WARRIOR - DD -fertig // Helm, Kette, Schulter, 0, Brust, Gurt, Beine, Füße, Arme, Hände, Ring, Ring2, Schmuck, Schmuck, Umhang, Waffe, 2HWaffe, Fernk uint16 items[] = {16731, 22340, 16733, 0, 16730, 16736, 16732, 16734, 16735, 16737, 18701, 13098, 7734, 22321, 13397, 22404, 14487, 18680}; Player->EquipForPush(items); if (!Player->HasItemCount(28053, 200, true)) Player->AddItem(28053, 200); Player->ADD_GOSSIP_ITEM(0, "Weiter zu den Berufen", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30013, Creature->GetGUID()); break; } case GOSSIP_ACTION_INFO_DEF + 14: { // WARRIOR - TANK -ü uint16 items[] = {12620,13177,22001,0,18503,21503,22000,20710,21996,14525,22680, 19912,21784,21567,19888,19968,12602,19993}; Player->EquipForPush(items); if (!Player->HasItemCount(28053, 200, true)) Player->AddItem(28053, 200); Player->ADD_GOSSIP_ITEM(0, "Weiter zu den Berufen", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30013, Creature->GetGUID()); break; } case GOSSIP_ACTION_INFO_DEF + 15: { // PALADIN - DD - fertig uint16 items[] = {16727, 22340, 16729, 0, 16726, 16723, 16728, 16725, 16722, 16724, 18701, 13098, 7734, 22321, 13397, 12583, 0, 22401}; Player->EquipForPush(items); Player->ADD_GOSSIP_ITEM(0, "Weiter zu den Berufen", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30013, Creature->GetGUID()); break; } case GOSSIP_ACTION_INFO_DEF + 151: { // PALADIN - DD - Shockadin uint16 items[] = {29969, 25784, 30005, 0, 29789, 29807, 29980, 29786, 30402, 29812, 30339, 25926, 29776, 31617, 25780, 30394, 0, 30227}; Player->EquipForPush(items); Player->ADD_GOSSIP_ITEM(0, "Weiter zu den Berufen", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30013, Creature->GetGUID()); break; } case GOSSIP_ACTION_INFO_DEF + 16: { // PALADIN - TANK -ü uint16 items[] = {23276,21792,18384,0,15413,14620,14623,14621,21996, 23274,22680, 11669,12930,13515,19888,18396,22336,22401}; Player->EquipForPush(items); Player->ADD_GOSSIP_ITEM(0, "Weiter zu den Berufen", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30013, Creature->GetGUID()); break; } case GOSSIP_ACTION_INFO_DEF + 17: { // PALADIN - HEILER -ü uint16 items[] = {12633,18723,14548,0,15047,18702,20266,20711,13969,18527,13178, 16058,18472,12930,18389,22380,22336,23201}; Player->EquipForPush(items); Player->ADD_GOSSIP_ITEM(0, "Weiter zu den Berufen", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30013, Creature->GetGUID()); break; } case GOSSIP_ACTION_INFO_DEF + 18: { // HUNTER - fertig uint16 items[] = {16677, 22340, 16679, 0, 16674, 16680, 16678, 16675, 16681, 16676, 18701, 13098, 7734, 18537, 13397, 13368, 13368, 18680}; Player->EquipForPush(items); Player->ADD_GOSSIP_ITEM(0, "Weiter zu den Berufen", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30013, Creature->GetGUID()); break; } case GOSSIP_ACTION_INFO_DEF + 19: { // ROGUE - fertig uint16 items[] = {16707, 22340, 16708, 0, 16721, 16713, 16709, 16711, 16710, 16712, 18701, 13098, 7734, 22321, 13397, 22404, 13368, 28972}; Player->EquipForPush(items); Player->ADD_GOSSIP_ITEM(0, "Weiter zu den Berufen", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30013, Creature->GetGUID()); break; } case GOSSIP_ACTION_INFO_DEF + 20: { // PRIEST - DD - fertig uint16 items[] = {16693, 22403, 16695, 0, 16690, 16696, 16694, 16691, 16697, 16692, 22433, 13345, 7734, 12930, 12968, 22335, 0, 13938}; Player->EquipForPush(items); Player->ADD_GOSSIP_ITEM(0, "Weiter zu den Berufen", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30013, Creature->GetGUID()); break; } case GOSSIP_ACTION_INFO_DEF + 21: { // PRIEST - HEILER -ü uint16 items[] = {13102,18723,22405,0,13346,18327,18386,12556,18497,12554,22334, 18395,18469,12930,18389,22380,18523,21801}; Player->EquipForPush(items); Player->ADD_GOSSIP_ITEM(0, "Weiter zu den Berufen", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30013, Creature->GetGUID()); break; } case GOSSIP_ACTION_INFO_DEF + 22: { // SHAMANE - VERSTÄRKER - fertig uint16 items[] = {16667, 22340, 16669, 0, 16666, 16673, 16668, 16670, 16671, 16672, 18701, 13098, 7734, 22321, 13397, 22404, 0, 22395}; Player->EquipForPush(items); Player->AddItem(14487, 1); Player->ADD_GOSSIP_ITEM(0, "Weiter zu den Berufen", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30013, Creature->GetGUID()); break; } case GOSSIP_ACTION_INFO_DEF + 23: { // SHAMANE - ELEMENTAR -fertig uint16 items[] = {16667, 22403, 16669, 0, 16666, 16673, 16668, 16670, 16671, 16672, 22433, 13345, 7734, 12930, 12968, 22335, 0, 22395}; Player->EquipForPush(items); Player->ADD_GOSSIP_ITEM(0, "Weiter zu den Berufen", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30013, Creature->GetGUID()); break; } case GOSSIP_ACTION_INFO_DEF + 24: { // SHAMANE - HEILER -ü uint16 items[] = {18807,18723,14548,0,15047,18721,14522,18318,13969, 18527,13178, 22334,12930,18471,18389,22380,22336,23200}; Player->EquipForPush(items); Player->ADD_GOSSIP_ITEM(0, "Weiter zu den Berufen", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30013, Creature->GetGUID()); break; } case GOSSIP_ACTION_INFO_DEF + 25: { // MAGE -fertig uint16 items[] = {16686, 22403, 16689, 0, 16688, 16685, 16687, 16682, 16683, 16684, 22433, 13345, 7734, 12930, 12968, 22335, 0, 13938}; Player->EquipForPush(items); Player->ADD_GOSSIP_ITEM(0, "Weiter zu den Berufen", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30013, Creature->GetGUID()); break; } case GOSSIP_ACTION_INFO_DEF + 26: { // WARLOCK -fertig uint16 items[] = {16698, 22403, 16701, 0, 16700, 16702, 16699, 16704, 16703, 16705, 22433, 13345, 7734, 12930, 12968, 22335, 0, 13938}; Player->EquipForPush(items); Player->ADD_GOSSIP_ITEM(0, "Weiter zu den Berufen", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30013, Creature->GetGUID()); break; } case GOSSIP_ACTION_INFO_DEF + 27: { // DRUID - KATZE -fertig uint16 items[] = {16720, 22340, 16718, 0, 16706, 16716, 16719, 16715, 16714, 16717, 18701, 13098, 7734, 22321, 13397, 13372, 0, 22397}; Player->EquipForPush(items); Player->ADD_GOSSIP_ITEM(0, "Weiter zu den Berufen", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30013, Creature->GetGUID()); break; } case GOSSIP_ACTION_INFO_DEF + 28: { // DRUID - EULE -ü uint16 items[] = {16720, 22403, 16718, 0, 16706, 16716, 16719, 16715, 16714, 16717, 22433, 13345, 7734, 12930, 12968, 22335, 0, 22398}; Player->EquipForPush(items); Player->ADD_GOSSIP_ITEM(0, "Weiter zu den Berufen", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30013, Creature->GetGUID()); break; } case GOSSIP_ACTION_INFO_DEF + 29: { // DRUID - BAUM -ü uint16 items[] = {17740,18723,15061,0,22272,18391,18682,22275,13208,12547,22334, 18395,18470,12930,18389,22380,18523,22398}; Player->EquipForPush(items); Player->ADD_GOSSIP_ITEM(0, "Weiter zu den Berufen", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30013, Creature->GetGUID()); break; } case GOSSIP_ACTION_INFO_DEF + 30: { // DRUID - BÄR -ü uint16 items[] = {14539,13091,15058,0,15056,20261,15057,19052,18700,18377,22680, 11669,21784,11810,19888,20556,0,23198}; Player->EquipForPush(items); Player->ADD_GOSSIP_ITEM(0, "Weiter zu den Berufen", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30013, Creature->GetGUID()); break; } case GOSSIP_ACTION_INFO_DEF + 31: { professions = 0; QueryResultAutoPtr result = RealmDataDatabase.PQuery("SELECT guid FROM characters WHERE account in (SELECT account FROM characters WHERE guid = '%u')", GUID_LOPART(Player->GetGUID())); Field *fields = NULL; uint32 maxchars = 0; do { fields = result->Fetch(); QueryResultAutoPtr level = RealmDataDatabase.PQuery("SELECT level FROM characters WHERE guid = %u", fields->GetUInt32()); if (level->Fetch()->GetUInt32() >= 60) maxchars++; } while (result->NextRow()); if (maxchars >= 2) { Player->ADD_GOSSIP_ITEM(0, "Weiter zum ausbilden :)", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 40); Player->PlayerTalkClass->SendGossipMenu(30017, Creature->GetGUID()); break; } if (Player->HasSkill(SKILL_ALCHEMY)) professions++; if (Player->HasSkill(SKILL_BLACKSMITHING)) professions++; if (Player->HasSkill(SKILL_ENCHANTING)) professions++; if (Player->HasSkill(SKILL_ENGINERING)) professions++; if (Player->HasSkill(SKILL_HERBALISM)) professions++; if (Player->HasSkill(SKILL_JEWELCRAFTING)) professions++; if (Player->HasSkill(SKILL_LEATHERWORKING)) professions++; if (Player->HasSkill(SKILL_MINING)) professions++; if (Player->HasSkill(SKILL_SKINNING)) professions++; if (Player->HasSkill(SKILL_TAILORING)) professions++; if (professions >= 2) { Player->ADD_GOSSIP_ITEM(0, "Weiter zum ausbilden!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 40); Player->PlayerTalkClass->SendGossipMenu(30017, Creature->GetGUID()); } else { Player->ADD_GOSSIP_ITEM(GOSSIP_ICON_TRAINER, "Alchemie", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 401); Player->ADD_GOSSIP_ITEM(GOSSIP_ICON_TRAINER, "Bergbauer", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 402); Player->ADD_GOSSIP_ITEM(GOSSIP_ICON_TRAINER, "Ingenieurskunst", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 403); Player->ADD_GOSSIP_ITEM(GOSSIP_ICON_TRAINER, "Juwelenschleifen", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 404); Player->ADD_GOSSIP_ITEM(GOSSIP_ICON_TRAINER, "Kraeutersuche", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 405); Player->ADD_GOSSIP_ITEM(GOSSIP_ICON_TRAINER, "Kuerschnerei", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 406); Player->ADD_GOSSIP_ITEM(GOSSIP_ICON_TRAINER, "Lederverarbeitung", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 407); Player->ADD_GOSSIP_ITEM(GOSSIP_ICON_TRAINER, "Schmiedekunst", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 408); Player->ADD_GOSSIP_ITEM(GOSSIP_ICON_TRAINER, "Schneiderei", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 409); Player->ADD_GOSSIP_ITEM(GOSSIP_ICON_TRAINER, "Verzauberungskunst", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 410); Player->ADD_GOSSIP_ITEM(0, "Ich will keinen Beruf", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 40); Player->PlayerTalkClass->SendGossipMenu(30016, Creature->GetGUID()); } break; } case GOSSIP_ACTION_INFO_DEF + 401: //Alchi { professions = 0; if (Player->HasSkill(SKILL_ALCHEMY)) professions++; if (Player->HasSkill(SKILL_BLACKSMITHING)) professions++; if (Player->HasSkill(SKILL_ENCHANTING)) professions++; if (Player->HasSkill(SKILL_ENGINERING)) professions++; if (Player->HasSkill(SKILL_HERBALISM)) professions++; if (Player->HasSkill(SKILL_JEWELCRAFTING)) professions++; if (Player->HasSkill(SKILL_LEATHERWORKING)) professions++; if (Player->HasSkill(SKILL_MINING)) professions++; if (Player->HasSkill(SKILL_SKINNING)) professions++; if (Player->HasSkill(SKILL_TAILORING)) professions++; if (professions >= 2) { Player->ADD_GOSSIP_ITEM(0, "Weiter zum ausbilden!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 40); Player->PlayerTalkClass->SendGossipMenu(30017, Creature->GetGUID()); } else { Player->learnSpell(11611); Player->SetSkill(171,300,300); Player->AddItem(9149, 1); Player->AddItem(8925, 20); Player->AddItem(18256, 20); Player->ADD_GOSSIP_ITEM(0, "Weiter", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30019, Creature->GetGUID()); } break; } case GOSSIP_ACTION_INFO_DEF + 402: //Bergbau { professions = 0; if (Player->HasSkill(SKILL_ALCHEMY)) professions++; if (Player->HasSkill(SKILL_BLACKSMITHING)) professions++; if (Player->HasSkill(SKILL_ENCHANTING)) professions++; if (Player->HasSkill(SKILL_ENGINERING)) professions++; if (Player->HasSkill(SKILL_HERBALISM)) professions++; if (Player->HasSkill(SKILL_JEWELCRAFTING)) professions++; if (Player->HasSkill(SKILL_LEATHERWORKING)) professions++; if (Player->HasSkill(SKILL_MINING)) professions++; if (Player->HasSkill(SKILL_SKINNING)) professions++; if (Player->HasSkill(SKILL_TAILORING)) professions++; if (professions >= 2) { Player->ADD_GOSSIP_ITEM(0, "Weiter zum ausbilden!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 40); Player->PlayerTalkClass->SendGossipMenu(30017, Creature->GetGUID()); } else { Player->learnSpell(10248); Player->SetSkill(186,300,300); Player->AddItem(2901, 1); Player->ADD_GOSSIP_ITEM(0, "Weiter", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30019, Creature->GetGUID()); } break; } case GOSSIP_ACTION_INFO_DEF + 403: //Ingi { professions = 0; if (Player->HasSkill(SKILL_ALCHEMY)) professions++; if (Player->HasSkill(SKILL_BLACKSMITHING)) professions++; if (Player->HasSkill(SKILL_ENCHANTING)) professions++; if (Player->HasSkill(SKILL_ENGINERING)) professions++; if (Player->HasSkill(SKILL_HERBALISM)) professions++; if (Player->HasSkill(SKILL_JEWELCRAFTING)) professions++; if (Player->HasSkill(SKILL_LEATHERWORKING)) professions++; if (Player->HasSkill(SKILL_MINING)) professions++; if (Player->HasSkill(SKILL_SKINNING)) professions++; if (Player->HasSkill(SKILL_TAILORING)) professions++; if (professions >= 2) { Player->ADD_GOSSIP_ITEM(0, "Weiter zum ausbilden!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 40); Player->PlayerTalkClass->SendGossipMenu(30017, Creature->GetGUID()); } else { Player->learnSpell(12656); Player->SetSkill(202,300,300); Player->AddItem(6219, 1); Player->AddItem(10498, 1); professions++; Player->ADD_GOSSIP_ITEM(0, "Weiter", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30019, Creature->GetGUID()); } break; } case GOSSIP_ACTION_INFO_DEF + 404: //Juwe { professions = 0; if (Player->HasSkill(SKILL_ALCHEMY)) professions++; if (Player->HasSkill(SKILL_BLACKSMITHING)) professions++; if (Player->HasSkill(SKILL_ENCHANTING)) professions++; if (Player->HasSkill(SKILL_ENGINERING)) professions++; if (Player->HasSkill(SKILL_HERBALISM)) professions++; if (Player->HasSkill(SKILL_JEWELCRAFTING)) professions++; if (Player->HasSkill(SKILL_LEATHERWORKING)) professions++; if (Player->HasSkill(SKILL_MINING)) professions++; if (Player->HasSkill(SKILL_SKINNING)) professions++; if (Player->HasSkill(SKILL_TAILORING)) professions++; if (professions >= 2) { Player->ADD_GOSSIP_ITEM(0, "Weiter zum ausbilden!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 40); Player->PlayerTalkClass->SendGossipMenu(30017, Creature->GetGUID()); } else { Player->learnSpell(28895); Player->SetSkill(755,300,300); Player->AddItem(20815, 1); Player->AddItem(20824, 1); Player->ADD_GOSSIP_ITEM(0, "Weiter", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30019, Creature->GetGUID()); } break; } case GOSSIP_ACTION_INFO_DEF + 405: //Kräuter { professions = 0; if (Player->HasSkill(SKILL_ALCHEMY)) professions++; if (Player->HasSkill(SKILL_BLACKSMITHING)) professions++; if (Player->HasSkill(SKILL_ENCHANTING)) professions++; if (Player->HasSkill(SKILL_ENGINERING)) professions++; if (Player->HasSkill(SKILL_HERBALISM)) professions++; if (Player->HasSkill(SKILL_JEWELCRAFTING)) professions++; if (Player->HasSkill(SKILL_LEATHERWORKING)) professions++; if (Player->HasSkill(SKILL_MINING)) professions++; if (Player->HasSkill(SKILL_SKINNING)) professions++; if (Player->HasSkill(SKILL_TAILORING)) professions++; if (professions >= 2) { Player->ADD_GOSSIP_ITEM(0, "Weiter zum ausbilden!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 40); Player->PlayerTalkClass->SendGossipMenu(30017, Creature->GetGUID()); } else { Player->learnSpell(11993); Player->SetSkill(182,300,300); Player->ADD_GOSSIP_ITEM(0, "Weiter", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30019, Creature->GetGUID()); } break; } case GOSSIP_ACTION_INFO_DEF + 406: //Kürschner { professions = 0; if (Player->HasSkill(SKILL_ALCHEMY)) professions++; if (Player->HasSkill(SKILL_BLACKSMITHING)) professions++; if (Player->HasSkill(SKILL_ENCHANTING)) professions++; if (Player->HasSkill(SKILL_ENGINERING)) professions++; if (Player->HasSkill(SKILL_HERBALISM)) professions++; if (Player->HasSkill(SKILL_JEWELCRAFTING)) professions++; if (Player->HasSkill(SKILL_LEATHERWORKING)) professions++; if (Player->HasSkill(SKILL_MINING)) professions++; if (Player->HasSkill(SKILL_SKINNING)) professions++; if (Player->HasSkill(SKILL_TAILORING)) professions++; if (professions >= 2) { Player->ADD_GOSSIP_ITEM(0, "Weiter zum ausbilden!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 40); Player->PlayerTalkClass->SendGossipMenu(30017, Creature->GetGUID()); } else { Player->learnSpell(10768); Player->SetSkill(393,300,300); Player->AddItem(7005, 1); Player->ADD_GOSSIP_ITEM(0, "Weiter", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30019, Creature->GetGUID()); } break; } case GOSSIP_ACTION_INFO_DEF + 407: //Leder { professions = 0; if (Player->HasSkill(SKILL_ALCHEMY)) professions++; if (Player->HasSkill(SKILL_BLACKSMITHING)) professions++; if (Player->HasSkill(SKILL_ENCHANTING)) professions++; if (Player->HasSkill(SKILL_ENGINERING)) professions++; if (Player->HasSkill(SKILL_HERBALISM)) professions++; if (Player->HasSkill(SKILL_JEWELCRAFTING)) professions++; if (Player->HasSkill(SKILL_LEATHERWORKING)) professions++; if (Player->HasSkill(SKILL_MINING)) professions++; if (Player->HasSkill(SKILL_SKINNING)) professions++; if (Player->HasSkill(SKILL_TAILORING)) professions++; if (professions >= 2) { Player->ADD_GOSSIP_ITEM(0, "Weiter zum ausbilden!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 40); Player->PlayerTalkClass->SendGossipMenu(30017, Creature->GetGUID()); } else { Player->learnSpell(10662); Player->SetSkill(165,300,300); Player->ADD_GOSSIP_ITEM(0, "Weiter", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30019, Creature->GetGUID()); } break; } case GOSSIP_ACTION_INFO_DEF + 408: //Schmied { professions = 0; if (Player->HasSkill(SKILL_ALCHEMY)) professions++; if (Player->HasSkill(SKILL_BLACKSMITHING)) professions++; if (Player->HasSkill(SKILL_ENCHANTING)) professions++; if (Player->HasSkill(SKILL_ENGINERING)) professions++; if (Player->HasSkill(SKILL_HERBALISM)) professions++; if (Player->HasSkill(SKILL_JEWELCRAFTING)) professions++; if (Player->HasSkill(SKILL_LEATHERWORKING)) professions++; if (Player->HasSkill(SKILL_MINING)) professions++; if (Player->HasSkill(SKILL_SKINNING)) professions++; if (Player->HasSkill(SKILL_TAILORING)) professions++; if (professions >= 2) { Player->ADD_GOSSIP_ITEM(0, "Weiter zum ausbilden!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 40); Player->PlayerTalkClass->SendGossipMenu(30017, Creature->GetGUID()); } else { Player->learnSpell(9785); Player->SetSkill(164,300,300); Player->AddItem(5956, 1); Player->ADD_GOSSIP_ITEM(0, "Weiter", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30019, Creature->GetGUID()); } break; } case GOSSIP_ACTION_INFO_DEF + 409: //Schneider { professions = 0; if (Player->HasSkill(SKILL_ALCHEMY)) professions++; if (Player->HasSkill(SKILL_BLACKSMITHING)) professions++; if (Player->HasSkill(SKILL_ENCHANTING)) professions++; if (Player->HasSkill(SKILL_ENGINERING)) professions++; if (Player->HasSkill(SKILL_HERBALISM)) professions++; if (Player->HasSkill(SKILL_JEWELCRAFTING)) professions++; if (Player->HasSkill(SKILL_LEATHERWORKING)) professions++; if (Player->HasSkill(SKILL_MINING)) professions++; if (Player->HasSkill(SKILL_SKINNING)) professions++; if (Player->HasSkill(SKILL_TAILORING)) professions++; if (professions >= 2) { Player->ADD_GOSSIP_ITEM(0, "Weiter zum ausbilden!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 40); Player->PlayerTalkClass->SendGossipMenu(30017, Creature->GetGUID()); } else { Player->learnSpell(12180); Player->SetSkill(197,300,300); Player->AddItem(14341, 20); Player->ADD_GOSSIP_ITEM(0, "Weiter", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30019, Creature->GetGUID()); } break; } case GOSSIP_ACTION_INFO_DEF + 410: //VZ { professions = 0; if (Player->HasSkill(SKILL_ALCHEMY)) professions++; if (Player->HasSkill(SKILL_BLACKSMITHING)) professions++; if (Player->HasSkill(SKILL_ENCHANTING)) professions++; if (Player->HasSkill(SKILL_ENGINERING)) professions++; if (Player->HasSkill(SKILL_HERBALISM)) professions++; if (Player->HasSkill(SKILL_JEWELCRAFTING)) professions++; if (Player->HasSkill(SKILL_LEATHERWORKING)) professions++; if (Player->HasSkill(SKILL_MINING)) professions++; if (Player->HasSkill(SKILL_SKINNING)) professions++; if (Player->HasSkill(SKILL_TAILORING)) professions++; if (professions >= 2) { Player->ADD_GOSSIP_ITEM(0, "Weiter zum ausbilden!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 40); Player->PlayerTalkClass->SendGossipMenu(30017, Creature->GetGUID()); } else { Player->learnSpell(13920); Player->SetSkill(333,300,300); Player->AddItem(22461, 1); Player->ADD_GOSSIP_ITEM(0, "Weiter", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); Player->PlayerTalkClass->SendGossipMenu(30019, Creature->GetGUID()); } break; } case GOSSIP_ACTION_INFO_DEF + 40: { Player->FinishPush(); return true; } default: return false; } return true; }
void CreatureGroupManager::LoadCreatureFormations() { //Clear existing map CreatureGroupMap.clear(); //Check Integrity of the table QueryResultAutoPtr result = GameDataDatabase.PQuery("SELECT MAX(`leaderGUID`) FROM `creature_formations`"); if (!result) { sLog.outLog(LOG_DB_ERR, " ...an error occured while loading the table `creature_formations` (maybe it doesn't exist ?)\n"); return; } //Get group data result = GameDataDatabase.PQuery("SELECT `leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI` FROM `creature_formations` ORDER BY `leaderGUID`"); if (!result) { sLog.outLog(LOG_DB_ERR, "The table `creature_formations` is empty or corrupted"); return; } uint32 total_records = result->GetRowCount(); BarGoLink bar(total_records); Field *fields; FormationInfo *group_member; //Loading data... do { fields = result->Fetch(); bar.step(); //Load group member data group_member = new FormationInfo; group_member->leaderGUID = fields[0].GetUInt32(); uint32 memberGUID = fields[1].GetUInt32(); group_member->groupAI = fields[4].GetUInt8(); //If creature is group leader we may skip loading of dist/angle if (group_member->leaderGUID != memberGUID) { group_member->follow_dist = fields[2].GetUInt32(); group_member->follow_angle = fields[3].GetFloat(); } // check data correctness const CreatureData* leader = sObjectMgr.GetCreatureData(group_member->leaderGUID); const CreatureData* member = sObjectMgr.GetCreatureData(memberGUID); if (!leader || !member || leader->mapid != member->mapid) { sLog.outLog(LOG_DB_ERR, "Table `creature_formations` has an invalid record (leaderGUID: '%u', memberGUID: '%u')", group_member->leaderGUID, memberGUID); delete group_member; continue; } CreatureGroupMap[memberGUID] = group_member; } while (result->NextRow()) ; sLog.outString(); sLog.outString(">> Loaded %u creatures in formations", total_records); sLog.outString(); }