void WorldSession::HandleWrapItemOpcode(WorldPacket& recv_data) { CHECK_PACKET_SIZE(recv_data,1+1+1+1); sLog.outDebug("Received opcode CMSG_WRAP_ITEM"); uint8 gift_bag, gift_slot, item_bag, item_slot; //recv_data.hexlike(); recv_data >> gift_bag >> gift_slot; // paper recv_data >> item_bag >> item_slot; // item sLog.outDebug("WRAP: receive gift_bag = %u, gift_slot = %u, item_bag = %u, item_slot = %u", gift_bag, gift_slot, item_bag, item_slot); Item *gift = _player->GetItemByPos( gift_bag, gift_slot ); if(!gift) { _player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, gift, NULL ); return; } if(!gift->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPER))// cheating: non-wrapper wrapper { _player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, gift, NULL ); return; } Item *item = _player->GetItemByPos( item_bag, item_slot ); if( !item ) { _player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, item, NULL ); return; } if(item==gift) // not possable with pacjket from real client { _player->SendEquipError( EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED, item, NULL ); return; } if(item->IsEquipped()) { _player->SendEquipError( EQUIP_ERR_EQUIPPED_CANT_BE_WRAPPED, item, NULL ); return; } if(item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR)) // HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED); { _player->SendEquipError( EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED, item, NULL ); return; } if(item->IsBag()) { _player->SendEquipError( EQUIP_ERR_BAGS_CANT_BE_WRAPPED, item, NULL ); return; } if(item->IsSoulBound()) { _player->SendEquipError( EQUIP_ERR_BOUND_CANT_BE_WRAPPED, item, NULL ); return; } if(item->GetMaxStackCount() != 1) { _player->SendEquipError( EQUIP_ERR_STACKABLE_CANT_BE_WRAPPED, item, NULL ); return; } // maybe not correct check (it is better than nothing) if(item->GetProto()->MaxCount>0) { _player->SendEquipError( EQUIP_ERR_UNIQUE_CANT_BE_WRAPPED, item, NULL ); return; } CharacterDatabase.BeginTransaction(); CharacterDatabase.PExecute("INSERT INTO character_gifts VALUES ('%u', '%u', '%u', '%u')", GUID_LOPART(item->GetOwnerGUID()), item->GetGUIDLow(), item->GetEntry(), item->GetUInt32Value(ITEM_FIELD_FLAGS)); item->SetEntry(gift->GetEntry()); switch (item->GetEntry()) { case 5042: item->SetEntry( 5043); break; case 5048: item->SetEntry( 5044); break; case 17303: item->SetEntry(17302); break; case 17304: item->SetEntry(17305); break; case 17307: item->SetEntry(17308); break; case 21830: item->SetEntry(21831); break; } item->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, _player->GetGUID()); item->SetUInt32Value(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED); item->SetState(ITEM_CHANGED, _player); if(item->GetState()==ITEM_NEW) // save new item, to have alway for `character_gifts` record in `item_instance` { // after save it will be impossible to remove the item from the queue item->RemoveFromUpdateQueueOf(_player); item->SaveToDB(); // item gave inventory record unchanged and can be save standalone } CharacterDatabase.CommitTransaction(); uint32 count = 1; _player->DestroyItemCount(gift, count, true); }
void WorldSession::HandleAreaTriggerOpcode(WorldPacket & recv_data) { CHECK_PACKET_SIZE(recv_data, 4); uint32 id = 0; WorldPacket data(80); AreaTrigger *pAreaTrigger = NULL; recv_data >> id; sLog.outDebug("AreaTrigger: %u", id); pAreaTrigger = sWorld.GetAreaTrigger(id); // Search quest log, find any exploration quests sQuestMgr.OnPlayerExploreArea(GetPlayer(),id); // if in BG handle is triggers if(GetPlayer()->m_bgInBattleground && GetPlayer()->GetCurrentBattleground() != NULL) { GetPlayer()->GetCurrentBattleground()->HandleBattlegroundAreaTrigger(GetPlayer(), id); return; } if(pAreaTrigger && pAreaTrigger->Type == ATTYPE_BATTLEGROUND) { if(pAreaTrigger->Mapid == 489) // hack fix pAreaTrigger->Mapid = 2; else if(pAreaTrigger->Mapid == 529) pAreaTrigger->Mapid = 3; else if(pAreaTrigger->Mapid == 30) pAreaTrigger->Mapid = 1; WorldPacket *pkt = sBattlegroundMgr.BuildBattlegroundListPacket(GetPlayer()->GetGUID(), _player, pAreaTrigger->Mapid); SendPacket(pkt); delete pkt; return; } if(pAreaTrigger) { bool bFailedPre = false; std::string failed_reason; if(pAreaTrigger->required_level) { if(GetPlayer()->getLevel() < pAreaTrigger->required_level) { bFailedPre = true; if(failed_reason.size() > 0) failed_reason += ", and "; else failed_reason = "You must be "; // mm hacky char lvltext[30]; sprintf(lvltext, "at least level %d", pAreaTrigger->required_level); failed_reason += lvltext; } } if(bFailedPre) { failed_reason += " before you're allowed through here."; WorldPacket msg; msg.Initialize(SMSG_AREA_TRIGGER_MESSAGE); msg << uint32(0) << failed_reason << uint8(0); SendPacket(&msg); sLog.outDebug("Player %s failed areatrigger prereq - %s", GetPlayer()->GetName(), failed_reason.c_str()); return; } switch(pAreaTrigger->Type) { case ATTYPE_INSTANCE: { if(GetPlayer()->GetPlayerStatus() != TRANSFER_PENDING) //only ports if player is out of pendings { GetPlayer()->SaveEntryPoint(); //death system check. Corpse *pCorpse = NULL; CorpseData *pCorpseData = NULL; MapInfo *pMapinfo = NULL; pMapinfo = sWorld.GetMapInformation(pAreaTrigger->Mapid); if(pMapinfo && !pMapinfo->HasFlag(WMI_INSTANCE_ENABLED)) { WorldPacket msg; msg.Initialize(SMSG_AREA_TRIGGER_MESSAGE); msg << uint32(0) << "This instance is currently unavailable." << uint8(0) << uint8(0); SendPacket(&msg); return; } if(pMapinfo && pMapinfo->HasFlag(WMI_INSTANCE_XPACK_01) && !HasFlag(ACCOUNT_FLAG_XPACK_01)) { WorldPacket msg; msg.Initialize(SMSG_BROADCAST_MSG); msg << uint32(3) << "You must have The Burning Crusade Expansion to access this content." << uint8(0); SendPacket(&msg); return; } if(!GetPlayer()->isAlive()) { pCorpse = objmgr.GetCorpseByOwner(GetPlayer()); if(pCorpse) { pMapinfo = sWorld.GetMapInformation(pCorpse->GetMapId()); if(pMapinfo) { if(pMapinfo->type != INSTANCE_NULL && pMapinfo->type != INSTANCE_PVP && pMapinfo->type != INSTANCE_NONRAID && GetPlayer()->GetMapId() != pCorpse->GetMapId() && pCorpse->GetMapId() == pAreaTrigger->Mapid && !GetPlayer()->InGroup()) { GetPlayer()->ResurrectPlayer(); return; } else if(pMapinfo->type != INSTANCE_NONRAID) { GetPlayer()->RepopAtGraveyard(GetPlayer()->GetPositionX(),GetPlayer()->GetPositionY(),GetPlayer()->GetPositionZ(), GetPlayer()->GetMapId()); return; } } } else { GetPlayer()->RepopAtGraveyard(GetPlayer()->GetPositionX(),GetPlayer()->GetPositionY(),GetPlayer()->GetPositionZ(),GetPlayer()->GetMapId()); return; } } sWorldCreator.CheckInstanceForObject(static_cast<Object*>(_player), pMapinfo); _player->SaveEntryPoint(); _player->SafeTeleport(pAreaTrigger->Mapid, 0, LocationVector(pAreaTrigger->x, pAreaTrigger->y, pAreaTrigger->z, pAreaTrigger->o)); } }break; case ATTYPE_QUESTTRIGGER: { }break; case ATTYPE_INN: { // Inn if (!GetPlayer()->m_isResting) GetPlayer()->ApplyPlayerRestState(true); }break; case ATTYPE_TELEPORT: { if(GetPlayer()->GetPlayerStatus() != TRANSFER_PENDING) //only ports if player is out of pendings { _player->SaveEntryPoint(); _player->SafeTeleport(pAreaTrigger->Mapid, 0, LocationVector(pAreaTrigger->x, pAreaTrigger->y, pAreaTrigger->z, pAreaTrigger->o)); } }break; case ATTYPE_NULL: { MapInfo *pMapinfo = NULL; pMapinfo = sWorld.GetMapInformation(pAreaTrigger->Mapid); if(pMapinfo && pMapinfo->HasFlag(WMI_INSTANCE_XPACK_01) && !HasFlag(ACCOUNT_FLAG_XPACK_01)) { WorldPacket msg; msg.Initialize(SMSG_BROADCAST_MSG); msg << uint32(3) << "You must have The Burning Crusade Expansion to access this content." << uint8(0); SendPacket(&msg); return; } } default:break; } } }
void WorldSession::HandleLootMasterGiveOpcode( WorldPacket & recv_data ) { CHECK_PACKET_SIZE(recv_data,8+1+8); uint8 slotid; uint64 lootguid, target_playerguid; recv_data >> lootguid >> slotid >> target_playerguid; if(!_player->GetGroup() || _player->GetGroup()->GetLooterGuid() != _player->GetGUID()) { _player->SendLootRelease(GetPlayer()->GetLootGUID()); return; } Player *target = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(target_playerguid, 0, HIGHGUID_PLAYER)); if(!target) return; sLog.outDebug("WorldSession::HandleLootMasterGiveOpcode (CMSG_LOOT_MASTER_GIVE, 0x02A3) Target = [%s].", target->GetName()); if(_player->GetLootGUID() != lootguid) return; Loot *pLoot = NULL; if(IS_CREATURE_GUID(GetPlayer()->GetLootGUID())) { Creature *pCreature = ObjectAccessor::GetCreature(*GetPlayer(), lootguid); if(!pCreature) return; pLoot = &pCreature->loot; } else if(IS_GAMEOBJECT_GUID(GetPlayer()->GetLootGUID())) { GameObject *pGO = ObjectAccessor::GetGameObject(*GetPlayer(), lootguid); if(!pGO) return; pLoot = &pGO->loot; } if(!pLoot) return; if (slotid > pLoot->items.size()) { sLog.outDebug("AutoLootItem: Player %s might be using a hack! (slot %d, size %lu)",GetPlayer()->GetName(), slotid, (unsigned long)pLoot->items.size()); return; } LootItem& item = pLoot->items[slotid]; ItemPosCountVec dest; uint8 msg = target->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, item.itemid, item.count ); if ( msg != EQUIP_ERR_OK ) { target->SendEquipError( msg, NULL, NULL ); _player->SendEquipError( msg, NULL, NULL ); // send duplicate of error massage to master looter return; } // not move item from loot to target inventory Item * newitem = target->StoreNewItem( dest, item.itemid, true, item.randomPropertyId ); target->SendNewItem(newitem, uint32(item.count), false, false, true ); target->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item.itemid, item.count); // mark as looted item.count=0; item.is_looted=true; pLoot->NotifyItemRemoved(slotid); --pLoot->unlootedCount; }
////////////////////////////////////////////////////////////// /// This function handles CMSG_CREATURE_QUERY: ////////////////////////////////////////////////////////////// void WorldSession::HandleCreatureQueryOpcode(WorldPacket & recv_data) { CHECK_INWORLD_RETURN CHECK_PACKET_SIZE(recv_data, 12); WorldPacket data(SMSG_CREATURE_QUERY_RESPONSE, 250); //VLack: thanks Aspire, this was 146 before uint32 entry; uint64 guid; CreatureInfo* ci; recv_data >> entry; recv_data >> guid; if(entry == 300000) { data << (uint32)entry; data << "WayPoint"; data << uint8(0) << uint8(0) << uint8(0); data << "Level is WayPoint ID"; for(uint32 i = 0; i < 8; i++) { data << uint32(0); } data << uint8(0); } else { ci = CreatureNameStorage.LookupEntry(entry); if(ci == NULL) return; LocalizedCreatureName* lcn = (language > 0) ? sLocalizationMgr.GetLocalizedCreatureName(entry, language) : NULL; if(lcn == NULL) { LOG_DETAIL("WORLD: CMSG_CREATURE_QUERY '%s'", ci->Name); data << (uint32)entry; data << ci->Name; // name of the creature data << uint8(0); // name2, always seems to be empty data << uint8(0); // name3, always seems to be empty data << uint8(0); // name4, always seems to be empty data << ci->SubName; // this is the title/guild of the creature } else { LOG_DETAIL("WORLD: CMSG_CREATURE_QUERY '%s' (localized to %s)", ci->Name, lcn->Name); data << (uint32)entry; data << lcn->Name; data << uint8(0); data << uint8(0); data << uint8(0); data << lcn->SubName; } data << ci->info_str; //!!! this is a string in 2.3.0 Example: stormwind guard has : "Direction" data << ci->Flags1; // flags like skinnable data << ci->Type; // humanoid, beast, etc data << ci->Family; // petfamily data << ci->Rank; // normal, elite, etc data << ci->killcredit[0]; // quest kill credit 1 data << ci->killcredit[1]; // quest kill credit 2 data << ci->Male_DisplayID; data << ci->Female_DisplayID; data << ci->Male_DisplayID2; data << ci->Female_DisplayID2; data << ci->unkfloat1; data << ci->unkfloat2; data << ci->Leader; // faction leader // these are the 6 seperate quest items a creature can drop for(uint32 i = 0; i < 6; ++i) { data << uint32(ci->QuestItems[i]); } data << ci->waypointid; } SendPacket(&data); }
void WorldSession::HandleOpenItemOpcode(WorldPacket& recvPacket) { CHECK_PACKET_SIZE(recvPacket,1+1); sLog.outDetail("WORLD: CMSG_OPEN_ITEM packet, data length = %i",recvPacket.size()); Player* pUser = _player; uint8 bagIndex, slot; recvPacket >> bagIndex >> slot; sLog.outDetail("bagIndex: %u, slot: %u",bagIndex,slot); Item *pItem = pUser->GetItemByPos(bagIndex, slot); if(!pItem) { pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL ); return; } ItemPrototype const *proto = pItem->GetProto(); if(!proto) { pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL ); return; } // locked item uint32 lockId = proto->LockID; if(lockId) { LockEntry const *lockInfo = sLockStore.LookupEntry(lockId); if (!lockInfo) { pUser->SendEquipError(EQUIP_ERR_ITEM_LOCKED, pItem, NULL ); sLog.outError( "WORLD::OpenItem: item [guid = %u] has an unknown lockId: %u!", pItem->GetGUIDLow() , lockId); return; } // required picklocking if(lockInfo->requiredlockskill || lockInfo->requiredminingskill) { pUser->SendEquipError(EQUIP_ERR_ITEM_LOCKED, pItem, NULL ); return; } } if(pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED))// wrapped? { QueryResult *result = CharacterDatabase.PQuery("SELECT entry, flags FROM character_gifts WHERE item_guid = '%u'", pItem->GetGUIDLow()); if (result) { Field *fields = result->Fetch(); uint32 entry = fields[0].GetUInt32(); uint32 flags = fields[1].GetUInt32(); pItem->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, 0); pItem->SetEntry(entry); pItem->SetUInt32Value(ITEM_FIELD_FLAGS, flags); pItem->SetState(ITEM_CHANGED, pUser); delete result; } else { sLog.outError("Wrapped item %u don't have record in character_gifts table and will deleted", pItem->GetGUIDLow()); pUser->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true); return; } CharacterDatabase.PExecute("DELETE FROM character_gifts WHERE item_guid = '%u'", pItem->GetGUIDLow()); } else pUser->SendLoot(pItem->GetGUID(),LOOT_CORPSE); }
void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) { CHECK_PACKET_SIZE(recv_data, 1+1+4+2+1); sLog.outDebug( "WORLD: Recvd CMSG_BATTLEFIELD_PORT Message"); uint8 type; // arenatype if arena uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1 uint32 instanceId; uint32 bgTypeId_; // type id from dbc uint16 unk; // 0x1F90 constant? uint8 action; // enter battle 0x1, leave queue 0x0 recv_data >> type >> unk2 >> bgTypeId_ >> unk >> action; if(!sBattlemasterListStore.LookupEntry(bgTypeId_)) { sLog.outError("Battleground: invalid bgtype (%u) received.",bgTypeId_); // update battleground slots for the player to fix his UI and sent data. // this is a HACK, I don't know why the client starts sending invalid packets in the first place. // it usually happens with extremely high latency (if debugging / stepping in the code for example) if(_player->InBattleGroundQueue()) { // update all queues, send invitation info if player is invited, queue info if queued for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++) { BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i); if(!bgQueueTypeId) continue; BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId); uint32 queue_id = _player->GetBattleGroundQueueIdFromLevel(bgTypeId); BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[queue_id]; BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID()); // if the player is not in queue, continue if(itrPlayerStatus == qpMap.end()) continue; // no group information, this should never happen if(!itrPlayerStatus->second.GroupInfo) continue; BattleGround * bg = NULL; // get possibly needed data from groupinfo uint8 arenatype = itrPlayerStatus->second.GroupInfo->ArenaType; uint8 israted = itrPlayerStatus->second.GroupInfo->IsRated; uint8 status = 0; if(!itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID) { // not invited to bg, get template bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); status = STATUS_WAIT_QUEUE; } else { // get the bg we're invited to BattleGround * bg = sBattleGroundMgr.GetBattleGround(itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID); status = STATUS_WAIT_JOIN; } // if bg not found, then continue if(!bg) continue; // don't invite if already in the instance if(_player->InBattleGround() && _player->GetBattleGround() && _player->GetBattleGround()->GetInstanceID() == bg->GetInstanceID()) continue; // re - invite player with proper data WorldPacket data; sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, itrPlayerStatus->second.GroupInfo->Team?itrPlayerStatus->second.GroupInfo->Team:_player->GetTeam(), i, status, INVITE_ACCEPT_WAIT_TIME, 0, arenatype, israted); SendPacket(&data); } } return; } BattleGroundTypeId bgTypeId = BattleGroundTypeId(bgTypeId_); BattleGroundQueueTypeId bgQueueTypeId = BATTLEGROUND_QUEUE_NONE; // get the bg what we were invited to bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId,type); BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel(bgTypeId)]; BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID()); if(itrPlayerStatus == qpMap.end()) { sLog.outError("Battleground: itrplayerstatus not found."); return; } instanceId = itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID; // if action == 1, then instanceId is _required_ if(!instanceId && action == 1) { sLog.outError("Battleground: instance not found."); return; } BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId); // bg template might and must be used in case of leaving queue, when instance is not created yet if(!bg && action == 0) bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); if(!bg) { sLog.outError("Battleground: bg not found for type id %u.",bgTypeId); return; } bgTypeId = bg->GetTypeID(); if(_player->InBattleGroundQueue()) { uint32 queueSlot = 0; uint32 team = 0; uint32 arenatype = 0; uint32 israted = 0; uint32 rating = 0; uint32 opponentsRating = 0; // get the team info from the queue BattleGroundQueue::QueuedPlayersMap& qpMap2 = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel(bgTypeId)]; BattleGroundQueue::QueuedPlayersMap::iterator pitr = qpMap2.find(_player->GetGUID()); if (pitr !=qpMap2.end() && pitr->second.GroupInfo) { team = pitr->second.GroupInfo->Team; arenatype = pitr->second.GroupInfo->ArenaType; israted = pitr->second.GroupInfo->IsRated; rating = pitr->second.GroupInfo->ArenaTeamRating; opponentsRating = pitr->second.GroupInfo->OpponentsTeamRating; } else { sLog.outError("Battleground: Invalid player queue info!"); return; } WorldPacket data; switch(action) { case 1: // port to battleground if(!_player->IsInvitedForBattleGroundQueueType(bgQueueTypeId)) return; // cheating? // resurrect the player if(!_player->isAlive()) { _player->ResurrectPlayer(1.0f); _player->SpawnCorpseBones(); } // stop taxi flight at port if(_player->isInFlight()) { _player->GetMotionMaster()->MovementExpired(); _player->m_taxi.ClearTaxiDestinations(); } _player->RemoveFromGroup(); queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId); sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime()); _player->GetSession()->SendPacket(&data); // remove battleground queue status from BGmgr sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), false); // this is still needed here if battleground "jumping" shouldn't add deserter debuff // also this required to prevent stuck at old battleground after SetBattleGroundId set to new if( BattleGround *currentBg = _player->GetBattleGround() ) currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true); // set the destination instance id _player->SetBattleGroundId(bg->GetInstanceID()); // set the destination team _player->SetBGTeam(team); // bg->HandleBeforeTeleportToBattleGround(_player); sBattleGroundMgr.SendToBattleGround(_player, instanceId); // add only in HandleMoveWorldPortAck() // bg->AddPlayer(_player,team); sLog.outDebug("Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.",_player->GetName(),_player->GetGUIDLow(),bg->GetInstanceID(),bg->GetTypeID(),bgQueueTypeId); break; case 0: // leave queue queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId); /* if player leaves rated arena match before match start, it is counted as he played but he lost */ if (israted) { ArenaTeam * at = objmgr.GetArenaTeamById(team); if (at) { sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u, because he has left queue!", GUID_LOPART(_player->GetGUID()), opponentsRating); at->MemberLost(_player, opponentsRating); at->SaveToDB(); } } _player->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_NONE, 0, 0); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), true); // player left queue, we should update it, maybe now his group fits in sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId,_player->GetBattleGroundQueueIdFromLevel(bgTypeId),arenatype,israted,rating); SendPacket(&data); sLog.outDebug("Battleground: player %s (%u) left queue for bgtype %u, queue type %u.",_player->GetName(),_player->GetGUIDLow(),bg->GetTypeID(),bgQueueTypeId); break; default: sLog.outError("Battleground port: unknown action %u", action); break; } } }
void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data ) { CHECK_PACKET_SIZE(recv_data, 8+4+4+1); uint64 guid; uint32 bgTypeId_; uint32 instanceId; uint8 joinAsGroup; Group * grp; recv_data >> guid; // battlemaster guid recv_data >> bgTypeId_; // battleground type id (DBC id) recv_data >> instanceId; // instance id, 0 if First Available selected recv_data >> joinAsGroup; // join as group if(!sBattlemasterListStore.LookupEntry(bgTypeId_)) { sLog.outError("Battleground: invalid bgtype (%u) received. possible cheater? player guid %u",bgTypeId_,_player->GetGUIDLow()); return; } BattleGroundTypeId bgTypeId = BattleGroundTypeId(bgTypeId_); sLog.outDebug( "WORLD: Recvd CMSG_BATTLEMASTER_JOIN Message from: " I64FMT, guid); // can do this, since it's battleground, not arena BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, 0); // ignore if player is already in BG if(_player->InBattleGround()) return; Creature *unit = ObjectAccessor::GetCreature(*_player, guid); if(!unit) return; if(!unit->isBattleMaster()) // it's not battlemaster return; // get bg instance or bg template if instance not found BattleGround * bg = 0; if(instanceId) BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId); if(!bg && !(bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId))) { sLog.outError("Battleground: no available bg / template found"); return; } // check queueing conditions if(!joinAsGroup) { // check Deserter debuff if( !_player->CanJoinToBattleground() ) { WorldPacket data(SMSG_GROUP_JOINED_BATTLEGROUND, 4); data << (uint32) 0xFFFFFFFE; _player->GetSession()->SendPacket(&data); return; } // check if already in queue if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES) //player is already in this queue return; // check if has free queue slots if(!_player->HasFreeBattleGroundQueueId()) return; } else { grp = _player->GetGroup(); // no group found, error if(!grp) return; uint32 err = grp->CanJoinBattleGroundQueue(bgTypeId, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0); if (err != BG_JOIN_ERR_OK) { SendBattleGroundOrArenaJoinError(err); return; } } // if we're here, then the conditions to join a bg are met. We can proceed in joining. // _player->GetGroup() was already checked, grp is already initialized if(joinAsGroup /* && _player->GetGroup()*/) { sLog.outDebug("Battleground: the following players are joining as group:"); GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, 0); for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) { Player *member = itr->getSource(); if(!member) continue; // this should never happen uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId); // add to queue // store entry point coords (same as leader entry point) member->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation()); WorldPacket data; // send status packet (in queue) sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, member->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0); member->GetSession()->SendPacket(&data); sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId); member->GetSession()->SendPacket(&data); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(member, ginfo); sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName()); } sLog.outDebug("Battleground: group end"); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId)); if(!ginfo->IsInvitedToBGInstanceGUID) sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AnnounceWorld(ginfo, _player->GetGUID(), true); } else { // already checked if queueSlot is valid, now just get it uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId); // store entry point coords _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation()); WorldPacket data; // send status packet (in queue) sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0); SendPacket(&data); GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, 0); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId)); if(!ginfo->IsInvitedToBGInstanceGUID) sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AnnounceWorld(ginfo, _player->GetGUID(), true); sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName()); } }
void WorldSession::HandleCharCustomize(WorldPacket& recv_data) { CHECK_PACKET_SIZE(recv_data, 8+1); uint64 guid; std::string newname; recv_data >> guid; recv_data >> newname; CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+1+1+1+1+1+1); uint8 gender, skin, face, hairStyle, hairColor, facialHair; recv_data >> gender >> skin >> face >> hairStyle >> hairColor >> facialHair; QueryResult *result = CharacterDatabase.PQuery("SELECT at_login FROM characters WHERE guid ='%u'", GUID_LOPART(guid)); if (!result) { WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); data << uint8(CHAR_CREATE_ERROR); SendPacket( &data ); return; } Field *fields = result->Fetch(); uint32 at_loginFlags = fields[0].GetUInt32(); delete result; if (!(at_loginFlags & AT_LOGIN_CUSTOMIZE)) { WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); data << uint8(CHAR_CREATE_ERROR); SendPacket( &data ); return; } // prevent character rename to invalid name if(!normalizePlayerName(newname)) { WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); data << uint8(CHAR_NAME_NO_NAME); SendPacket( &data ); return; } if(!ObjectMgr::IsValidName(newname,true)) { WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); data << uint8(CHAR_NAME_INVALID_CHARACTER); SendPacket( &data ); return; } // check name limitations if(GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(newname)) { WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); data << uint8(CHAR_NAME_RESERVED); SendPacket( &data ); return; } if(objmgr.GetPlayerGUIDByName(newname)) // character with this name already exist { WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); data << uint8(CHAR_CREATE_NAME_IN_USE); SendPacket( &data ); return; } CharacterDatabase.escape_string(newname); Player::Customize(guid, gender, skin, face, hairStyle, hairColor, facialHair); CharacterDatabase.PExecute("UPDATE characters set name = '%s', at_login = at_login & ~ %u WHERE guid ='%u'", newname.c_str(), uint32(AT_LOGIN_CUSTOMIZE), GUID_LOPART(guid)); CharacterDatabase.PExecute("DELETE FROM character_declinedname WHERE guid ='%u'", GUID_LOPART(guid)); std::string IP_str = GetRemoteAddress(); sLog.outChar("Account: %d (IP: %s), Character guid: %u Customized to: %s", GetAccountId(), IP_str.c_str(), GUID_LOPART(guid), newname.c_str()); WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1+8+(newname.size()+1)+6); data << uint8(RESPONSE_SUCCESS); data << uint64(guid); data << newname; data << uint8(gender); data << uint8(skin); data << uint8(face); data << uint8(hairStyle); data << uint8(hairColor); data << uint8(facialHair); SendPacket(&data); }
void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data ) { CHECK_PACKET_SIZE(recv_data,1+1+1+1+1+1+1+1+1+1); std::string name; uint8 race_,class_; recv_data >> name; // recheck with known string size CHECK_PACKET_SIZE(recv_data,(name.size()+1)+1+1+1+1+1+1+1+1+1); recv_data >> race_; recv_data >> class_; WorldPacket data(SMSG_CHAR_CREATE, 1); // returned with diff.values in all cases if(GetSecurity() == SEC_PLAYER) { if(uint32 mask = sWorld.getConfig(CONFIG_CHARACTERS_CREATING_DISABLED)) { bool disabled = false; uint32 team = Player::TeamForRace(race_); switch(team) { case ALLIANCE: disabled = mask & (1<<0); break; case HORDE: disabled = mask & (1<<1); break; } if(disabled) { data << (uint8)CHAR_CREATE_DISABLED; SendPacket( &data ); return; } } } ChrClassesEntry const* classEntry = sChrClassesStore.LookupEntry(class_); ChrRacesEntry const* raceEntry = sChrRacesStore.LookupEntry(race_); if( !classEntry || !raceEntry ) { data << (uint8)CHAR_CREATE_FAILED; SendPacket( &data ); sLog.outError("Class: %u or Race %u not found in DBC (Wrong DBC files?) or Cheater?", class_, race_); return; } // prevent character creating Expansion race without Expansion account if (raceEntry->addon > Expansion()) { data << (uint8)CHAR_CREATE_EXPANSION; sLog.outError("Expansion %u account:[%d] tried to Create character with expansion %u race (%u)",Expansion(),GetAccountId(),raceEntry->addon,race_); SendPacket( &data ); return; } // prevent character creating Expansion class without Expansion account if (classEntry->addon > Expansion()) { data << (uint8)CHAR_CREATE_EXPANSION_CLASS; sLog.outError("Expansion %u account:[%d] tried to Create character with expansion %u class (%u)",Expansion(),GetAccountId(),classEntry->addon,class_); SendPacket( &data ); return; } // prevent character creating with invalid name if(!normalizePlayerName(name)) { data << (uint8)CHAR_NAME_INVALID_CHARACTER; SendPacket( &data ); sLog.outError("Account:[%d] but tried to Create character with empty [name] ",GetAccountId()); return; } // check name limitations if(!ObjectMgr::IsValidName(name,true)) { data << (uint8)CHAR_NAME_INVALID_CHARACTER; SendPacket( &data ); return; } if(GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(name)) { data << (uint8)CHAR_NAME_RESERVED; SendPacket( &data ); return; } if(objmgr.GetPlayerGUIDByName(name)) { data << (uint8)CHAR_CREATE_NAME_IN_USE; SendPacket( &data ); return; } QueryResult *resultacct = loginDatabase.PQuery("SELECT SUM(numchars) FROM realmcharacters WHERE acctid = '%d'", GetAccountId()); if ( resultacct ) { Field *fields=resultacct->Fetch(); uint32 acctcharcount = fields[0].GetUInt32(); delete resultacct; if (acctcharcount >= sWorld.getConfig(CONFIG_CHARACTERS_PER_ACCOUNT)) { data << (uint8)CHAR_CREATE_ACCOUNT_LIMIT; SendPacket( &data ); return; } } QueryResult *result = CharacterDatabase.PQuery("SELECT COUNT(guid) FROM characters WHERE account = '%d'", GetAccountId()); uint8 charcount = 0; if ( result ) { Field *fields=result->Fetch(); charcount = fields[0].GetUInt8(); delete result; if (charcount >= sWorld.getConfig(CONFIG_CHARACTERS_PER_REALM)) { data << (uint8)CHAR_CREATE_SERVER_LIMIT; SendPacket( &data ); return; } } // speedup check for heroic class disabled case uint32 heroic_free_slots = sWorld.getConfig(CONFIG_HEROIC_CHARACTERS_PER_REALM); if(heroic_free_slots==0 && GetSecurity()==SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT) { data << (uint8)CHAR_CREATE_UNIQUE_CLASS_LIMIT; SendPacket( &data ); return; } // speedup check for heroic class disabled case uint32 req_level_for_heroic = sWorld.getConfig(CONFIG_MIN_LEVEL_FOR_HEROIC_CHARACTER_CREATING); if(GetSecurity()==SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT && req_level_for_heroic > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) { data << (uint8)CHAR_CREATE_LEVEL_REQUIREMENT; SendPacket( &data ); return; } bool AllowTwoSideAccounts = !sWorld.IsPvPRealm() || sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_ACCOUNTS) || GetSecurity() > SEC_PLAYER; uint32 skipCinematics = sWorld.getConfig(CONFIG_SKIP_CINEMATICS); bool have_same_race = false; // if 0 then allowed creating without any characters bool have_req_level_for_heroic = (req_level_for_heroic==0); if(!AllowTwoSideAccounts || skipCinematics == 1 || class_ == CLASS_DEATH_KNIGHT) { QueryResult *result2 = CharacterDatabase.PQuery("SELECT guid,race,class FROM characters WHERE account = '%u' %s", GetAccountId(), (skipCinematics == 1 || class_ == CLASS_DEATH_KNIGHT) ? "" : "LIMIT 1"); if(result2) { uint32 team_= Player::TeamForRace(race_); Field* field = result2->Fetch(); uint8 acc_race = field[1].GetUInt32(); if(GetSecurity()==SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT) { uint8 acc_class = field[2].GetUInt32(); if(acc_class == CLASS_DEATH_KNIGHT) { if(heroic_free_slots > 0) --heroic_free_slots; if(heroic_free_slots==0) { data << (uint8)CHAR_CREATE_UNIQUE_CLASS_LIMIT; SendPacket( &data ); return; } } if(!have_req_level_for_heroic) { uint32 acc_guid = field[0].GetUInt32(); uint32 acc_level = Player::GetUInt32ValueFromDB(UNIT_FIELD_LEVEL,acc_guid); if(acc_level >= req_level_for_heroic) have_req_level_for_heroic = true; } } // need to check team only for first character // TODO: what to if account already has characters of both races? if (!AllowTwoSideAccounts) { uint32 acc_team=0; if(acc_race > 0) acc_team = Player::TeamForRace(acc_race); if(acc_team != team_) { data << (uint8)CHAR_CREATE_PVP_TEAMS_VIOLATION; SendPacket( &data ); delete result2; return; } } // search same race for cinematic or same class if need // TODO: check if cinematic already shown? (already logged in?; cinematic field) while ((skipCinematics == 1 && !have_same_race) || class_ == CLASS_DEATH_KNIGHT) { if(!result2->NextRow()) break; field = result2->Fetch(); acc_race = field[1].GetUInt32(); if(!have_same_race) have_same_race = race_ == acc_race; if(GetSecurity()==SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT) { uint8 acc_class = field[2].GetUInt32(); if(acc_class == CLASS_DEATH_KNIGHT) { if(heroic_free_slots > 0) --heroic_free_slots; if(heroic_free_slots==0) { data << (uint8)CHAR_CREATE_UNIQUE_CLASS_LIMIT; SendPacket( &data ); return; } } if(!have_req_level_for_heroic) { uint32 acc_guid = field[0].GetUInt32(); uint32 acc_level = Player::GetUInt32ValueFromDB(UNIT_FIELD_LEVEL,acc_guid); if(acc_level >= req_level_for_heroic) have_req_level_for_heroic = true; } } } delete result2; } } if(GetSecurity()==SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT && !have_req_level_for_heroic) { data << (uint8)CHAR_CREATE_LEVEL_REQUIREMENT; SendPacket( &data ); return; } // extract other data required for player creating uint8 gender, skin, face, hairStyle, hairColor, facialHair, outfitId; recv_data >> gender >> skin >> face; recv_data >> hairStyle >> hairColor >> facialHair >> outfitId; Player * pNewChar = new Player(this); if(!pNewChar->Create( objmgr.GenerateLowGuid(HIGHGUID_PLAYER), name, race_, class_, gender, skin, face, hairStyle, hairColor, facialHair, outfitId )) { // Player not create (race/class problem?) delete pNewChar; data << (uint8)CHAR_CREATE_ERROR; SendPacket( &data ); return; } if(have_same_race && skipCinematics == 1 || skipCinematics == 2) pNewChar->setCinematic(1); // not show intro // Player created, save it now pNewChar->SaveToDB(); charcount+=1; loginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid= '%d' AND realmid = '%d'", GetAccountId(), realmID); loginDatabase.PExecute("INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (%u, %u, %u)", charcount, GetAccountId(), realmID); delete pNewChar; // created only to call SaveToDB() data << (uint8)CHAR_CREATE_SUCCESS; SendPacket( &data ); std::string IP_str = GetRemoteAddress(); sLog.outBasic("Account: %d (IP: %s) Create Character:[%s]",GetAccountId(),IP_str.c_str(),name.c_str()); sLog.outChar("Account: %d (IP: %s) Create Character:[%s]",GetAccountId(),IP_str.c_str(),name.c_str()); }
//MIT void WorldSession::HandleCreatureQueryOpcode(WorldPacket& recv_data) { CHECK_INWORLD_RETURN CHECK_PACKET_SIZE(recv_data, 12); uint32 entry; uint64 guid; recv_data >> entry; recv_data >> guid; WorldPacket data(SMSG_CREATURE_QUERY_RESPONSE, 150); if (entry == 300000) { data << entry; data << "WayPoint"; data << uint8(0); data << uint8(0); data << uint8(0); data << "Level is WayPoint ID"; for (uint8 i = 0; i < 8; i++) { data << uint32(0); } data << uint8(0); } else { CreatureProperties const* ci = sMySQLStore.getCreatureProperties(entry); if (ci == nullptr) { return; } MySQLStructure::LocalesCreature const* lcn = (language > 0) ? sMySQLStore.getLocalizedCreature(entry, language) : nullptr; if (lcn == nullptr) { data << entry; data << ci->Name; // name of the creature data << uint8(0); // name2, always seems to be empty data << uint8(0); // name3, always seems to be empty data << uint8(0); // name4, always seems to be empty data << ci->SubName; // this is the title/guild of the creature } else { data << entry; data << lcn->name; data << uint8(0); data << uint8(0); data << uint8(0); data << lcn->subName; } data << ci->info_str; // this is a string in 2.3.0 Example: stormwind guard has : "Direction" data << ci->typeFlags; // flags like skinnable data << ci->Type; // humanoid, beast, etc data << ci->Family; // petfamily data << ci->Rank; // normal, elite, etc data << ci->killcredit[0]; // quest kill credit 1 data << ci->killcredit[1]; // quest kill credit 2 data << ci->Male_DisplayID; data << ci->Female_DisplayID; data << ci->Male_DisplayID2; data << ci->Female_DisplayID2; data << ci->baseAttackMod; data << ci->rangeAttackMod; data << ci->Leader; // faction leader } SendPacket(&data); }
void WorldSession::HandleDeclinedPlayerNameOpcode(WorldPacket& recv_data) { uint64 guid; CHECK_PACKET_SIZE(recv_data, 8); recv_data >> guid; // not accept declined names for unsupported languages std::string name; if(!objmgr.GetPlayerNameByGUID(guid, name)) { WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); data << uint32(1); data << uint64(guid); SendPacket(&data); return; } std::wstring wname; if(!Utf8toWStr(name, wname)) { WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); data << uint32(1); data << uint64(guid); SendPacket(&data); return; } if(!isCyrillicCharacter(wname[0])) // name already stored as only single alphabet using { WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); data << uint32(1); data << uint64(guid); SendPacket(&data); return; } std::string name2; DeclinedName declinedname; CHECK_PACKET_SIZE(recv_data, recv_data.rpos() + 1); recv_data >> name2; if(name2 != name) // character have different name { WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); data << uint32(1); data << uint64(guid); SendPacket(&data); return; } for(int i = 0; i < MAX_DECLINED_NAME_CASES; ++i) { CHECK_PACKET_SIZE(recv_data, recv_data.rpos() + 1); recv_data >> declinedname.name[i]; if(!normalizePlayerName(declinedname.name[i])) { WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); data << uint32(1); data << uint64(guid); SendPacket(&data); return; } } if(!ObjectMgr::CheckDeclinedNames(GetMainPartOfName(wname, 0), declinedname)) { WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); data << uint32(1); data << uint64(guid); SendPacket(&data); return; } for(int i = 0; i < MAX_DECLINED_NAME_CASES; ++i) CharacterDatabase.escape_string(declinedname.name[i]); CharacterDatabase.BeginTransaction(); CharacterDatabase.PExecute("DELETE FROM character_declinedname WHERE guid = '%u'", GUID_LOPART(guid)); CharacterDatabase.PExecute("INSERT INTO character_declinedname (guid, genitive, dative, accusative, instrumental, prepositional) VALUES ('%u','%s','%s','%s','%s','%s')", GUID_LOPART(guid), declinedname.name[0].c_str(), declinedname.name[1].c_str(), declinedname.name[2].c_str(), declinedname.name[3].c_str(), declinedname.name[4].c_str()); CharacterDatabase.CommitTransaction(); WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); data << uint32(0); // OK data << uint64(guid); SendPacket(&data); }
////////////////////////////////////////////////////////////////////////////////////////// /// This function handles CMSG_GAMEOBJECT_QUERY: ////////////////////////////////////////////////////////////////////////////////////////// void WorldSession::HandleGameObjectQueryOpcode(WorldPacket& recv_data) { CHECK_INWORLD_RETURN CHECK_PACKET_SIZE(recv_data, 12); WorldPacket data(SMSG_GAMEOBJECT_QUERY_RESPONSE, 900); uint32 entryID; uint64 guid; recv_data >> entryID; recv_data >> guid; LOG_DETAIL("WORLD: CMSG_GAMEOBJECT_QUERY '%u'", entryID); auto gameobject_info = sMySQLStore.getGameObjectProperties(entryID); if (gameobject_info == nullptr) { return; } MySQLStructure::LocalesGameobject const* lgn = (language > 0) ? sMySQLStore.getLocalizedGameobject(entryID, language) : nullptr; data << entryID; // unique identifier of the GO template data << gameobject_info->type; // type of the gameobject data << gameobject_info->display_id; // displayid/modelid of the gameobject // Name of the gameobject if (lgn != nullptr) { data << lgn->name; } else { data << gameobject_info->name; } data << uint8(0); // name2, always seems to be empty data << uint8(0); // name3, always seems to be empty data << uint8(0); // name4, always seems to be empty data << gameobject_info->category_name; // Category string of the GO, like "attack", "pvp", "point", etc data << gameobject_info->cast_bar_text; // text displayed when using the go, like "collecting", "summoning" etc data << gameobject_info->Unkstr; data << gameobject_info->raw.parameter_0; // spellfocus id, ex.: spell casted when interacting with the GO data << gameobject_info->raw.parameter_1; data << gameobject_info->raw.parameter_2; data << gameobject_info->raw.parameter_3; data << gameobject_info->raw.parameter_4; data << gameobject_info->raw.parameter_5; data << gameobject_info->raw.parameter_6; data << gameobject_info->raw.parameter_7; data << gameobject_info->raw.parameter_8; data << gameobject_info->raw.parameter_9; data << gameobject_info->raw.parameter_10; data << gameobject_info->raw.parameter_11; data << gameobject_info->raw.parameter_12; data << gameobject_info->raw.parameter_13; data << gameobject_info->raw.parameter_14; data << gameobject_info->raw.parameter_15; data << gameobject_info->raw.parameter_16; data << gameobject_info->raw.parameter_17; data << gameobject_info->raw.parameter_18; data << gameobject_info->raw.parameter_19; data << gameobject_info->raw.parameter_20; data << gameobject_info->raw.parameter_21; data << gameobject_info->raw.parameter_22; data << gameobject_info->raw.parameter_23; data << float(gameobject_info->size); // scaling of the GO // questitems that the go can contain for (uint8 i = 0; i < 6; ++i) { data << uint32(gameobject_info->QuestItems[i]); } SendPacket(&data); }
void WorldSession::HandleChangePlayerNameOpcode(WorldPacket& recv_data) { uint64 guid; std::string newname; std::string oldname; CHECK_PACKET_SIZE(recv_data, 8+1); recv_data >> guid; recv_data >> newname; if(!objmgr.GetPlayerNameByGUID(guid, oldname)) // character not exist, because we have no name for this guid { WorldPacket data(SMSG_CHAR_RENAME, 1); data << (uint8)CHAR_LOGIN_NO_CHARACTER; SendPacket( &data ); return; } // prevent character rename to invalid name if(newname.empty()) // checked by client { WorldPacket data(SMSG_CHAR_RENAME, 1); data << (uint8)CHAR_NAME_NO_NAME; SendPacket( &data ); return; } normalizePlayerName(newname); if(newname.find_first_of(notAllowedChars) != newname.npos) { WorldPacket data(SMSG_CHAR_RENAME, 1); data << (uint8)CHAR_NAME_INVALID_CHARACTER;; SendPacket( &data ); return; } // check name limitations if(GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(newname)) { WorldPacket data(SMSG_CHAR_RENAME, 1); data << (uint8)CHAR_NAME_RESERVED; SendPacket( &data ); return; } if(objmgr.GetPlayerGUIDByName(newname)) // character with this name already exist { WorldPacket data(SMSG_CHAR_RENAME, 1); data << (uint8)CHAR_CREATE_ERROR; SendPacket( &data ); return; } if(newname == oldname) // checked by client { WorldPacket data(SMSG_CHAR_RENAME, 1); data << (uint8)CHAR_NAME_FAILURE; SendPacket( &data ); return; } CharacterDatabase.escape_string(newname); CharacterDatabase.PExecute("UPDATE `character` set `name` = '%s', `at_login` = `at_login` & ~ '%u' WHERE `guid` ='%u'", newname.c_str(), uint32(AT_LOGIN_RENAME),GUID_LOPART(guid)); std::string IP_str = _socket ? _socket->GetRemoteAddress().c_str() : "-"; sLog.outChar("Account: %d (IP: %s) Character:[%s] (guid:%u) Changed name to: %p",GetAccountId(),IP_str.c_str(),oldname.c_str(),GUID_LOPART(guid),newname.c_str()); WorldPacket data(SMSG_CHAR_RENAME,1+8+(newname.size()+1)); data << (uint8)RESPONSE_SUCCESS; data << guid; data << newname; SendPacket(&data); }
void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data ) { // in Player::Create: //uint8 race,class_,gender,skin,face,hairStyle,hairColor,facialHair,outfitId; //data >> name //data >> race >> class_ >> gender >> skin >> face; //data >> hairStyle >> hairColor >> facialHair >> outfitId; CHECK_PACKET_SIZE(recv_data,1+1+1+1+1+1+1+1+1+1); std::string name; uint8 race_,class_; bool pTbc = this->IsTBC() && sWorld.getConfig(CONFIG_EXPANSION); recv_data >> name; // recheck with known string size CHECK_PACKET_SIZE(recv_data,(name.size()+1)+1+1+1+1+1+1+1+1+1); recv_data >> race_; recv_data >> class_; WorldPacket data(SMSG_CHAR_CREATE, 1); // returned with diff.values in all cases if (!sChrClassesStore.LookupEntry(class_)|| !sChrRacesStore.LookupEntry(race_)) { data << (uint8)CHAR_CREATE_FAILED; SendPacket( &data ); sLog.outError("Class: %u or Race %u not found in DBC (Wrong DBC files?) or Cheater?", class_, race_); return; } // prevent character creating Expansion race without Expansion account if (!pTbc&&(race_>RACE_TROLL)) { data << (uint8)CHAR_CREATE_EXPANSION; sLog.outError("No Expansion Account:[%d] but tried to Create TBC character",GetAccountId()); SendPacket( &data ); return; } // prevent character creating with invalid name if(name.empty()) { data << (uint8)CHAR_NAME_INVALID_CHARACTER; SendPacket( &data ); sLog.outError("Account:[%d] but tried to Create character with empty [name] ",GetAccountId()); return; } normalizePlayerName(name); if(name.find_first_of(notAllowedChars)!=name.npos) { data << (uint8)CHAR_NAME_INVALID_CHARACTER; SendPacket( &data ); sLog.outError("Account:[%d] tried to Create character with empty name or with not allowed by client charcters",GetAccountId()); return; } // check name limitations if(GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(name)) { data << (uint8)CHAR_NAME_RESERVED; SendPacket( &data ); return; } if(objmgr.GetPlayerGUIDByName(name)) { data << (uint8)CHAR_CREATE_NAME_IN_USE; SendPacket( &data ); return; } QueryResult *result = CharacterDatabase.PQuery("SELECT COUNT(guid) FROM `character` WHERE `account` = '%d'", GetAccountId()); uint8 charcount = 0; if ( result ) { Field *fields=result->Fetch(); charcount = fields[0].GetUInt8(); delete result; if (charcount >= 10) { data << (uint8)CHAR_CREATE_ACCOUNT_LIMIT; SendPacket( &data ); return; } } bool AllowTwoSideAccounts = sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_ACCOUNTS); if(sWorld.IsPvPRealm()&&!AllowTwoSideAccounts) { QueryResult *result2 = CharacterDatabase.PQuery("SELECT `race` FROM `character` WHERE `account` = '%u' LIMIT 1", GetAccountId()); if(result2) { Field * field = result2->Fetch(); uint8 race = field[0].GetUInt32(); delete result2; uint32 team=0; if(race > 0) team = Player::TeamForRace(race); uint32 team_=0; //if(race_ > 0) team_ = Player::TeamForRace(race_); if(team != team_ && GetSecurity() < SEC_GAMEMASTER) { data << (uint8)CHAR_CREATE_PVP_TEAMS_VIOLATION; SendPacket( &data ); return; } } } Player * pNewChar = new Player(this); recv_data.rpos(0); if(pNewChar->Create( objmgr.GenerateLowGuid(HIGHGUID_PLAYER), recv_data )) { // Player create pNewChar->SaveToDB(); charcount+=1; loginDatabase.PExecute("INSERT INTO `realmcharacters` (`numchars`, `acctid`, `realmid`) VALUES (%d, %d, %d) ON DUPLICATE KEY UPDATE `numchars` = '%d'", charcount, GetAccountId(), realmID, charcount); delete pNewChar; } else { // Player not create (race/class problem?) delete pNewChar; data << (uint8)CHAR_CREATE_ERROR; SendPacket( &data ); return; } data << (uint8)CHAR_CREATE_SUCCESS; SendPacket( &data ); std::string IP_str = _socket ? _socket->GetRemoteAddress().c_str() : "-"; sLog.outBasic("Account: %d (IP: %s) Create Character:[%s]",GetAccountId(),IP_str.c_str(),name.c_str()); sLog.outChar("Account: %d (IP: %s) Create Character:[%s]",GetAccountId(),IP_str.c_str(),name.c_str()); }
//called when player lists his received mails void WorldSession::HandleGetMail(WorldPacket & recv_data ) { CHECK_PACKET_SIZE(recv_data,8); uint64 mailbox; recv_data >> mailbox; //GameObject* obj = ObjectAccessor::GetGameObject(_player, mailbox); //if(!obj || !obj->IsMailBox()) // return; Player* pl = _player; //load players mails, and mailed items if(!pl->m_mailsLoaded) pl ->_LoadMail(); // client can't work with packets > max int16 value const uint32 maxPacketSize = 32767; uint32 mails_count = 0; // real send to client mails amount WorldPacket data(SMSG_MAIL_LIST_RESULT, (200)); // guess size data << uint8(0); // mail's count time_t cur_time = time(NULL); for(PlayerMails::iterator itr = pl->GetmailBegin(); itr != pl->GetmailEnd(); ++itr) { // skip deleted or not delivered (deliver delay not expired) mails if ((*itr)->state == MAIL_STATE_DELETED || cur_time < (*itr)->deliver_time) continue; uint8 item_count = (*itr)->items.size(); // max count is MAX_MAIL_ITEMS (12) size_t next_mail_size = 2+4+1+8+4*8+((*itr)->subject.size()+1)+1+item_count*(1+4+4+6*3*4+4+4+1+4+4+4); if(data.wpos()+next_mail_size > maxPacketSize) break; data << (uint16) 0x0040; // unknown 2.3.0, different values data << (uint32) (*itr)->messageID; // Message ID data << (uint8) (*itr)->messageType; // Message Type switch((*itr)->messageType) { case MAIL_NORMAL: // sender guid data << uint64(MAKE_NEW_GUID((*itr)->sender, 0, HIGHGUID_PLAYER)); break; case MAIL_CREATURE: case MAIL_GAMEOBJECT: case MAIL_AUCTION: data << (uint32) (*itr)->sender; // creature/gameobject entry, auction id break; case MAIL_ITEM: // item entry (?) sender = "Unknown", NYI break; } data << (uint32) (*itr)->COD; // COD data << (uint32) (*itr)->itemTextId; // sure about this data << (uint32) 0; // unknown data << (uint32) (*itr)->stationery; // stationery (Stationery.dbc) data << (uint32) (*itr)->money; // Gold data << (uint32) 0x04; // unknown, 0x4 - auction, 0x10 - normal // Time data << (float) ((*itr)->expire_time-time(NULL))/DAY; data << (uint32) (*itr)->mailTemplateId; // mail template (MailTemplate.dbc) data << (*itr)->subject; // Subject string - once 00, when mail type = 3 data << (uint8) item_count; for(uint8 i = 0; i < item_count; ++i) { Item *item = pl->GetMItem((*itr)->items[i].item_guid); // item index (0-6?) data << (uint8) i; // item guid low? data << (uint32) (item ? item->GetGUIDLow() : 0); // entry data << (uint32) (item ? item->GetEntry() : 0); for(uint8 j = 0; j < 6; ++j) { // unsure data << (uint32) (item ? item->GetEnchantmentCharges((EnchantmentSlot)j) : 0); // unsure data << (uint32) (item ? item->GetEnchantmentDuration((EnchantmentSlot)j) : 0); // unsure data << (uint32) (item ? item->GetEnchantmentId((EnchantmentSlot)j) : 0); } // can be negative data << (uint32) (item ? item->GetItemRandomPropertyId() : 0); // unk data << (uint32) (item ? item->GetItemSuffixFactor() : 0); // stack count data << (uint8) (item ? item->GetCount() : 0); // charges data << (uint32) (item ? item->GetSpellCharges() : 0); // durability data << (uint32) (item ? item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY) : 0); // durability data << (uint32) (item ? item->GetUInt32Value(ITEM_FIELD_DURABILITY) : 0); } mails_count += 1; } data.put<uint8>(0, mails_count); // set real send mails to client SendPacket(&data); // recalculate m_nextMailDelivereTime and unReadMails _player->UpdateNextMailTimeAndUnreads(); }
void WorldSession::HandleCharDeleteOpcode( WorldPacket & recv_data ) { CHECK_PACKET_SIZE(recv_data,8); uint64 guid; recv_data >> guid; // can't delete loaded character if(objmgr.GetPlayer(guid)) return; uint32 accountId = 0; std::string name; // is guild leader if(objmgr.GetGuildByLeader(guid)) { WorldPacket data(SMSG_CHAR_DELETE, 1); data << (uint8)CHAR_DELETE_FAILED_GUILD_LEADER; SendPacket( &data ); return; } // is arena team captain if(objmgr.GetArenaTeamByCaptain(guid)) { WorldPacket data(SMSG_CHAR_DELETE, 1); data << (uint8)CHAR_DELETE_FAILED_ARENA_CAPTAIN; SendPacket( &data ); return; } QueryResult *result = CharacterDatabase.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(); delete result; } // prevent deleting other players' characters using cheating tools if(accountId != GetAccountId()) return; std::string IP_str = GetRemoteAddress(); sLog.outBasic("Account: %d (IP: %s) Delete Character:[%s] (guid:%u)",GetAccountId(),IP_str.c_str(),name.c_str(),GUID_LOPART(guid)); sLog.outChar("Account: %d (IP: %s) Delete Character:[%s] (guid: %u)",GetAccountId(),IP_str.c_str(),name.c_str(),GUID_LOPART(guid)); if(sLog.IsOutCharDump()) // optimize GetPlayerDump call { std::string dump = PlayerDumpWriter().GetDump(GUID_LOPART(guid)); sLog.outCharDump(dump.c_str(),GetAccountId(),GUID_LOPART(guid),name.c_str()); } Player::DeleteFromDB(guid, GetAccountId()); WorldPacket data(SMSG_CHAR_DELETE, 1); data << (uint8)CHAR_DELETE_SUCCESS; SendPacket( &data ); }
////////////////////////////////////////////////////////////// /// This function handles CMSG_GROUP_INVITE ////////////////////////////////////////////////////////////// void WorldSession::HandleGroupInviteOpcode(WorldPacket & recv_data) { CHECK_INWORLD_RETURN; CHECK_PACKET_SIZE(recv_data, 1); WorldPacket data(100); std::string membername; Group* group = NULL; recv_data >> membername; if(_player->HasBeenInvited()) return; Player* player = objmgr.GetPlayer(membername.c_str(), false); if(player == NULL) { SendPartyCommandResult(_player, 0, membername, ERR_PARTY_CANNOT_FIND); return; } if(player == _player) { return; } if (player->GetMapId() == 750 || _player->GetMapId() == 750) return; if(_player->InGroup() && !_player->IsGroupLeader()) { SendPartyCommandResult(_player, 0, "", ERR_PARTY_YOU_ARE_NOT_LEADER); return; } group = _player->GetGroup(); if(group != NULL) { if(group->IsFull()) { SendPartyCommandResult(_player, 0, "", ERR_PARTY_IS_FULL); return; } } if(player->InGroup()) { SendPartyCommandResult(_player, player->GetGroup()->GetGroupType(), membername, ERR_PARTY_ALREADY_IN_GROUP); data.SetOpcode(SMSG_GROUP_INVITE); data << uint8(0); data << GetPlayer()->GetName(); player->GetSession()->SendPacket(&data); return; } if(player->GetTeam() != _player->GetTeam() && _player->GetSession()->GetPermissionCount() == 0 && !sWorld.interfaction_group) { SendPartyCommandResult(_player, 0, membername, ERR_PARTY_WRONG_FACTION); return; } if(player->HasBeenInvited()) { SendPartyCommandResult(_player, 0, membername, ERR_PARTY_ALREADY_IN_GROUP); return; } if(player->Social_IsIgnoring(_player->GetLowGUID())) { SendPartyCommandResult(_player, 0, membername, ERR_PARTY_IS_IGNORING_YOU); return; } if(player->HasFlag(PLAYER_FLAGS, PLAYER_FLAG_GM) && !_player->GetSession()->HasPermissions()) { SendPartyCommandResult(_player, 0, membername, ERR_PARTY_CANNOT_FIND); return; } data.SetOpcode(SMSG_GROUP_INVITE); data << uint8(1); data << GetPlayer()->GetName(); player->GetSession()->SendPacket(&data); SendPartyCommandResult(_player, 0, membername, ERR_PARTY_NO_ERROR); // 16/08/06 - change to guid to prevent very unlikely event of a crash in deny, etc player->SetInviter(_player->GetLowGUID()); }
/*this procedure handles clients CMSG_REQUEST_PARTY_MEMBER_STATS request*/ void WorldSession::HandleRequestPartyMemberStatsOpcode( WorldPacket &recv_data ) { CHECK_PACKET_SIZE(recv_data, 8); sLog.outDebug("WORLD: Received CMSG_REQUEST_PARTY_MEMBER_STATS"); uint64 Guid; recv_data >> Guid; Player *player = objmgr.GetPlayer(Guid); if(!player) { WorldPacket data(SMSG_PARTY_MEMBER_STATS_FULL, 3+4+2); data << uint8(0); // only for SMSG_PARTY_MEMBER_STATS_FULL, probably arena/bg related data.appendPackGUID(Guid); data << (uint32) GROUP_UPDATE_FLAG_STATUS; data << (uint16) MEMBER_STATUS_OFFLINE; SendPacket(&data); return; } Unit *pet = player->GetCharmOrPet(); WorldPacket data(SMSG_PARTY_MEMBER_STATS_FULL, 4+2+2+2+1+2*6+8+1+8); data << uint8(0); // only for SMSG_PARTY_MEMBER_STATS_FULL, probably arena/bg related data.append(player->GetPackGUID()); uint32 mask1 = 0x00040BFF; // common mask, real flags used 0x000040BFF if(pet) mask1 = 0xFFFFFFFF; // for hunters and other classes with pets Powers powerType = player->getPowerType(); data << (uint32) mask1; // group update mask data << (uint16) MEMBER_STATUS_ONLINE; // member's online status data << (uint32) player->GetHealth(); // GROUP_UPDATE_FLAG_CUR_HP data << (uint32) player->GetMaxHealth(); // GROUP_UPDATE_FLAG_MAX_HP data << (uint8) powerType; // GROUP_UPDATE_FLAG_POWER_TYPE data << (uint16) player->GetPower(powerType); // GROUP_UPDATE_FLAG_CUR_POWER data << (uint16) player->GetMaxPower(powerType); // GROUP_UPDATE_FLAG_MAX_POWER data << (uint16) player->getLevel(); // GROUP_UPDATE_FLAG_LEVEL data << (uint16) player->GetZoneId(); // GROUP_UPDATE_FLAG_ZONE data << (uint16) player->GetPositionX(); // GROUP_UPDATE_FLAG_POSITION data << (uint16) player->GetPositionY(); // GROUP_UPDATE_FLAG_POSITION uint64 auramask = 0; size_t maskPos = data.wpos(); data << (uint64) auramask; // placeholder for(uint8 i = 0; i < MAX_AURAS; ++i) { if(uint32 aura = player->GetVisibleAura(i)) { auramask |= (uint64(1) << i); data << (uint32) aura; data << (uint8) 1; } } data.put<uint64>(maskPos,auramask); // GROUP_UPDATE_FLAG_AURAS if(pet) { Powers petpowertype = pet->getPowerType(); data << (uint64) pet->GetGUID(); // GROUP_UPDATE_FLAG_PET_GUID data << pet->GetName(); // GROUP_UPDATE_FLAG_PET_NAME data << (uint16) pet->GetDisplayId(); // GROUP_UPDATE_FLAG_PET_MODEL_ID data << (uint32) pet->GetHealth(); // GROUP_UPDATE_FLAG_PET_CUR_HP data << (uint32) pet->GetMaxHealth(); // GROUP_UPDATE_FLAG_PET_MAX_HP data << (uint8) petpowertype; // GROUP_UPDATE_FLAG_PET_POWER_TYPE data << (uint16) pet->GetPower(petpowertype); // GROUP_UPDATE_FLAG_PET_CUR_POWER data << (uint16) pet->GetMaxPower(petpowertype); // GROUP_UPDATE_FLAG_PET_MAX_POWER uint64 petauramask = 0; size_t petMaskPos = data.wpos(); data << (uint64) petauramask; // placeholder for(uint8 i = 0; i < MAX_AURAS; ++i) { if(uint32 petaura = pet->GetVisibleAura(i)) { petauramask |= (uint64(1) << i); data << (uint32) petaura; data << (uint8) 1; } } data.put<uint64>(petMaskPos,petauramask); // GROUP_UPDATE_FLAG_PET_AURAS data << (uint32) player->m_SeatData.dbc_seat; } else { data << (uint8) 0; // GROUP_UPDATE_FLAG_PET_NAME data << (uint64) 0; // GROUP_UPDATE_FLAG_PET_AURAS } SendPacket(&data); }
void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data ) { CHECK_PACKET_SIZE(recv_data, 8+1+1+1); sLog.outDebug("WORLD: CMSG_BATTLEMASTER_JOIN_ARENA"); recv_data.hexlike(); // ignore if we already in BG or BG queue if(_player->InBattleGround()) return; uint64 guid; // arena Battlemaster guid uint8 arenaslot; // 2v2, 3v3 or 5v5 uint8 asGroup; // asGroup uint8 isRated; // isRated Group * grp; recv_data >> guid >> arenaslot >> asGroup >> isRated; Creature *unit = ObjectAccessor::GetCreature(*_player, guid); if(!unit) return; if(!unit->isBattleMaster()) // it's not battle master return; uint8 arenatype = 0; uint32 arenaRating = 0; switch(arenaslot) { case 0: arenatype = ARENA_TYPE_2v2; break; case 1: arenatype = ARENA_TYPE_3v3; break; case 2: arenatype = ARENA_TYPE_5v5; break; default: sLog.outError("Unknown arena slot %u at HandleBattleGroundArenaJoin()", arenaslot); return; } //check existance BattleGround* bg = NULL; if( !(bg = sBattleGroundMgr.GetBattleGroundTemplate(BATTLEGROUND_AA)) ) { sLog.outError("Battleground: template bg (all arenas) not found"); return; } BattleGroundTypeId bgTypeId = bg->GetTypeID(); BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, arenatype); // check queueing conditions if(!asGroup) { // check if already in queue if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES) //player is already in this queue return; // check if has free queue slots if(!_player->HasFreeBattleGroundQueueId()) return; } else { grp = _player->GetGroup(); // no group found, error if(!grp) return; uint32 err = grp->CanJoinBattleGroundQueue(bgTypeId, bgQueueTypeId, arenatype, arenatype, (bool)isRated, arenaslot); if (err != BG_JOIN_ERR_OK) { SendBattleGroundOrArenaJoinError(err); return; } } uint32 ateamId = 0; if(isRated) { ateamId = _player->GetArenaTeamId(arenaslot); // check real arenateam existence only here (if it was moved to group->CanJoin .. () then we would ahve to get it twice) ArenaTeam * at = objmgr.GetArenaTeamById(ateamId); if(!at) { _player->GetSession()->SendNotInArenaTeamPacket(arenatype); return; } // get the team rating for queueing arenaRating = at->GetRating(); // the arenateam id must match for everyone in the group // get the personal ratings for queueing uint32 avg_pers_rating = 0; for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) { Player *member = itr->getSource(); // calc avg personal rating avg_pers_rating += member->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (arenaslot*6) + 5); } if( arenatype ) avg_pers_rating /= arenatype; // if avg personal rating is more than 150 points below the teams rating, the team will be queued against an opponent matching or similar to the average personal rating if(avg_pers_rating + 150 < arenaRating) arenaRating = avg_pers_rating; } if(asGroup) { GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, arenaRating, ateamId); sLog.outDebug("Battleground: arena join as group start"); if(isRated) sLog.outDebug("Battleground: arena team id %u, leader %s queued with rating %u for type %u",_player->GetArenaTeamId(arenaslot),_player->GetName(),arenaRating,arenatype); for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) { Player *member = itr->getSource(); if(!member) continue; uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId);// add to queue // store entry point coords (same as leader entry point) member->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation()); WorldPacket data; // send status packet (in queue) sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, member->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0, arenatype, isRated); member->GetSession()->SendPacket(&data); sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId); member->GetSession()->SendPacket(&data); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(member, ginfo); sLog.outDebug("Battleground: player joined queue for arena as group bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName()); } sLog.outDebug("Battleground: arena join as group end"); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId), arenatype, isRated, arenaRating); if(isRated) sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AnnounceWorld(ginfo, _player->GetGUID(), true); } else { uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId); // store entry point coords _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation()); WorldPacket data; // send status packet (in queue) sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0, arenatype, isRated); SendPacket(&data); GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, arenaRating); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId), arenatype, isRated, arenaRating); sLog.outDebug("Battleground: player joined queue for arena, skirmish, bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName()); } }
////////////////////////////////////////////////////////////// /// This function handles CMSG_GROUP_INVITE ////////////////////////////////////////////////////////////// void WorldSession::HandleGroupInviteOpcode( WorldPacket & recv_data ) { if(!_player->IsInWorld()) return; CHECK_PACKET_SIZE(recv_data, 1); WorldPacket data(100); std::string membername; Player * player = NULL; Group *group = NULL; recv_data >> membername; if(_player->HasBeenInvited())return; player = objmgr.GetPlayer(membername.c_str(), false); if ( player == NULL) { SendPartyCommandResult(_player, 0, membername, ERR_PARTY_CANNOT_FIND); return; } if (player == _player) { return; } if ( _player->InGroup() && (!_player->IsGroupLeader() || _player->GetGroup()->HasFlag(GROUP_FLAG_BATTLEGROUND_GROUP) ) ) { SendPartyCommandResult(_player, 0, "", ERR_PARTY_YOU_ARE_NOT_LEADER); return; } group = _player->GetGroup(); if ( group != NULL ) { if (group->IsFull()) { SendPartyCommandResult(_player, 0, "", ERR_PARTY_IS_FULL); return; } } if ( player->InGroup() ) { SendPartyCommandResult(_player, player->GetGroup()->GetGroupType(), membername, ERR_PARTY_ALREADY_IN_GROUP); return; } if(player->GetTeam()!=_player->GetTeam() && _player->GetSession()->GetPermissionCount() == 0) { SendPartyCommandResult(_player, 0, membername, ERR_PARTY_WRONG_FACTION); return; } if ( player->HasBeenInvited() ) { SendPartyCommandResult(_player, 0, membername, ERR_PARTY_ALREADY_IN_GROUP); return; } if( player->Social_IsIgnoring( _player->GetLowGUID() ) ) { SendPartyCommandResult(_player, 0, membername, ERR_PARTY_IS_IGNORING_YOU); return; } if( player->bGMTagOn && !_player->GetSession()->HasPermissions()) { SendPartyCommandResult(_player, 0, membername, ERR_PARTY_CANNOT_FIND); return; } // 16/08/06 - change to guid to prevent very unlikely event of a crash in deny, etc _player->SetInviter(_player->GetLowGUID());//bugfix if player invtied 2 people-> he can be in 2 parties data.SetOpcode(SMSG_GROUP_INVITE); data << GetPlayer()->GetName(); player->GetSession()->SendPacket(&data); uint32 gtype = 0; if(group) gtype = group->GetGroupType(); SendPartyCommandResult(_player, gtype, membername, ERR_PARTY_NO_ERROR); // 16/08/06 - change to guid to prevent very unlikely event of a crash in deny, etc player->SetInviter(_player->GetLowGUID()); }
////////////////////////////////////////////////////////////// /// This function handles CMSG_GAMEOBJECT_QUERY: ////////////////////////////////////////////////////////////// void WorldSession::HandleGameObjectQueryOpcode(WorldPacket & recv_data) { CHECK_INWORLD_RETURN CHECK_PACKET_SIZE(recv_data, 12); WorldPacket data(SMSG_GAMEOBJECT_QUERY_RESPONSE, 900); uint32 entryID; uint64 guid; GameObjectInfo* goinfo; recv_data >> entryID; recv_data >> guid; LOG_DETAIL("WORLD: CMSG_GAMEOBJECT_QUERY '%u'", entryID); goinfo = GameObjectNameStorage.LookupEntry(entryID); if(goinfo == NULL) return; LocalizedGameObjectName* lgn = (language > 0) ? sLocalizationMgr.GetLocalizedGameObjectName(entryID, language) : NULL; data << entryID; // unique identifier of the GO template data << goinfo->Type; // type of the gameobject data << goinfo->DisplayID; // displayid/modelid of the gameobject // Name of the gameobject if(lgn) data << lgn->Name; else data << goinfo->Name; data << uint8(0); // name2, always seems to be empty data << uint8(0); // name3, always seems to be empty data << uint8(0); // name4, always seems to be empty data << goinfo->Category; // Category string of the GO, like "attack", "pvp", "point", etc data << goinfo->Castbartext; // text displayed when using the go, like "collecting", "summoning" etc data << goinfo->Unkstr; data << goinfo->SpellFocus; // spellfocus id, ex.: spell casted when interacting with the GO data << goinfo->sound1; data << goinfo->sound2; data << goinfo->sound3; data << goinfo->sound4; data << goinfo->sound5; data << goinfo->sound6; data << goinfo->sound7; data << goinfo->sound8; data << goinfo->sound9; data << goinfo->Unknown1; data << goinfo->Unknown2; data << goinfo->Unknown3; data << goinfo->Unknown4; data << goinfo->Unknown5; data << goinfo->Unknown6; data << goinfo->Unknown7; data << goinfo->Unknown8; data << goinfo->Unknown9; data << goinfo->Unknown10; data << goinfo->Unknown11; data << goinfo->Unknown12; data << goinfo->Unknown13; data << goinfo->Unknown14; data << float(goinfo->Size); // scaling of the GO // questitems that the go can contain for(uint32 i = 0; i < 6; ++i) { data << uint32(goinfo->QuestItems[i]); } SendPacket(&data); }
void WorldSession::HandleCharacterCustomization( WorldPacket & recv_data ) { CHECK_PACKET_SIZE(recv_data, 16); uint64 guid; recv_data >> guid; PlayerInfo * pInfo = objmgr.GetPlayerInfo((uint32)guid); if(pInfo == NULL) return; if(pInfo->acct != _accountId) { Disconnect(); // Cheater return; } QueryResult * result = CharacterDatabase.Query("SELECT recustomize FROM characters WHERE guid = %u AND acct = %u", (uint32)guid, _accountId); if(result == 0) { delete result; return; } uint32 recustomize = result[0].Fetch()[0].GetUInt32(); if(recustomize == 0 && !CanUseCommand('z')) { delete result; return; } delete result; string name; recv_data >> name; if(!VerifyName(name.c_str(), name.length())) { uint8 err = CHAR_NAME_INVALID_CHARACTER; OutPacket(SMSG_CHAR_CUSTOMIZE, 1, &err); return; } if(g_characterNameFilter->Parse(name, false)) { uint8 err = CHAR_NAME_RESERVED; OutPacket(SMSG_CHAR_CUSTOMIZE, 1, &err); return; } if(strcmp(pInfo->name, name.c_str()) && objmgr.GetPlayerInfoByName(name.c_str()) != 0) { uint8 err = CHAR_CREATE_NAME_IN_USE; OutPacket(SMSG_CHAR_CUSTOMIZE, 1, &err); return; } result = CharacterDatabase.Query("SELECT COUNT(*) FROM banned_names WHERE name = '%s'", CharacterDatabase.EscapeString(name).c_str()); if(result) { if(result->Fetch()[0].GetUInt32() > 0) { // That name is banned! uint8 err = CHAR_CREATE_NAME_IN_USE; OutPacket(SMSG_CHAR_CUSTOMIZE, 1, &err); // You cannot use that name delete result; return; } delete result; } CapitalizeString(name); // Correct capitalization uint8 gender,skin,face,hairStyle,hairColor,facialHair; recv_data >> gender >> skin >> hairColor >> hairStyle >> facialHair >> face; result = CharacterDatabase.Query("SELECT bytes2 FROM characters WHERE guid = '%u'", (uint32)guid); if(result == NULL) return; Field * f = result->Fetch(); uint32 bytes2 = f[0].GetUInt32(); bytes2 &= 0xFFFFFF00; // Delete facial hair bytes2 |= facialHair; uint32 bytes = ((skin) | (face << 8) | (hairStyle << 16) | (hairColor << 24)); pInfo->gender = gender; objmgr.RenamePlayerInfo(pInfo, pInfo->name, name.c_str()); CharacterDatabase.WaitExecute("UPDATE characters SET name = '%s', gender = '%u', bytes = '%u', bytes2 = '%u', recustomize = 0 WHERE guid = '%u'", name.c_str(), gender, bytes, bytes2, (uint32)guid); WorldPacket data(SMSG_CHAR_CUSTOMIZE, 15+(name.size()+1)); data << uint8(RESPONSE_SUCCESS); data << uint64(guid); data << name; data << uint8(gender); data << uint8(skin); data << uint8(face); data << uint8(hairStyle); data << uint8(hairColor); data << uint8(facialHair); SendPacket(&data); Log.Debug("CharacterHandler", "Received CMSG_CHAR_CUSTOMIZE."); }
void WorldSession::HandleTrainerBuySpellOpcode( WorldPacket & recv_data ) { CHECK_PACKET_SIZE(recv_data,8+4); uint64 guid; uint32 spellId = 0; recv_data >> guid >> spellId; sLog.outDebug( "WORLD: Received CMSG_TRAINER_BUY_SPELL NpcGUID=%u, learn spell id is: %u",uint32(GUID_LOPART(guid)), spellId ); Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid, UNIT_NPC_FLAG_TRAINER); if (!unit) { sLog.outDebug( "WORLD: HandleTrainerBuySpellOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) ); return; } // remove fake death if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); if(!unit->isCanTrainingOf(_player,true)) return; // check present spell in trainer spell list TrainerSpellData const* trainer_spells = unit->GetTrainerSpells(); if(!trainer_spells) return; // not found, cheat? TrainerSpell const* trainer_spell = trainer_spells->Find(spellId); if(!trainer_spell) return; // can't be learn, cheat? Or double learn with lags... if(_player->GetTrainerSpellState(trainer_spell) != TRAINER_SPELL_GREEN) return; // apply reputation discount uint32 nSpellCost = uint32(floor(trainer_spell->spellCost * _player->GetReputationPriceDiscount(unit))); // check money requirement if(_player->GetMoney() < nSpellCost ) return; _player->ModifyMoney( -int32(nSpellCost) ); WorldPacket data(SMSG_PLAY_SPELL_VISUAL, 12); // visual effect on trainer data << uint64(guid) << uint32(0xB3); SendPacket(&data); data.Initialize(SMSG_PLAY_SPELL_IMPACT, 12); // visual effect on player data << uint64(_player->GetGUID()) << uint32(0x016A); SendPacket(&data); // learn explicitly or cast explicitly if(trainer_spell->IsCastable ()) //FIXME: prof. spell entry in trainer list not marked gray until list re-open. _player->CastSpell(_player,trainer_spell->spell,true); else _player->learnSpell(spellId,false); data.Initialize(SMSG_TRAINER_BUY_SUCCEEDED, 12); data << uint64(guid) << uint32(trainer_spell->spell); SendPacket(&data); }
void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data ) { CHECK_PACKET_SIZE(recv_data, 10); std::string name; uint8 race, class_; recv_data >> name >> race >> class_; recv_data.rpos(0); if(!VerifyName(name.c_str(), name.length())) { OutPacket(SMSG_CHAR_CREATE, 1, "\x32"); return; } if(g_characterNameFilter->Parse(name, false)) { OutPacket(SMSG_CHAR_CREATE, 1, "\x32"); return; } //reserved for console whisper if(name == "Console" || name == "console") { OutPacket(SMSG_CHAR_CREATE, 1, "\x32"); return; } if(objmgr.GetPlayerInfoByName(name.c_str()) != 0) { OutPacket(SMSG_CHAR_CREATE, 1, "\x32"); return; } if(!sHookInterface.OnNewCharacter(race, class_, this, name.c_str())) { OutPacket(SMSG_CHAR_CREATE, 1, "\x32"); return; } if( class_ == CLASS_DEATHKNIGHT && (!HasFlag(ACCOUNT_FLAG_XPACK_02) || !CanCreateDeathKnight() ) ) { OutPacket(SMSG_CHAR_CREATE, 1, "\x3B"); return; } QueryResult * result = CharacterDatabase.Query("SELECT COUNT(*) FROM banned_names WHERE name = '%s'", CharacterDatabase.EscapeString(name).c_str()); if(result) { if(result->Fetch()[0].GetUInt32() > 0) { // That name is banned! OutPacket(SMSG_CHAR_CREATE, 1, "\x51"); // You cannot use that name delete result; return; } delete result; } // loading characters // checking number of chars is useless since client will not allow to create more than 10 chars // as the 'create' button will not appear (unless we want to decrease maximum number of characters) Player* pNewChar = objmgr.CreatePlayer(); pNewChar->SetSession(this); if(!pNewChar->Create( recv_data )) { // Player not create (race/class problem?) pNewChar->ok_to_remove = true; pNewChar->Destructor(); pNewChar = NULL; return; } pNewChar->UnSetBanned(); pNewChar->addSpell(22027); // Remove Insignia if(pNewChar->getClass() == CLASS_WARLOCK) { pNewChar->AddSummonSpell(416, 3110); // imp fireball pNewChar->AddSummonSpell(417, 19505); pNewChar->AddSummonSpell(1860, 3716); pNewChar->AddSummonSpell(1863, 7814); } // Player created, save it now pNewChar->SaveToDB(true); PlayerInfo *pn=new PlayerInfo; memset(pn, 0, sizeof(PlayerInfo)); pn->guid = pNewChar->GetLowGUID(); pn->name = strdup(pNewChar->GetName()); pn->cl = pNewChar->getClass(); pn->race = pNewChar->getRace(); pn->gender = pNewChar->getGender(); pn->lastLevel = pNewChar->getLevel(); pn->lastZone = pNewChar->GetZoneId(); pn->lastOnline = UNIXTIME; pn->team = pNewChar->GetTeam(); pn->acct = GetAccountId(); objmgr.AddPlayerInfo(pn); pNewChar->ok_to_remove = true; pNewChar->Destructor(); pNewChar = NULL; // CHAR_CREATE_SUCCESS OutPacket(SMSG_CHAR_CREATE, 1, "\x2F"); sLogonCommHandler.UpdateAccountCount(GetAccountId(), 1); m_lastEnumTime = 0; }
void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) { // TODO: add targets.read() check CHECK_PACKET_SIZE(recvPacket,1+1+1+1+8); Player* pUser = _player; uint8 bagIndex, slot; uint8 spell_count; // number of spells at item, not used uint8 cast_count; // next cast if exists (single or not) uint64 item_guid; recvPacket >> bagIndex >> slot >> spell_count >> cast_count >> item_guid; Item *pItem = pUser->GetItemByPos(bagIndex, slot); if(!pItem) { pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL ); return; } if(pItem->GetGUID() != item_guid) { pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL ); return; } sLog.outDetail("WORLD: CMSG_USE_ITEM packet, bagIndex: %u, slot: %u, spell_count: %u , cast_count: %u, Item: %u, data length = %i", bagIndex, slot, spell_count, cast_count, pItem->GetEntry(), recvPacket.size()); ItemPrototype const *proto = pItem->GetProto(); if(!proto) { pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL ); return; } // some item classes can be used only in equipped state if(proto->InventoryType != INVTYPE_NON_EQUIP && !pItem->IsEquipped()) { pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL ); return; } uint8 msg = pUser->CanUseItem(pItem); if( msg != EQUIP_ERR_OK ) { pUser->SendEquipError( msg, pItem, NULL ); return; } // only allow conjured consumable, bandage, poisons (all should have the 2^21 item flag set in DB) if( proto->Class == ITEM_CLASS_CONSUMABLE && !(proto->Flags & ITEM_FLAGS_USEABLE_IN_ARENA) && pUser->InArena()) { pUser->SendEquipError(EQUIP_ERR_NOT_DURING_ARENA_MATCH,pItem,NULL); return; } if (pUser->isInCombat()) { for(int i = 0; i < 5; ++i) { if (SpellEntry const *spellInfo = sSpellStore.LookupEntry(proto->Spells[i].SpellId)) { if (IsNonCombatSpell(spellInfo)) { pUser->SendEquipError(EQUIP_ERR_NOT_IN_COMBAT,pItem,NULL); return; } } } } // check also BIND_WHEN_PICKED_UP and BIND_QUEST_ITEM for .additem or .additemset case by GM (not binded at adding to inventory) if( pItem->GetProto()->Bonding == BIND_WHEN_USE || pItem->GetProto()->Bonding == BIND_WHEN_PICKED_UP || pItem->GetProto()->Bonding == BIND_QUEST_ITEM ) { if (!pItem->IsSoulBound()) { pItem->SetState(ITEM_CHANGED, pUser); pItem->SetBinding( true ); } } SpellCastTargets targets; if(!targets.read(&recvPacket, pUser)) return; //Note: If script stop casting it must send appropriate data to client to prevent stuck item in gray state. if(!Script->ItemUse(pUser,pItem,targets)) { // no script or script not process request by self // special learning case if(pItem->GetProto()->Spells[0].SpellId==SPELL_ID_GENERIC_LEARN) { uint32 learning_spell_id = pItem->GetProto()->Spells[1].SpellId; SpellEntry const *spellInfo = sSpellStore.LookupEntry(SPELL_ID_GENERIC_LEARN); if(!spellInfo) { sLog.outError("Item (Entry: %u) in have wrong spell id %u, ignoring ",proto->ItemId, SPELL_ID_GENERIC_LEARN); pUser->SendEquipError(EQUIP_ERR_NONE,pItem,NULL); return; } Spell *spell = new Spell(pUser, spellInfo, false); spell->m_CastItem = pItem; spell->m_cast_count = cast_count; //set count of casts spell->m_currentBasePoints[0] = learning_spell_id; spell->prepare(&targets); return; } // use triggered flag only for items with many spell casts and for not first cast int count = 0; for(int i = 0; i < 5; ++i) { _Spell const& spellData = pItem->GetProto()->Spells[i]; // no spell if(!spellData.SpellId) continue; // wrong triggering type if( spellData.SpellTrigger != ITEM_SPELLTRIGGER_ON_USE && spellData.SpellTrigger != ITEM_SPELLTRIGGER_ON_NO_DELAY_USE) continue; SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellData.SpellId); if(!spellInfo) { sLog.outError("Item (Entry: %u) in have wrong spell id %u, ignoring ",proto->ItemId, spellData.SpellId); continue; } Spell *spell = new Spell(pUser, spellInfo, (count > 0)); spell->m_CastItem = pItem; spell->m_cast_count = cast_count; //set count of casts spell->prepare(&targets); ++count; } } }
//called when player takes item attached in mail void WorldSession::HandleTakeItem(WorldPacket & recv_data ) { CHECK_PACKET_SIZE(recv_data,8+4+4); uint64 mailbox; uint32 mailId; uint32 itemId; recv_data >> mailbox; recv_data >> mailId; recv_data >> itemId; // item guid low? Player* pl = _player; Mail* m = pl->GetMail(mailId); if(!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL)) { pl->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_INTERNAL_ERROR); return; } // prevent cheating with skip client money check if(pl->GetMoney() < m->COD) { pl->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_NOT_ENOUGH_MONEY); return; } Item *it = pl->GetMItem(itemId); ItemPosCountVec dest; uint8 msg = _player->CanStoreItem( NULL_BAG, NULL_SLOT, dest, it, false ); if( msg == EQUIP_ERR_OK ) { m->RemoveItem(itemId); m->removedItems.push_back(itemId); if (m->COD > 0) //if there is COD, take COD money from player and send them to sender by mail { uint64 sender_guid = MAKE_NEW_GUID(m->sender, 0, HIGHGUID_PLAYER); Player *receive = objmgr.GetPlayer(sender_guid); uint32 sender_accId = 0; if( GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) ) { std::string sender_name; if(receive) { sender_accId = receive->GetSession()->GetAccountId(); sender_name = receive->GetName(); } else { // can be calculated early sender_accId = objmgr.GetPlayerAccountIdByGUID(sender_guid); if(!objmgr.GetPlayerNameByGUID(sender_guid,sender_name)) sender_name = objmgr.GetTrinityStringForDBCLocale(LANG_UNKNOWN); } sLog.outCommand(GetAccountId(),"GM %s (Account: %u) receive mail item: %s (Entry: %u Count: %u) and send COD money: %u to player: %s (Account: %u)", GetPlayerName(),GetAccountId(),it->GetProto()->Name1,it->GetEntry(),it->GetCount(),m->COD,sender_name.c_str(),sender_accId); } else if(!receive) sender_accId = objmgr.GetPlayerAccountIdByGUID(sender_guid); // check player existence if(receive || sender_accId) { WorldSession::SendMailTo(receive, MAIL_NORMAL, MAIL_STATIONERY_NORMAL, m->receiver, m->sender, m->subject, 0, NULL, m->COD, 0, MAIL_CHECK_MASK_COD_PAYMENT); } pl->ModifyMoney( -int32(m->COD) ); } m->COD = 0; m->state = MAIL_STATE_CHANGED; pl->m_mailsUpdated = true; pl->RemoveMItem(it->GetGUIDLow()); uint32 count = it->GetCount(); // save counts before store and possible merge with deleting pl->MoveItemToInventory(dest,it,true); CharacterDatabase.BeginTransaction(); pl->SaveInventoryAndGoldToDB(); pl->_SaveMail(); CharacterDatabase.CommitTransaction(); pl->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_OK, 0, itemId, count); } else pl->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_BAG_FULL, msg); }
void WorldSession::HandleAutostoreLootItemOpcode( WorldPacket & recv_data ) { CHECK_PACKET_SIZE(recv_data,1); sLog.outDebug("WORLD: CMSG_AUTOSTORE_LOOT_ITEM"); Player *player = GetPlayer(); uint64 lguid = player->GetLootGUID(); Loot *loot; uint8 lootSlot; recv_data >> lootSlot; if (IS_GAMEOBJECT_GUID(lguid)) { GameObject *go = ObjectAccessor::GetGameObject(*player, lguid); // not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO if (!go || (go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player,INTERACTION_DISTANCE)) { player->SendLootRelease(lguid); return; } loot = &go->loot; } else if (IS_ITEM_GUID(lguid)) { Item *pItem = player->GetItemByGuid( lguid ); if (!pItem) { player->SendLootRelease(lguid); return; } loot = &pItem->loot; } else if (IS_CORPSE_GUID(lguid)) { Corpse *bones = ObjectAccessor::GetCorpse(*player, lguid); if (!bones) { player->SendLootRelease(lguid); return; } loot = &bones->loot; } else { Creature* pCreature = ObjectAccessor::GetCreature(*player, lguid); bool ok_loot = pCreature && pCreature->isAlive() == (player->getClass()==CLASS_ROGUE && pCreature->lootForPickPocketed); if( !ok_loot || !pCreature->IsWithinDistInMap(_player,INTERACTION_DISTANCE) ) { player->SendLootRelease(lguid); return; } loot = &pCreature->loot; } QuestItem *qitem = NULL; QuestItem *ffaitem = NULL; QuestItem *conditem = NULL; LootItem *item = loot->LootItemInSlot(lootSlot,player,&qitem,&ffaitem,&conditem); if(!item) { player->SendEquipError( EQUIP_ERR_ALREADY_LOOTED, NULL, NULL ); return; } // questitems use the blocked field for other purposes if (!qitem && item->is_blocked) { player->SendLootRelease(lguid); return; } ItemPosCountVec dest; uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, item->itemid, item->count ); if ( msg == EQUIP_ERR_OK ) { Item * newitem = player->StoreNewItem( dest, item->itemid, true, item->randomPropertyId); if (qitem) { qitem->is_looted = true; //freeforall is 1 if everyone's supposed to get the quest item. if (item->freeforall || loot->GetPlayerQuestItems().size() == 1) player->SendNotifyLootItemRemoved(lootSlot); else loot->NotifyQuestItemRemoved(qitem->index); } else { if (ffaitem) { //freeforall case, notify only one player of the removal ffaitem->is_looted=true; player->SendNotifyLootItemRemoved(lootSlot); } else { //not freeforall, notify everyone if(conditem) conditem->is_looted=true; loot->NotifyItemRemoved(lootSlot); } } //if only one person is supposed to loot the item, then set it to looted if (!item->freeforall) item->is_looted = true; --loot->unlootedCount; player->SendNewItem(newitem, uint32(item->count), false, false, true); player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item->itemid, item->count); } else player->SendEquipError( msg, NULL, NULL ); }
void WorldSession::HandleSendMail(WorldPacket & recv_data ) { CHECK_PACKET_SIZE(recv_data,8+1+1+1+4+4+1+4+4+8+1); uint64 mailbox, unk3; std::string receiver, subject, body; uint32 unk1, unk2, money, COD; uint8 unk4; recv_data >> mailbox; 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 MailItemsInfo mi; uint8 items_count; recv_data >> items_count; // attached items count if(items_count > 12) // client limit 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); if(items_count) { for(uint8 i = 0; i < items_count; ++i) { uint8 item_slot; uint64 item_guid; recv_data >> item_slot; recv_data >> item_guid; mi.AddItem(GUID_LOPART(item_guid), item_slot); } } recv_data >> money >> COD; // money and cod recv_data >> unk3; // const 0 recv_data >> unk4; // const 0 items_count = mi.size(); // this is the real size after the duplicates have been removed if (receiver.empty()) return; Player* pl = _player; uint64 rc = 0; if(normalizePlayerName(receiver)) rc = objmgr.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 = objmgr.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 = objmgr.GetPlayerTeamByGUID(rc); QueryResult* result = CharacterDatabase.PQuery("SELECT COUNT(*) FROM mail WHERE receiver = '%u'", GUID_LOPART(rc)); if(result) { Field *fields = result->Fetch(); mails_count = fields[0].GetUInt32(); delete result; } } //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 && GetSecurity() == SEC_PLAYER) { pl->SendMailResult(0, 0, MAIL_ERR_NOT_YOUR_TEAM); return; } if (items_count) { for(MailItemMap::iterator mailItemIter = mi.begin(); mailItemIter != mi.end(); ++mailItemIter) { MailItem& mailItem = mailItemIter->second; if(!mailItem.item_guidlow) { pl->SendMailResult(0, 0, MAIL_ERR_INTERNAL_ERROR); return; } mailItem.item = pl->GetItemByGuid(MAKE_NEW_GUID(mailItem.item_guidlow, 0, HIGHGUID_ITEM)); // prevent sending bag with items (cheat: can be placed in bag after adding equipped empty bag to mail) if(!mailItem.item || !mailItem.item->CanBeTraded()) { pl->SendMailResult(0, 0, MAIL_ERR_INTERNAL_ERROR); return; } if (mailItem.item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_CONJURED) || mailItem.item->GetUInt32Value(ITEM_FIELD_DURATION)) { pl->SendMailResult(0, 0, MAIL_ERR_INTERNAL_ERROR); return; } if(COD && mailItem.item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED)) { pl->SendMailResult(0, 0, MAIL_ERR_CANT_SEND_WRAPPED_COD); return; } } } pl->SendMailResult(0, 0, MAIL_OK); uint32 itemTextId = 0; if (!body.empty()) { itemTextId = objmgr.CreateItemText( body ); } pl->ModifyMoney( -int32(reqmoney) ); bool needItemDelay = false; if(items_count > 0 || money > 0) { uint32 rc_account = 0; if(receive) rc_account = receive->GetSession()->GetAccountId(); else rc_account = objmgr.GetPlayerAccountIdByGUID(rc); if (items_count > 0) { for(MailItemMap::iterator mailItemIter = mi.begin(); mailItemIter != mi.end(); ++mailItemIter) { MailItem& mailItem = mailItemIter->second; if(!mailItem.item) continue; mailItem.item_template = mailItem.item ? mailItem.item->GetEntry() : 0; if( GetSecurity() > SEC_PLAYER && 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(), mailItem.item->GetProto()->Name1, mailItem.item->GetEntry(), mailItem.item->GetCount(), receiver.c_str(), rc_account); } pl->MoveItemFromInventory(mailItem.item->GetBagSlot(), mailItem.item->GetSlot(), true); CharacterDatabase.BeginTransaction(); mailItem.item->DeleteFromInventoryDB(); //deletes item from character's inventory mailItem.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 CharacterDatabase.PExecute("UPDATE item_instance SET owner_guid = '%u' WHERE guid='%u'", GUID_LOPART(rc), mailItem.item->GetGUIDLow()); CharacterDatabase.CommitTransaction(); } // if item send to character at another account, then apply item delivery delay needItemDelay = pl->GetSession()->GetAccountId() != rc_account; } if(money > 0 && GetSecurity() > SEC_PLAYER && 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 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; // will delete item or place to receiver mail list WorldSession::SendMailTo(receive, MAIL_NORMAL, MAIL_STATIONERY_NORMAL, pl->GetGUIDLow(), GUID_LOPART(rc), subject, itemTextId, &mi, money, COD, MAIL_CHECK_MASK_NONE, deliver_delay); CharacterDatabase.BeginTransaction(); pl->SaveInventoryAndGoldToDB(); CharacterDatabase.CommitTransaction(); }
////////////////////////////////////////////////////////////// /// This function handles CMSG_CREATURE_QUERY: ////////////////////////////////////////////////////////////// void WorldSession::HandleCreatureQueryOpcode( WorldPacket & recv_data ) { CHECK_PACKET_SIZE(recv_data, 12); WorldPacket data(SMSG_CREATURE_QUERY_RESPONSE, 150); uint32 entry; uint64 guid; CreatureInfo *ci; recv_data >> entry; recv_data >> guid; if(entry == 300000) { data << (uint32)entry; data << "WayPoint"; data << uint8(0) << uint8(0) << uint8(0); data << "Level is WayPoint ID"; for(uint32 i = 0; i < 8;i++) { data << uint32(0); } data << uint8(0); } else { ci = CreatureNameStorage.LookupEntry(entry); if(ci == NULL) return; LocalizedCreatureName * lcn = (language>0) ? sLocalizationMgr.GetLocalizedCreatureName(entry, language) : NULL; if(lcn == NULL) { sLog.outDetail("WORLD: CMSG_CREATURE_QUERY '%s'", ci->Name); data << (uint32)entry; data << ci->Name; data << uint8(0) << uint8(0) << uint8(0); data << ci->SubName; } else { sLog.outDetail("WORLD: CMSG_CREATURE_QUERY '%s' (localized to %s)", ci->Name, lcn->Name); data << (uint32)entry; data << lcn->Name; data << uint8(0) << uint8(0) << uint8(0); data << lcn->SubName; } data << ci->info_str; //!!! this is a string in 2.3.0 Example: stormwind guard has : "Direction" data << ci->Flags1; data << ci->Type; data << ci->Family; data << ci->Rank; data << ci->Unknown1; data << ci->SpellDataID; data << ci->Male_DisplayID; data << ci->Female_DisplayID; data << ci->Male_DisplayID2; data << ci->Female_DisplayID2; data << ci->unkfloat1; data << ci->unkfloat2; data << ci->Leader; } SendPacket( &data ); }
void WorldSession::HandleSellItemOpcode( WorldPacket & recv_data ) { CHECK_PACKET_SIZE(recv_data,8+8+1); sLog.outDebug( "WORLD: Received CMSG_SELL_ITEM" ); uint64 vendorguid, itemguid; uint8 _count; recv_data >> vendorguid >> itemguid >> _count; // prevent possible overflow, as mangos uses uint32 for item count uint32 count = _count; if(!itemguid) return; Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, vendorguid,UNIT_NPC_FLAG_VENDOR); if (!pCreature) { sLog.outDebug( "WORLD: HandleSellItemOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(vendorguid)) ); _player->SendSellError( SELL_ERR_CANT_FIND_VENDOR, NULL, itemguid, 0); return; } // remove fake death if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); Item *pItem = _player->GetItemByGuid( itemguid ); if( pItem ) { // prevent sell not owner item if(_player->GetGUID()!=pItem->GetOwnerGUID()) { _player->SendSellError( SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); return; } // prevent sell non empty bag by drag-and-drop at vendor's item list if(pItem->IsBag() && !((Bag*)pItem)->IsEmpty()) { _player->SendSellError( SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); return; } // prevent sell currently looted item if(_player->GetLootGUID()==pItem->GetGUID()) { _player->SendSellError( SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); return; } // special case at auto sell (sell all) if(count==0) { count = pItem->GetCount(); } else { // prevent sell more items that exist in stack (possable only not from client) if(count > pItem->GetCount()) { _player->SendSellError( SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); return; } } ItemPrototype const *pProto = pItem->GetProto(); if( pProto ) { if( pProto->SellPrice > 0 ) { if(count < pItem->GetCount()) // need split items { Item *pNewItem = pItem->CloneItem( count, _player ); if (!pNewItem) { sLog.outError("WORLD: HandleSellItemOpcode - could not create clone of item %u; count = %u", pItem->GetEntry(), count ); _player->SendSellError( SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); return; } pItem->SetCount( pItem->GetCount() - count ); _player->ItemRemovedQuestCheck( pItem->GetEntry(), count ); if( _player->IsInWorld() ) pItem->SendUpdateToPlayer( _player ); pItem->SetState(ITEM_CHANGED, _player); _player->AddItemToBuyBackSlot( pNewItem ); if( _player->IsInWorld() ) pNewItem->SendUpdateToPlayer( _player ); } else { _player->ItemRemovedQuestCheck( pItem->GetEntry(), pItem->GetCount()); _player->RemoveItem( pItem->GetBagSlot(), pItem->GetSlot(), true); pItem->RemoveFromUpdateQueueOf(_player); _player->AddItemToBuyBackSlot( pItem ); } _player->ModifyMoney( pProto->SellPrice * count ); } else _player->SendSellError( SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); return; } } _player->SendSellError( SELL_ERR_CANT_FIND_ITEM, pCreature, itemguid, 0); return; }