void BattleGroundNA::HandleAreaTrigger(Player *Source, uint32 Trigger) { // this is wrong way to implement these things. On official it done by gameobject spell cast. if(GetStatus() != STATUS_IN_PROGRESS) return; uint32 SpellId = 0; uint64 buff_guid = 0; switch(Trigger) { case 4536: // buff trigger? case 4537: // buff trigger? break; default: sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger); Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger); break; } if(buff_guid) { GameObject *obj = HashMapHolder<GameObject>::Find(buff_guid); if(obj) { if(!obj->isSpawned()) return; // buff not spawned yet obj->SetRespawnTime(BUFF_RESPAWN_TIME); obj->SetLootState(GO_LOOTED); SpellId = obj->GetGOInfo()->data3; if(SpellId) Source->CastSpell(Source, SpellId, true); } } }
static bool HandleGameObjectActivateCommand(ChatHandler* handler, char const* args) { if (!*args) return false; char* id = handler->extractKeyFromLink((char*)args, "Hgameobject"); if (!id) return false; ObjectGuid::LowType guidLow = atoul(id); if (!guidLow) return false; GameObject* object = handler->GetObjectFromPlayerMapByDbGuid(guidLow); if (!object) { handler->PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, guidLow); handler->SetSentErrorMessage(true); return false; } uint32_t const autoCloseTime = object->GetGOInfo()->GetAutoCloseTime() ? 10000u : 0u; // Activate object->SetLootState(GO_READY); object->UseDoorOrButton(autoCloseTime, false, handler->GetSession()->GetPlayer()); handler->PSendSysMessage("Object activated!"); return true; }
//move selected object static bool HandleGameObjectMoveCommand(ChatHandler* handler, char const* args) { uint32 guidLow = GetGuidLowFromArgsOrLastTargetedGo(handler, args); if (!guidLow) return false; GameObject* object = NULL; // by DB guid if (GameObjectData const* gameObjectData = sObjectMgr->GetGOData(guidLow)) object = handler->GetObjectGlobalyWithGuidOrNearWithDbGuid(guidLow, gameObjectData->id); if (!object) { handler->PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, guidLow); handler->SetSentErrorMessage(true); return false; } char* toX = strtok(NULL, " "); char* toY = strtok(NULL, " "); char* toZ = strtok(NULL, " "); if (!toX) { Player* player = handler->GetSession()->GetPlayer(); object->Relocate(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), object->GetOrientation()); object->DestroyForNearbyPlayers(); object->UpdateObjectVisibility(); } else { if (!toY || !toZ) return false; float x = (float)atof(toX); float y = (float)atof(toY); float z = (float)atof(toZ); if (!MapManager::IsValidMapCoord(object->GetMapId(), x, y, z)) { handler->PSendSysMessage(LANG_INVALID_TARGET_COORD, x, y, object->GetMapId()); handler->SetSentErrorMessage(true); return false; } object->Relocate(x, y, z, object->GetOrientation()); object->DestroyForNearbyPlayers(); object->UpdateObjectVisibility(); } object->SaveToDB(); object->Refresh(); handler->PSendSysMessage(LANG_COMMAND_MOVEOBJMESSAGE, object->GetGUIDLow(), object->GetGOInfo()->name.c_str(), object->GetGUIDLow()); return true; }
void BfCapturePoint::SendChangePhase() { GameObject* capturePoint = GetCapturePointGo(); if (!capturePoint) return; for (uint8 team = 0; team < 2; ++team) for (GuidSet::iterator itr = m_activePlayers[team].begin(); itr != m_activePlayers[team].end(); ++itr) // send to all players present in the area if (Player* player = ObjectAccessor::FindPlayer(*itr)) { // send this too, sometimes the slider disappears, dunno why :( player->SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldState1, 1); // send these updates to only the ones in this objective player->SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldstate2, (uint32) ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f)); // send this too, sometimes it resets :S player->SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldstate3, m_neutralValuePct); } }
//turn selected object static bool HandleGameObjectTurnCommand(ChatHandler* handler, char const* args) { // number or [name] Shift-click form |color|Hgameobject:go_id|h[name]|h|r char* id = handler->extractKeyFromLink((char*)args, "Hgameobject"); if (!id) return false; uint32 guidLow = atoi(id); if (!guidLow) return false; GameObject* object = nullptr; // by DB guid if (GameObjectData const* gameObjectData = sObjectMgr->GetGOData(guidLow)) object = handler->GetObjectGlobalyWithGuidOrNearWithDbGuid(guidLow, gameObjectData->id); if (!object) { handler->PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, guidLow); handler->SetSentErrorMessage(true); return false; } char* orientation = strtok(nullptr, " "); float oz = 0.f, oy = 0.f, ox = 0.f; if (orientation) { oz = float(atof(orientation)); orientation = strtok(nullptr, " "); if (orientation) { oy = float(atof(orientation)); orientation = strtok(nullptr, " "); if (orientation) ox = float(atof(orientation)); } } else { Player* player = handler->GetSession()->GetPlayer(); oz = player->GetOrientation(); } object->SetWorldRotationAngles(oz, oy, ox); object->DestroyForNearbyPlayers(); object->UpdateObjectVisibility(); object->SaveToDB(); object->Refresh(); handler->PSendSysMessage(LANG_COMMAND_TURNOBJMESSAGE, object->GetGUIDLow(), object->GetGOInfo()->name.c_str(), object->GetGUIDLow(), oz, oy, ox); return true; }
bool OutdoorPvPObjective::HandleCaptureCreaturePlayerMoveInLos(Player * p, Creature * c) { // check if guid matches if(c->GetGUID() != m_CapturePointCreature) return false; // check if capture point go is spawned Map* map = m_PvP->GetMap(); GameObject * cp = map->GetGameObject(m_CapturePoint); if(!cp) return false; // check range and activity if(cp->IsWithinDistInMap(p,cp->GetGOInfo()->raw.data[0]) && p->IsOutdoorPvPActive()) // data[8] will be used for player enter return HandleCapturePointEvent(p, cp->GetGOInfo()->raw.data[8]); //i_objective->HandlePlayerEnter((Player*)u); else // data[9] will be used for player leave return HandleCapturePointEvent(p, cp->GetGOInfo()->raw.data[9]); //i_objective->HandlePlayerLeave((Player*)u); }
static bool HandleGameObjectSetScaleCommand(ChatHandler* handler, char const* args) { // number or [name] Shift-click form |color|Hgameobject:go_id|h[name]|h|r char* id = handler->extractKeyFromLink((char*)args, "Hgameobject"); if (!id) return false; uint32 guidLow = atoi(id); if (!guidLow) return false; GameObject* object = NULL; if (GameObjectData const* gameObjectData = sObjectMgr->GetGOData(guidLow)) object = handler->GetObjectGlobalyWithGuidOrNearWithDbGuid(guidLow, gameObjectData->id); if (!object) { handler->PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, guidLow); handler->SetSentErrorMessage(true); return false; } char* scale_temp = strtok(NULL, " "); if (!scale_temp) { handler->SendSysMessage(LANG_BAD_VALUE); handler->SetSentErrorMessage(true); return false; } float scale = atof(scale_temp); if (scale <= 0.0f) { scale = object->GetGOInfo()->size; const_cast<GameObjectData*>(object->GetGOData())->size = -1.0f; } else { const_cast<GameObjectData*>(object->GetGOData())->size = scale; } object->SetObjectScale(scale); object->DestroyForNearbyPlayers(); object->UpdateObjectVisibility(); object->SaveToDB(); handler->PSendSysMessage("Set %s scale to %f", object->GetGUID().ToString(), scale); return true; }
//turn selected object static bool HandleGameObjectTurnCommand(ChatHandler* handler, const char* args) { // number or [name] Shift-click form |color|Hgameobject:go_id|h[name]|h|r char* cId = handler->extractKeyFromLink((char*)args,"Hgameobject"); if (!cId) return false; uint32 lowguid = atoi(cId); if (!lowguid) return false; GameObject* obj = NULL; // by DB guid if (GameObjectData const* go_data = sObjectMgr->GetGOData(lowguid)) obj = handler->GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id); if (!obj) { handler->PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid); handler->SetSentErrorMessage(true); return false; } char* po = strtok(NULL, " "); float o; if (po) { o = (float)atof(po); } else { Player *chr = handler->GetSession()->GetPlayer(); o = chr->GetOrientation(); } obj->Relocate(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), o); obj->UpdateRotationFields(); obj->DestroyForNearbyPlayers(); obj->UpdateObjectVisibility(); obj->SaveToDB(); obj->Refresh(); handler->PSendSysMessage(LANG_COMMAND_TURNOBJMESSAGE, obj->GetGUIDLow(), obj->GetGOInfo()->name, obj->GetGUIDLow(), o); return true; }
bool OutdoorPvPObjective::AddCapturePoint(uint32 entry, uint32 map, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3) { Map * pMap = MapManager::Instance().FindMap(map); if(!pMap) return false; GameObject* go = new GameObject; if (!go->Create(sObjectMgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), entry, pMap, PHASEMASK_NORMAL, x, y, z, o, rotation0, rotation1, rotation2, rotation3, 100, GO_STATE_READY)) { sLog.outError("OutdoorPvP: Gameobject template %u not found in database.", entry); delete go; // TODO: Should we return here? //return false; } else go->AddToWorld(); Creature* pCreature = new Creature; if (!pCreature->Create(sObjectMgr.GenerateLowGuid(HIGHGUID_UNIT), pMap,PHASEMASK_NORMAL, OPVP_TRIGGER_CREATURE_ENTRY, 0)) { sLog.outError("OutdoorPvP: Can't create creature entry: %u",entry); delete pCreature; return false; } pCreature->Relocate(x, y, z, o); if (!pCreature->IsPositionValid()) { sLog.outError("OutdoorPvP: Creature (guidlow %d, entry %d) not added to opvp. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY()); delete pCreature; return false; } pCreature->AIM_Initialize(); pMap->Add(pCreature); m_CapturePointCreature = MAKE_NEW_GUID(pCreature->GetGUID(), OPVP_TRIGGER_CREATURE_ENTRY, HIGHGUID_UNIT); m_CapturePoint = MAKE_NEW_GUID(go->GetGUID(), entry, HIGHGUID_GAMEOBJECT); // TODO: Use proper outdoor PvP GO type. GameObjectInfo const* goinfo = go->GetGOInfo(); m_ShiftMaxPhase = goinfo->raw.data[17]; m_ShiftMaxCaptureSpeed = m_ShiftMaxPhase / float(goinfo->raw.data[16]); m_NeutralValue = goinfo->raw.data[12]; return true; }
//turn selected object static bool HandleGameObjectTurnCommand(ChatHandler* handler, char const* args) { // number or [name] Shift-click form |color|Hgameobject:go_id|h[name]|h|r char* id = handler->extractKeyFromLink((char*)args, "Hgameobject"); if (!id) return false; ObjectGuid::LowType guidLow = strtoull(id, nullptr, 10); if (!guidLow) return false; GameObject* object = NULL; // by DB guid if (GameObjectData const* gameObjectData = sObjectMgr->GetGOData(guidLow)) object = handler->GetObjectGlobalyWithGuidOrNearWithDbGuid(guidLow, gameObjectData->id); if (!object) { handler->PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, guidLow); handler->SetSentErrorMessage(true); return false; } char* orientation = strtok(NULL, " "); float o; if (orientation) o = (float)atof(orientation); else { Player* player = handler->GetSession()->GetPlayer(); o = player->GetOrientation(); } object->Relocate(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), o); object->RelocateStationaryPosition(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), o); object->UpdateRotationFields(); object->DestroyForNearbyPlayers(); object->UpdateObjectVisibility(); object->SaveToDB(); handler->PSendSysMessage(LANG_COMMAND_TURNOBJMESSAGE, object->GetSpawnId(), object->GetGOInfo()->name.c_str(), object->GetGUID().ToString().c_str(), o); return true; }
//turn selected object static bool HandleGameObjectTurnCommand(ChatHandler* handler, char const* args) { uint32 guidLow = GetGuidLowFromArgsOrLastTargetedGo(handler, args); if (!guidLow) return false; GameObject* object = NULL; // by DB guid if (GameObjectData const* gameObjectData = sObjectMgr->GetGOData(guidLow)) object = handler->GetObjectGlobalyWithGuidOrNearWithDbGuid(guidLow, gameObjectData->id); if (!object) { handler->PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, guidLow); handler->SetSentErrorMessage(true); return false; } char* orientation = strtok(NULL, " "); float o; if (orientation) o = (float)atof(orientation); else { Player* player = handler->GetSession()->GetPlayer(); o = player->GetOrientation(); } object->Relocate(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), o); object->UpdateRotationFields(); object->DestroyForNearbyPlayers(); object->UpdateObjectVisibility(); object->SaveToDB(); object->Refresh(); handler->PSendSysMessage(LANG_COMMAND_TURNOBJMESSAGE, object->GetGUIDLow(), object->GetGOInfo()->name.c_str(), object->GetGUIDLow(), o); return true; }
void instance_naxxramas::ActivateAreaFissures(ChamberArea AreaNo) { for (std::list<uint64>::iterator itr = lFissuresGUIDs[AreaNo].begin(); itr != lFissuresGUIDs[AreaNo].end(); ++itr) { GameObject* pFissure = instance->GetGameObject(*itr); if (!pFissure) continue; float radius = 4.0f; Player* pPlayer = NULL; MaNGOS::AnyPlayerInObjectRangeCheck p_check(pFissure, radius); MaNGOS::PlayerSearcher<MaNGOS::AnyPlayerInObjectRangeCheck> checker(pFissure, pPlayer , p_check); Cell::VisitAllObjects(pFissure, checker, radius); if (pPlayer) pPlayer->CastSpell(pPlayer, pFissure->GetGOInfo()->trap.spellId, true, NULL, NULL, pFissure->GetGUID()); pFissure->SendGameObjectCustomAnim(pFissure->GetGUID()); } }
bool UseMeetingStoneAction::Execute(Event event) { Player* master = GetMaster(); if (!master) return false; WorldPacket p(event.getPacket()); p.rpos(0); ObjectGuid guid; p >> guid; if (master->GetSelectedPlayer() && master->GetSelectedPlayer() != bot) return false; if (!master->GetSelectedPlayer() && master->GetGroup() != bot->GetGroup()) return false; if (master->IsBeingTeleported()) return false; if (bot->IsInCombat()) { ai->TellMasterNoFacing("I am in combat"); return false; } Map* map = master->GetMap(); if (!map) return NULL; GameObject *gameObject = map->GetGameObject(guid); if (!gameObject) return false; const GameObjectTemplate* goInfo = gameObject->GetGOInfo(); if (!goInfo || goInfo->type != GAMEOBJECT_TYPE_SUMMONING_RITUAL) return false; return Teleport(); }
void WorldSession::HandleGameObjectUseOpcode(WorldPacket& recv_data) { uint64 guid; recv_data >> guid; DEBUG_LOG("WORLD: Recvd CMSG_GAMEOBJ_USE Message [guid=%u]", GUID_LOPART(guid)); GameObject* obj = GetPlayer()->GetMap()->GetGameObject(guid); if (!obj) return; FactionTemplateEntry const* faction = sFactionTemplateStore.LookupEntry(obj->GetGOInfo()->faction); if (faction && !_player->isGameMaster() && faction->IsHostileTo(*sFactionTemplateStore.LookupEntry(_player->getFaction())) && !faction->IsNeutralToAll() && !obj->GetOwner()) return; obj->Use(_player); }
void WorldSession::DoLootRelease(uint64 lguid) { Player *player = GetPlayer(); Loot *loot; player->SetLootGUID(0); player->SendLootRelease(lguid); player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING); if (!player->IsInWorld()) return; if (IS_GAMEOBJECT_GUID(lguid)) { GameObject* go = GetPlayer()->GetMap()->GetGameObject(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))) return; loot = &go->loot; if (go->GetGoType() == GAMEOBJECT_TYPE_DOOR) { // locked doors are opened with spelleffect openlock, prevent remove its as looted go->UseDoorOrButton(); } else if (loot->isLooted() || go->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE) { if (go->GetGoType() == GAMEOBJECT_TYPE_FISHINGHOLE) { // The fishing hole used once more go->AddUse(); // if the max usage is reached, will be despawned in next tick if (go->GetUseCount() >= urand(go->GetGOInfo()->fishinghole.minSuccessOpens, go->GetGOInfo()->fishinghole.maxSuccessOpens)) go->SetLootState(GO_JUST_DEACTIVATED); else go->SetLootState(GO_READY); } else go->SetLootState(GO_JUST_DEACTIVATED); loot->clear(); } else { // not fully looted object go->SetLootState(GO_ACTIVATED, player); // if the round robin player release, reset it. if (player->GetGUID() == loot->roundRobinPlayer) { if (Group* group = player->GetGroup()) { if (group->GetLootMethod() != MASTER_LOOT) loot->roundRobinPlayer = 0; } else loot->roundRobinPlayer = 0; } } } else if (IS_CORPSE_GUID(lguid)) // ONLY remove insignia at BG { Corpse* corpse = ObjectAccessor::GetCorpse(*player, lguid); if (!corpse || !corpse->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) return; loot = &corpse->loot; if (loot->isLooted()) { loot->clear(); corpse->RemoveFlag(CORPSE_FIELD_DYNAMIC_FLAGS, CORPSE_DYNFLAG_LOOTABLE); } } else if (IS_ITEM_GUID(lguid)) { Item* pItem = player->GetItemByGuid(lguid); if (!pItem) return; ItemTemplate const* proto = pItem->GetTemplate(); // destroy only 5 items from stack in case prospecting and milling if (proto->Flags & (ITEM_PROTO_FLAG_PROSPECTABLE | ITEM_PROTO_FLAG_MILLABLE)) { pItem->m_lootGenerated = false; pItem->loot.clear(); uint32 count = pItem->GetCount(); // >=5 checked in spell code, but will work for cheating cases also with removing from another stacks. if (count > 5) count = 5; player->DestroyItemCount(pItem, count, true); } else // FIXME: item must not be deleted in case not fully looted state. But this pre-request implement loot saving in DB at item save. Or cheating possible. player->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true); return; // item can be looted only single player } else { Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid); bool lootAllowed = creature && creature->isAlive() == (player->getClass() == CLASS_ROGUE && creature->lootForPickPocketed); if (!lootAllowed || !creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) return; loot = &creature->loot; if (loot->isLooted()) { // skip pickpocketing loot for speed, skinning timer reduction is no-op in fact if (!creature->isAlive()) creature->AllLootRemovedFromCorpse(); creature->RemoveFlag(OBJECT_FIELD_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); loot->clear(); // Clear all linkedLoot looted std::set<uint64> alreadyClear; for (auto itr : loot->linkedLoot) { if (alreadyClear.find(itr.second.creatureGUID) == alreadyClear.end()) { alreadyClear.insert(itr.second.creatureGUID); if (Creature* c = creature->GetCreature(*creature, itr.second.creatureGUID)) { if (!c->loot.isLooted()) continue; // skip pickpocketing loot for speed, skinning timer reduction is no-op in fact if (!c->isAlive()) c->AllLootRemovedFromCorpse(); c->RemoveFlag(OBJECT_FIELD_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); c->loot.clear(); c->loot.RemoveLooter(player->GetGUID()); } } } loot->linkedLoot.clear(); } else { // if the round robin player release, reset it. if (player->GetGUID() == loot->roundRobinPlayer) { if (Group* group = player->GetGroup()) { if (group->GetLootMethod() != MASTER_LOOT) { loot->roundRobinPlayer = 0; group->SendLooter(creature, NULL); // force update of dynamic flags, otherwise other group's players still not able to loot. creature->ForceValuesUpdateAtIndex(OBJECT_FIELD_DYNAMIC_FLAGS); } } else loot->roundRobinPlayer = 0; } } } //Player is not looking at loot list, he doesn't need to see updates on the loot list loot->RemoveLooter(player->GetGUID()); }
void WorldSession::DoLootRelease(ObjectGuid lguid) { Player* player = GetPlayer(); Loot* loot; player->SetLootGuid(ObjectGuid()); player->SendLootRelease(lguid); player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING); if (!player->IsInWorld()) { return; } switch (lguid.GetHigh()) { case HIGHGUID_GAMEOBJECT: { GameObject* go = GetPlayer()->GetMap()->GetGameObject(lguid); // not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO if (!go || ((go->GetOwnerGuid() != _player->GetObjectGuid() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player, INTERACTION_DISTANCE))) { return; } loot = &go->loot; if (go->GetGoType() == GAMEOBJECT_TYPE_DOOR) { // locked doors are opened with spelleffect openlock, prevent remove its as looted go->UseDoorOrButton(); } else if (loot->isLooted() || go->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE) { // GO is mineral vein? so it is not removed after its looted if (go->GetGoType() == GAMEOBJECT_TYPE_CHEST) { uint32 go_min = go->GetGOInfo()->chest.minSuccessOpens; uint32 go_max = go->GetGOInfo()->chest.maxSuccessOpens; // only vein pass this check if (go_min != 0 && go_max > go_min) { float amount_rate = sWorld.getConfig(CONFIG_FLOAT_RATE_MINING_AMOUNT); float min_amount = go_min * amount_rate; float max_amount = go_max * amount_rate; go->AddUse(); float uses = float(go->GetUseCount()); if (uses < max_amount) { if (uses >= min_amount) { float chance_rate = sWorld.getConfig(CONFIG_FLOAT_RATE_MINING_NEXT); int32 ReqValue = 175; LockEntry const* lockInfo = sLockStore.LookupEntry(go->GetGOInfo()->chest.lockId); if (lockInfo) { ReqValue = lockInfo->Skill[0]; } float skill = float(player->GetSkillValue(SKILL_MINING)) / (ReqValue + 25); double chance = pow(0.8 * chance_rate, 4 * (1 / double(max_amount)) * double(uses)); if (roll_chance_f(float(100.0f * chance + skill))) { go->SetLootState(GO_READY); } else // not have more uses { go->SetLootState(GO_JUST_DEACTIVATED); } } else // 100% chance until min uses { go->SetLootState(GO_READY); } } else // max uses already { go->SetLootState(GO_JUST_DEACTIVATED); } } else // not vein { go->SetLootState(GO_JUST_DEACTIVATED); } } else if (go->GetGoType() == GAMEOBJECT_TYPE_FISHINGHOLE) { // The fishing hole used once more go->AddUse(); // if the max usage is reached, will be despawned at next tick if (go->GetUseCount() >= urand(go->GetGOInfo()->fishinghole.minSuccessOpens, go->GetGOInfo()->fishinghole.maxSuccessOpens)) { go->SetLootState(GO_JUST_DEACTIVATED); } else { go->SetLootState(GO_READY); } } else // not chest (or vein/herb/etc) { go->SetLootState(GO_JUST_DEACTIVATED); } loot->clear(); } else // not fully looted object { go->SetLootState(GO_ACTIVATED); } go->SetGoState(GO_STATE_READY); break; } /* Only used for removing insignia in battlegrounds */ case HIGHGUID_CORPSE: { /* Get pointer to corpse */ Corpse* corpse = _player->GetMap()->GetCorpse(lguid); /* If corpse is invalid or not in a valid position, dont allow looting */ if (!corpse || !corpse->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) { return; } loot = &corpse->loot; if (loot->isLooted()) { loot->clear(); corpse->RemoveFlag(CORPSE_FIELD_DYNAMIC_FLAGS, CORPSE_DYNFLAG_LOOTABLE); } break; } case HIGHGUID_ITEM: { Item* pItem = player->GetItemByGuid(lguid); if (!pItem) { return; } switch (pItem->loot.loot_type) { // temporary loot in stacking items, clear loot state, no auto loot move case LOOT_PROSPECTING: { uint32 count = pItem->GetCount(); // >=5 checked in spell code, but will work for cheating cases also with removing from another stacks. if (count > 5) count = 5; // reset loot for allow repeat looting if stack > 5 pItem->loot.clear(); pItem->SetLootState(ITEM_LOOT_REMOVED); player->DestroyItemCount(pItem, count, true); break; } // temporary loot, auto loot move case LOOT_DISENCHANTING: { if (!pItem->loot.isLooted()) { player->AutoStoreLoot(pItem->loot); } // can be lost if no space pItem->loot.clear(); pItem->SetLootState(ITEM_LOOT_REMOVED); player->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true); break; } // normal persistence loot default: { // must be destroyed only if no loot if (pItem->loot.isLooted()) { pItem->SetLootState(ITEM_LOOT_REMOVED); player->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true); } break; } } return; // item can be looted only single player } case HIGHGUID_UNIT: { /* Get creature pointer */ Creature* pCreature = GetPlayer()->GetMap()->GetCreature(lguid); bool ok_loot = (pCreature && // The creature exists (we dont have a null pointer) pCreature->IsAlive() == // Creature is alive and we're a rogue and creature can be pickpocketed (player->getClass() == CLASS_ROGUE && pCreature->lootForPickPocketed)); if (!ok_loot || !pCreature->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) { return; } /* Copy creature loot to loot variable */ loot = &pCreature->loot; /* Update for other players. */ if(!loot->isLooted()) { Group const* group = pCreature->GetGroupLootRecipient(); if (group && !pCreature->hasBeenLootedOnce) { // Checking whether it has been looted once by the designed looter (master loot case). switch (group->GetLootMethod()) { case FREE_FOR_ALL: case NEED_BEFORE_GREED: case ROUND_ROBIN: case GROUP_LOOT: { pCreature->hasBeenLootedOnce = true; break; } case MASTER_LOOT: { pCreature->hasBeenLootedOnce = (group->GetLooterGuid() == player->GetObjectGuid()); break; } } pCreature->MarkFlagUpdateForClient(UNIT_DYNAMIC_FLAGS); } } /* We've completely looted the creature, mark it as available for skinning */ if (loot->isLooted() && !pCreature->IsAlive()) { /* Update Creature: for example skinning after normal loot */ pCreature->PrepareBodyLootState(); pCreature->AllLootRemovedFromCorpse(); } break; } default: { sLog.outError("%s is unsupported for looting.", lguid.GetString().c_str()); return; } } // Player is not looking at loot list, he doesn't need to see updates on the loot list loot->RemoveLooter(player->GetObjectGuid()); }
void WorldSession::DoLootRelease(uint64 lguid) { Player *player = GetPlayer(); Loot *loot; player->SetLootGUID(0); player->SendLootRelease(lguid); player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING); if (!player->IsInWorld()) return; if (IS_GAMEOBJECT_GUID(lguid)) { GameObject *go = GetPlayer()->GetMap()->GetGameObject(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))) return; loot = &go->loot; if (go->GetGoType() == GAMEOBJECT_TYPE_DOOR) { // locked doors are opened with spelleffect openlock, prevent remove its as looted go->UseDoorOrButton(); } else if (loot->isLooted() || go->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE) { // GO is mineral vein? so it is not removed after its looted if (go->GetGoType() == GAMEOBJECT_TYPE_CHEST) { uint32 go_min = go->GetGOInfo()->chest.minSuccessOpens; uint32 go_max = go->GetGOInfo()->chest.maxSuccessOpens; // only vein pass this check if (go_min != 0 && go_max > go_min) { float amount_rate = sWorld.getRate(RATE_MINING_AMOUNT); float min_amount = go_min*amount_rate; float max_amount = go_max*amount_rate; go->AddUse(); float uses = float(go->GetUseCount()); if (uses < max_amount) { if (uses >= min_amount) { float chance_rate = sWorld.getRate(RATE_MINING_NEXT); int32 ReqValue = 175; LockEntry const *lockInfo = sLockStore.LookupEntry(go->GetGOInfo()->chest.lockId); if (lockInfo) ReqValue = lockInfo->requiredminingskill; float skill = float(player->GetSkillValue(SKILL_MINING))/(ReqValue+25); double chance = pow(0.8*chance_rate,4*(1/double(max_amount))*double(uses)); if (roll_chance_f(100*chance+skill)) { go->SetLootState(GO_READY); } else // not have more uses go->SetLootState(GO_JUST_DEACTIVATED); } else // 100% chance until min uses go->SetLootState(GO_READY); } else // max uses already go->SetLootState(GO_JUST_DEACTIVATED); } else // not vein go->SetLootState(GO_JUST_DEACTIVATED); } else if (go->GetGoType() == GAMEOBJECT_TYPE_FISHINGHOLE) { // The fishing hole used once more go->AddUse(); // if the max usage is reached, will be despawned in next tick if (go->GetUseCount() >= irand(go->GetGOInfo()->fishinghole.minSuccessOpens,go->GetGOInfo()->fishinghole.maxSuccessOpens)) { go->SetLootState(GO_JUST_DEACTIVATED); } else go->SetLootState(GO_READY); } else // not chest (or vein/herb/etc) go->SetLootState(GO_JUST_DEACTIVATED); loot->clear(); } else // not fully looted object go->SetLootState(GO_ACTIVATED); } else if (IS_CORPSE_GUID(lguid)) // ONLY remove insignia at BG { Corpse *corpse = ObjectAccessor::GetCorpse(*player, lguid); if (!corpse || !corpse->IsWithinDistInMap(_player,INTERACTION_DISTANCE)) return; loot = &corpse->loot; if (loot->isLooted()) { loot->clear(); corpse->RemoveFlag(CORPSE_FIELD_DYNAMIC_FLAGS, CORPSE_DYNFLAG_LOOTABLE); } } else if (IS_ITEM_GUID(lguid)) { Item *pItem = player->GetItemByGuid(lguid); if (!pItem) return; if ((pItem->GetProto()->BagFamily & BAG_FAMILY_MASK_MINING_SUPP) && pItem->GetProto()->Class == ITEM_CLASS_TRADE_GOODS && pItem->GetCount() >= 5) { pItem->m_lootGenerated = false; pItem->loot.clear(); uint32 count = 5; player->DestroyItemCount(pItem, count, true); } else // FIXME: item must not be deleted in case not fully looted state. But this pre-request implement loot saving in DB at item save. Or cheating possible. player->DestroyItem(pItem->GetBagSlot(),pItem->GetSlot(), true); return; // item can be looted only single player } else { Creature* pCreature = GetPlayer()->GetMap()->GetCreature(lguid); bool ok_loot = pCreature && pCreature->isAlive() == (player->getClass() == CLASS_ROGUE && pCreature->lootForPickPocketed); if (!ok_loot || !pCreature->IsWithinDistInMap(_player,INTERACTION_DISTANCE)) return; loot = &pCreature->loot; // update next looter if (Player *recipient = pCreature->GetLootRecipient()) if (Group* group = recipient->GetGroup()) if (group->GetLooterGuid() == player->GetGUID()) group->UpdateLooterGuid(pCreature); if (loot->isLooted()) { // skip pickpocketing loot for speed, skinning timer redunction is no-op in fact if (!pCreature->isAlive()) pCreature->AllLootRemovedFromCorpse(); pCreature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); loot->clear(); } } //Player is not looking at loot list, he doesn't need to see updates on the loot list loot->RemoveLooter(player->GetGUID()); }
//move selected object static bool HandleGameObjectMoveCommand(ChatHandler* handler, char const* args) { // number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r char* id = handler->extractKeyFromLink((char*)args, "Hgameobject"); if (!id) return false; ObjectGuid::LowType guidLow = atoul(id); if (!guidLow) return false; GameObject* object = handler->GetObjectFromPlayerMapByDbGuid(guidLow); if (!object) { handler->PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, guidLow); handler->SetSentErrorMessage(true); return false; } char* toX = strtok(nullptr, " "); char* toY = strtok(nullptr, " "); char* toZ = strtok(nullptr, " "); float x, y, z; if (!toX) { Player* player = handler->GetSession()->GetPlayer(); player->GetPosition(x, y, z); } else { if (!toY || !toZ) return false; x = (float)atof(toX); y = (float)atof(toY); z = (float)atof(toZ); if (!MapManager::IsValidMapCoord(object->GetMapId(), x, y, z)) { handler->PSendSysMessage(LANG_INVALID_TARGET_COORD, x, y, object->GetMapId()); handler->SetSentErrorMessage(true); return false; } } Map* map = object->GetMap(); object->Relocate(x, y, z, object->GetOrientation()); object->SaveToDB(); // Generate a completely new spawn with new guid // 3.3.5a client caches recently deleted objects and brings them back to life // when CreateObject block for this guid is received again // however it entirely skips parsing that block and only uses already known location object->Delete(); object = new GameObject(); if (!object->LoadFromDB(guidLow, map, true)) { delete object; return false; } handler->PSendSysMessage(LANG_COMMAND_MOVEOBJMESSAGE, object->GetSpawnId(), object->GetGOInfo()->name.c_str(), object->GetSpawnId()); return true; }
//turn selected object static bool HandleGameObjectTurnCommand(ChatHandler* handler, char const* args) { // number or [name] Shift-click form |color|Hgameobject:go_id|h[name]|h|r char* id = handler->extractKeyFromLink((char*)args, "Hgameobject"); if (!id) return false; ObjectGuid::LowType guidLow = atoul(id); if (!guidLow) return false; GameObject* object = handler->GetObjectFromPlayerMapByDbGuid(guidLow); if (!object) { handler->PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, guidLow); handler->SetSentErrorMessage(true); return false; } char* orientation = strtok(nullptr, " "); float oz = 0.f, oy = 0.f, ox = 0.f; if (orientation) { oz = float(atof(orientation)); orientation = strtok(nullptr, " "); if (orientation) { oy = float(atof(orientation)); orientation = strtok(nullptr, " "); if (orientation) ox = float(atof(orientation)); } } else { Player* player = handler->GetSession()->GetPlayer(); oz = player->GetOrientation(); } Map* map = object->GetMap(); object->Relocate(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ()); object->SetWorldRotationAngles(oz, oy, ox); object->SaveToDB(); // Generate a completely new spawn with new guid // 3.3.5a client caches recently deleted objects and brings them back to life // when CreateObject block for this guid is received again // however it entirely skips parsing that block and only uses already known location object->Delete(); object = new GameObject(); if (!object->LoadFromDB(guidLow, map, true)) { delete object; return false; } handler->PSendSysMessage(LANG_COMMAND_TURNOBJMESSAGE, object->GetSpawnId(), object->GetGOInfo()->name.c_str(), object->GetSpawnId()); return true; }
bool BattlefieldWG::SetupBattlefield() { InitStalker(BATTLEFIELD_WG_NPC_STALKER, WintergraspStalkerPos[0], WintergraspStalkerPos[1], WintergraspStalkerPos[2], WintergraspStalkerPos[3]); m_TypeId = BATTLEFIELD_WG; // See enum BattlefieldTypes m_BattleId = BATTLEFIELD_BATTLEID_WG; m_ZoneId = BATTLEFIELD_WG_ZONEID; m_MapId = BATTLEFIELD_WG_MAPID; m_Guid = MAKE_NEW_GUID(m_TypeId, 0, HIGHGUID_TYPE_BATTLEGROUND); m_Guid |= 0x20000; // BATTLEFIELD_TYPE_WORLD_PVP 5.0.5 m_MaxPlayer = sWorld->getIntConfig(CONFIG_WINTERGRASP_PLR_MAX); m_IsEnabled = sWorld->getBoolConfig(CONFIG_WINTERGRASP_ENABLE); m_MinPlayer = sWorld->getIntConfig(CONFIG_WINTERGRASP_PLR_MIN); m_MinLevel = sWorld->getIntConfig(CONFIG_WINTERGRASP_PLR_MIN_LVL); m_BattleTime = sWorld->getIntConfig(CONFIG_WINTERGRASP_BATTLETIME) * MINUTE * IN_MILLISECONDS; m_NoWarBattleTime = sWorld->getIntConfig(CONFIG_WINTERGRASP_NOBATTLETIME) * MINUTE * IN_MILLISECONDS; m_RestartAfterCrash = sWorld->getIntConfig(CONFIG_WINTERGRASP_RESTART_AFTER_CRASH) * MINUTE * IN_MILLISECONDS; m_TimeForAcceptInvite = 20; m_StartGroupingTimer = 15 * MINUTE * IN_MILLISECONDS; m_StartGrouping = false; m_tenacityStack = 0; KickPosition.Relocate(5728.117f, 2714.346f, 697.733f, 0); KickPosition.m_mapId = m_MapId; RegisterZone(m_ZoneId); m_Data32.resize(BATTLEFIELD_WG_DATA_MAX); m_saveTimer = 60000; // Init GraveYards SetGraveyardNumber(BATTLEFIELD_WG_GRAVEYARD_MAX); // Load from db if ((sWorld->getWorldState(BATTLEFIELD_WG_WORLD_STATE_ACTIVE) == 0) && (sWorld->getWorldState(BATTLEFIELD_WG_WORLD_STATE_DEFENDER) == 0) && (sWorld->getWorldState(ClockWorldState[0]) == 0)) { sWorld->setWorldState(BATTLEFIELD_WG_WORLD_STATE_ACTIVE, uint64(false)); sWorld->setWorldState(BATTLEFIELD_WG_WORLD_STATE_DEFENDER, uint64(urand(0, 1))); sWorld->setWorldState(ClockWorldState[0], uint64(m_NoWarBattleTime)); } m_isActive = bool(sWorld->getWorldState(BATTLEFIELD_WG_WORLD_STATE_ACTIVE)); m_DefenderTeam = TeamId(sWorld->getWorldState(BATTLEFIELD_WG_WORLD_STATE_DEFENDER)); m_Timer = sWorld->getWorldState(ClockWorldState[0]); if (m_isActive) { m_isActive = false; m_Timer = m_RestartAfterCrash; } for (uint8 i = 0; i < BATTLEFIELD_WG_GRAVEYARD_MAX; i++) { BfGraveyardWG* graveyard = new BfGraveyardWG(this); // When between games, the graveyard is controlled by the defending team if (WGGraveYard[i].startcontrol == TEAM_NEUTRAL) graveyard->Initialize(m_DefenderTeam, WGGraveYard[i].gyid); else graveyard->Initialize(WGGraveYard[i].startcontrol, WGGraveYard[i].gyid); graveyard->SetTextId(WGGraveYard[i].textid); m_GraveyardList[i] = graveyard; } // Spawn workshop creatures and gameobjects for (uint8 i = 0; i < WG_MAX_WORKSHOP; i++) { WGWorkshop* workshop = new WGWorkshop(this, i); if (i < BATTLEFIELD_WG_WORKSHOP_KEEP_WEST) workshop->GiveControlTo(GetAttackerTeam(), true); else workshop->GiveControlTo(GetDefenderTeam(), true); // Note: Capture point is added once the gameobject is created. WorkshopsList.insert(workshop); } // Spawn NPCs in the defender's keep, both Horde and Alliance for (uint8 i = 0; i < WG_MAX_KEEP_NPC; i++) { // Horde npc if (Creature* creature = SpawnCreature(WGKeepNPC[i].entryHorde, WGKeepNPC[i].x, WGKeepNPC[i].y, WGKeepNPC[i].z, WGKeepNPC[i].o, TEAM_HORDE)) KeepCreature[TEAM_HORDE].insert(creature->GetGUID()); // Alliance npc if (Creature* creature = SpawnCreature(WGKeepNPC[i].entryAlliance, WGKeepNPC[i].x, WGKeepNPC[i].y, WGKeepNPC[i].z, WGKeepNPC[i].o, TEAM_ALLIANCE)) KeepCreature[TEAM_ALLIANCE].insert(creature->GetGUID()); } // Hide NPCs from the Attacker's team in the keep for (GuidSet::const_iterator itr = KeepCreature[GetAttackerTeam()].begin(); itr != KeepCreature[GetAttackerTeam()].end(); ++itr) if (Unit* unit = sObjectAccessor->FindUnit(*itr)) if (Creature* creature = unit->ToCreature()) HideNpc(creature); // Spawn Horde NPCs outside the keep for (uint8 i = 0; i < WG_OUTSIDE_ALLIANCE_NPC; i++) if (Creature* creature = SpawnCreature(WGOutsideNPC[i].entryHorde, WGOutsideNPC[i].x, WGOutsideNPC[i].y, WGOutsideNPC[i].z, WGOutsideNPC[i].o, TEAM_HORDE)) OutsideCreature[TEAM_HORDE].insert(creature->GetGUID()); // Spawn Alliance NPCs outside the keep for (uint8 i = WG_OUTSIDE_ALLIANCE_NPC; i < WG_MAX_OUTSIDE_NPC; i++) if (Creature* creature = SpawnCreature(WGOutsideNPC[i].entryAlliance, WGOutsideNPC[i].x, WGOutsideNPC[i].y, WGOutsideNPC[i].z, WGOutsideNPC[i].o, TEAM_ALLIANCE)) OutsideCreature[TEAM_ALLIANCE].insert(creature->GetGUID()); // Hide units outside the keep that are defenders for (GuidSet::const_iterator itr = OutsideCreature[GetDefenderTeam()].begin(); itr != OutsideCreature[GetDefenderTeam()].end(); ++itr) if (Unit* unit = sObjectAccessor->FindUnit(*itr)) if (Creature* creature = unit->ToCreature()) HideNpc(creature); // Spawn turrets and hide them per default for (uint8 i = 0; i < WG_MAX_TURRET; i++) { Position towerCannonPos; WGTurret[i].GetPosition(&towerCannonPos); if (Creature* creature = SpawnCreature(NPC_TOWER_CANNON, towerCannonPos, TEAM_ALLIANCE)) { CanonList.insert(creature->GetGUID()); HideNpc(creature); } } // Spawn all gameobjects for (uint8 i = 0; i < WG_MAX_OBJ; i++) { GameObject* go = SpawnGameObject(WGGameObjectBuilding[i].entry, WGGameObjectBuilding[i].x, WGGameObjectBuilding[i].y, WGGameObjectBuilding[i].z, WGGameObjectBuilding[i].o); BfWGGameObjectBuilding* b = new BfWGGameObjectBuilding(this); b->Init(go, WGGameObjectBuilding[i].type, WGGameObjectBuilding[i].WorldState, WGGameObjectBuilding[i].nameId); if (!IsEnabled() && go->GetGOInfo()->entry == GO_WINTERGRASP_VAULT_GATE) go->SetDestructibleState(GO_DESTRUCTIBLE_DESTROYED); BuildingsInZone.insert(b); } // Spawning portal defender for (uint8 i = 0; i < WG_MAX_TELEPORTER; i++) { GameObject* go = SpawnGameObject(WGPortalDefenderData[i].entry, WGPortalDefenderData[i].x, WGPortalDefenderData[i].y, WGPortalDefenderData[i].z, WGPortalDefenderData[i].o); DefenderPortalList.insert(go); go->SetUInt32Value(GAMEOBJECT_FACTION, WintergraspFaction[GetDefenderTeam()]); } // Spawn banners in the keep for (uint8 i = 0; i < WG_KEEPGAMEOBJECT_MAX; i++) { if (GameObject* go = SpawnGameObject(WGKeepGameObject[i].entryHorde, WGKeepGameObject[i].x, WGKeepGameObject[i].y, WGKeepGameObject[i].z, WGKeepGameObject[i].o)) { go->SetRespawnTime(GetDefenderTeam()? RESPAWN_ONE_DAY : RESPAWN_IMMEDIATELY); m_KeepGameObject[1].insert(go); } if (GameObject* go = SpawnGameObject(WGKeepGameObject[i].entryAlliance, WGKeepGameObject[i].x, WGKeepGameObject[i].y, WGKeepGameObject[i].z, WGKeepGameObject[i].o)) { go->SetRespawnTime(GetDefenderTeam()? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY); m_KeepGameObject[0].insert(go); } } // Show defender banner in keep for (GameObjectSet::const_iterator itr = m_KeepGameObject[GetDefenderTeam()].begin(); itr != m_KeepGameObject[GetDefenderTeam()].end(); ++itr) (*itr)->SetRespawnTime(RESPAWN_IMMEDIATELY); // Hide attackant banner in keep for (GameObjectSet::const_iterator itr = m_KeepGameObject[GetAttackerTeam()].begin(); itr != m_KeepGameObject[GetAttackerTeam()].end(); ++itr) (*itr)->SetRespawnTime(RESPAWN_ONE_DAY); UpdateCounterVehicle(true); return true; }
void WorldSession::DoLootRelease(uint64 lguid) { Player *player = GetPlayer(); Loot *loot; player->SetLootGUID(0); player->SendLootRelease(lguid); player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING); if (!player->IsInWorld()) return; if (IS_GAMEOBJECT_GUID(lguid)) { GameObject *go = GetPlayer()->GetMap()->GetGameObject(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)) return; loot = &go->loot; if (go->GetGoType() == GAMEOBJECT_TYPE_DOOR) { // locked doors are opened with spelleffect openlock, prevent remove its as looted go->UseDoorOrButton(); } else if ((go->GetGoType() == GAMEOBJECT_TYPE_CHEST && go->GetGOInfo()->chest.consumable) || loot->isLooted()) { if (go->GetGoType() == GAMEOBJECT_TYPE_FISHINGHOLE) { // The fishing hole used once more go->AddUse(); // if the max usage is reached, will be despawned in next tick if (go->GetUseCount()>=irand(go->GetGOInfo()->fishinghole.minSuccessOpens,go->GetGOInfo()->fishinghole.maxSuccessOpens)) { go->SetLootState(GO_JUST_DEACTIVATED); } else go->SetLootState(GO_READY); } else if (go->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE) go->SetLootState(GO_JUST_DEACTIVATED); loot->clear(); } } else if (IS_CORPSE_GUID(lguid)) // ONLY remove insignia at BG { Corpse *corpse = ObjectAccessor::GetCorpse(*player, lguid); if (!corpse || !corpse->IsWithinDistInMap(_player,INTERACTION_DISTANCE)) return; loot = &corpse->loot; if (loot->isLooted()) { loot->clear(); corpse->RemoveFlag(CORPSE_FIELD_DYNAMIC_FLAGS, CORPSE_DYNFLAG_LOOTABLE); } } else if (IS_ITEM_GUID(lguid)) { Item *pItem = player->GetItemByGuid(lguid); if (!pItem) return; ItemPrototype const* proto = pItem->GetProto(); // destroy only 5 items from stack in case prospecting and milling if ((proto->BagFamily & BAG_FAMILY_MASK_MINING_SUPP) && proto->Class == ITEM_CLASS_TRADE_GOODS) { pItem->m_lootGenerated = false; pItem->loot.clear(); uint32 count = 5; player->DestroyItemCount(pItem, count, true); } else // FIXME: item don't must be deleted in case not fully looted state. But this pre-request implement loot saving in DB at item save. Or checting possible. player->DestroyItem(pItem->GetBagSlot(),pItem->GetSlot(), true); return; // item can be looted only single player } else { Creature* pCreature = GetPlayer()->GetMap()->GetCreature(lguid); bool ok_loot = pCreature && pCreature->isAlive() == (player->getClass()==CLASS_ROGUE && pCreature->lootForPickPocketed); if (!ok_loot || !pCreature->IsWithinDistInMap(_player,INTERACTION_DISTANCE)) return; loot = &pCreature->loot; if (player->GetGUID() == loot->looterGUID) { loot->looterGUID = 0; if (Group *group = player->GetGroup()) group->SendRoundRobin(loot, pCreature); } if (loot->isLooted()) { // skip pickpocketing loot for speed, skinning timer redunction is no-op in fact if (!pCreature->isAlive()) pCreature->AllLootRemovedFromCorpse(); pCreature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); loot->clear(); } } //Player is not looking at loot list, he doesn't need to see updates on the loot list loot->RemoveLooter(player->GetGUID()); // should be fixed after some research in loot implementation etc // loot->RemoveQuestLoot(player); }
//move selected object static bool HandleGameObjectMoveCommand(ChatHandler* handler, const char* args) { // number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r char* cId = handler->extractKeyFromLink((char*)args,"Hgameobject"); if (!cId) return false; uint32 lowguid = atoi(cId); if (!lowguid) return false; GameObject* obj = NULL; // by DB guid if (GameObjectData const* go_data = sObjectMgr->GetGOData(lowguid)) obj = handler->GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id); if (!obj) { handler->PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid); handler->SetSentErrorMessage(true); return false; } char* px = strtok(NULL, " "); char* py = strtok(NULL, " "); char* pz = strtok(NULL, " "); if (!px) { Player *chr = handler->GetSession()->GetPlayer(); obj->Relocate(chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), obj->GetOrientation()); obj->DestroyForNearbyPlayers(); obj->UpdateObjectVisibility(); } else { if (!py || !pz) return false; float x = (float)atof(px); float y = (float)atof(py); float z = (float)atof(pz); if (!MapManager::IsValidMapCoord(obj->GetMapId(),x,y,z)) { handler->PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,obj->GetMapId()); handler->SetSentErrorMessage(true); return false; } obj->Relocate(x, y, z, obj->GetOrientation()); obj->DestroyForNearbyPlayers(); obj->UpdateObjectVisibility(); } obj->SaveToDB(); obj->Refresh(); handler->PSendSysMessage(LANG_COMMAND_MOVEOBJMESSAGE, obj->GetGUIDLow(), obj->GetGOInfo()->name, obj->GetGUIDLow()); return true; }
void WorldSession::DoLootRelease(uint64 lguid) { Player *player = GetPlayer(); Loot *loot; player->SetLootGUID(0); player->SendLootRelease(lguid); player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING); if (!player->IsInWorld()) return; if (IS_GAMEOBJECT_GUID(lguid)) { GameObject* go = GetPlayer()->GetMap()->GetGameObject(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))) return; loot = &go->loot; if (go->GetGoType() == GAMEOBJECT_TYPE_DOOR) { // locked doors are opened with spelleffect openlock, prevent remove its as looted go->UseDoorOrButton(); } else if (loot->isLooted() || go->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE) { // GO is mineral vein? so it is not removed after its looted if (go->GetGoType() == GAMEOBJECT_TYPE_CHEST) { uint32 go_min = go->GetGOInfo()->chest.minSuccessOpens; uint32 go_max = go->GetGOInfo()->chest.maxSuccessOpens; // only vein pass this check if (go_min != 0 && go_max > go_min) { float amount_rate = sWorld->getRate(RATE_MINING_AMOUNT); float min_amount = go_min*amount_rate; float max_amount = go_max*amount_rate; go->AddUse(); float uses = float(go->GetUseCount()); if (uses < max_amount) { if (uses >= min_amount) { float chance_rate = sWorld->getRate(RATE_MINING_NEXT); int32 ReqValue = 175; LockEntry const* lockInfo = sLockStore.LookupEntry(go->GetGOInfo()->chest.lockId); if (lockInfo) ReqValue = lockInfo->Skill[0]; float skill = float(player->GetSkillValue(SKILL_MINING))/(ReqValue+25); double chance = pow(0.8*chance_rate, 4*(1/double(max_amount))*double(uses)); if (roll_chance_f((float)(100*chance+skill))) { go->SetLootState(GO_READY); } else // not have more uses go->SetLootState(GO_JUST_DEACTIVATED); } else // 100% chance until min uses go->SetLootState(GO_READY); } else // max uses already go->SetLootState(GO_JUST_DEACTIVATED); } else // not vein go->SetLootState(GO_JUST_DEACTIVATED); } else if (go->GetGoType() == GAMEOBJECT_TYPE_FISHINGHOLE) { // The fishing hole used once more go->AddUse(); // if the max usage is reached, will be despawned in next tick if (go->GetUseCount() >= urand(go->GetGOInfo()->fishinghole.minSuccessOpens, go->GetGOInfo()->fishinghole.maxSuccessOpens)) { go->SetLootState(GO_JUST_DEACTIVATED); } else go->SetLootState(GO_READY); } else // not chest (or vein/herb/etc) go->SetLootState(GO_JUST_DEACTIVATED); loot->clear(); } else { // not fully looted object go->SetLootState(GO_ACTIVATED, player); // if the round robin player release, reset it. if (player->GetGUID() == loot->roundRobinPlayer) { if (Group* group = player->GetGroup()) { if (group->GetLootMethod() != MASTER_LOOT) { loot->roundRobinPlayer = 0; } } else loot->roundRobinPlayer = 0; } } } else if (IS_CORPSE_GUID(lguid)) // ONLY remove insignia at BG { Corpse* corpse = ObjectAccessor::GetCorpse(*player, lguid); if (!corpse || !corpse->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) return; loot = &corpse->loot; if (loot->isLooted()) { loot->clear(); corpse->RemoveFlag(CORPSE_FIELD_DYNAMIC_FLAGS, CORPSE_DYNFLAG_LOOTABLE); } } else if (IS_ITEM_GUID(lguid)) { Item* pItem = player->GetItemByGuid(lguid); if (!pItem) return; ItemTemplate const* proto = pItem->GetTemplate(); // destroy only 5 items from stack in case prospecting and milling if (proto->Flags & (ITEM_PROTO_FLAG_PROSPECTABLE | ITEM_PROTO_FLAG_MILLABLE)) { pItem->m_lootGenerated = false; pItem->loot.clear(); uint32 count = pItem->GetCount(); // >=5 checked in spell code, but will work for cheating cases also with removing from another stacks. if (count > 5) count = 5; player->DestroyItemCount(pItem, count, true); } else // FIXME: item must not be deleted in case not fully looted state. But this pre-request implement loot saving in DB at item save. Or cheating possible. player->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true); return; // item can be looted only single player } else { Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid); bool lootAllowed = creature && creature->isAlive() == (player->getClass() == CLASS_ROGUE && creature->lootForPickPocketed); if (!lootAllowed || !creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) return; loot = &creature->loot; if (loot->isLooted()) { // skip pickpocketing loot for speed, skinning timer reduction is no-op in fact if (!creature->isAlive()) creature->AllLootRemovedFromCorpse(); creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); loot->clear(); } else { // if the round robin player release, reset it. if (player->GetGUID() == loot->roundRobinPlayer) { if (Group* group = player->GetGroup()) { if (group->GetLootMethod() != MASTER_LOOT) { loot->roundRobinPlayer = 0; group->SendLooter(creature, NULL); // force update of dynamic flags, otherwise other group's players still not able to loot. creature->ForceValuesUpdateAtIndex(UNIT_DYNAMIC_FLAGS); } } else loot->roundRobinPlayer = 0; } } } //Player is not looking at loot list, he doesn't need to see updates on the loot list loot->RemoveLooter(player->GetGUID()); }
void WorldSession::HandleGossipSelectOptionOpcode(WorldPackets::NPC::GossipSelectOption& packet) { if (!_player->PlayerTalkClass->GetGossipMenu().GetItem(packet.GossipIndex)) return; // Prevent cheating on C++ scripted menus if (_player->PlayerTalkClass->GetGossipMenu().GetSenderGUID() != packet.GossipUnit) return; Creature* unit = nullptr; GameObject* go = nullptr; if (packet.GossipUnit.IsCreatureOrVehicle()) { unit = GetPlayer()->GetNPCIfCanInteractWith(packet.GossipUnit, UNIT_NPC_FLAG_NONE); if (!unit) { TC_LOG_DEBUG("network", "WORLD: HandleGossipSelectOptionOpcode - %s not found or you can't interact with him.", packet.GossipUnit.ToString().c_str()); return; } } else if (packet.GossipUnit.IsGameObject()) { go = _player->GetMap()->GetGameObject(packet.GossipUnit); if (!go) { TC_LOG_DEBUG("network", "WORLD: HandleGossipSelectOptionOpcode - %s not found.", packet.GossipUnit.ToString().c_str()); return; } } else { TC_LOG_DEBUG("network", "WORLD: HandleGossipSelectOptionOpcode - unsupported %s.", packet.GossipUnit.ToString().c_str()); return; } // remove fake death if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); if ((unit && unit->GetCreatureTemplate()->ScriptID != unit->LastUsedScriptID) || (go && go->GetGOInfo()->ScriptId != go->LastUsedScriptID)) { TC_LOG_DEBUG("network", "WORLD: HandleGossipSelectOptionOpcode - Script reloaded while in use, ignoring and set new scipt id"); if (unit) unit->LastUsedScriptID = unit->GetCreatureTemplate()->ScriptID; if (go) go->LastUsedScriptID = go->GetGOInfo()->ScriptId; _player->PlayerTalkClass->SendCloseGossip(); return; } if (!packet.PromotionCode.empty()) { if (unit) { unit->AI()->sGossipSelectCode(_player, packet.GossipID, packet.GossipIndex, packet.PromotionCode.c_str()); if (!sScriptMgr->OnGossipSelectCode(_player, unit, _player->PlayerTalkClass->GetGossipOptionSender(packet.GossipIndex), _player->PlayerTalkClass->GetGossipOptionAction(packet.GossipIndex), packet.PromotionCode.c_str())) _player->OnGossipSelect(unit, packet.GossipIndex, packet.GossipID); } else { go->AI()->GossipSelectCode(_player, packet.GossipID, packet.GossipIndex, packet.PromotionCode.c_str()); if (!sScriptMgr->OnGossipSelectCode(_player, go, _player->PlayerTalkClass->GetGossipOptionSender(packet.GossipIndex), _player->PlayerTalkClass->GetGossipOptionAction(packet.GossipIndex), packet.PromotionCode.c_str())) _player->OnGossipSelect(go, packet.GossipIndex, packet.GossipID); } } else { if (unit) { unit->AI()->sGossipSelect(_player, packet.GossipID, packet.GossipIndex); if (!sScriptMgr->OnGossipSelect(_player, unit, _player->PlayerTalkClass->GetGossipOptionSender(packet.GossipIndex), _player->PlayerTalkClass->GetGossipOptionAction(packet.GossipIndex))) _player->OnGossipSelect(unit, packet.GossipIndex, packet.GossipID); } else { go->AI()->GossipSelect(_player, packet.GossipID, packet.GossipIndex); if (!sScriptMgr->OnGossipSelect(_player, go, _player->PlayerTalkClass->GetGossipOptionSender(packet.GossipIndex), _player->PlayerTalkClass->GetGossipOptionAction(packet.GossipIndex))) _player->OnGossipSelect(go, packet.GossipIndex, packet.GossipID); } } }
void WorldSession::HandleGameObjectUseOpcode( WorldPacket & recv_data ) { uint64 guid; uint32 spellId = OPEN_CHEST; const GameObjectInfo *info; recv_data >> guid; sLog.outDebug( "WORLD: Recvd CMSG_GAMEOBJ_USE Message [guid=%u]", guid); GameObject *obj = ObjectAccessor::Instance().GetGameObject(*_player, guid); if(!obj) return; // uint32 t = obj->GetUInt32Value(GAMEOBJECT_TYPE_ID); //obj->SetUInt32Value(GAMEOBJECT_FLAGS,2); //obj->SetUInt32Value(GAMEOBJECT_FLAGS,2); uint32 t = obj->GetUInt32Value(GAMEOBJECT_TYPE_ID); switch(t) { //door case GAMEOBJECT_TYPE_DOOR: //0 obj->SetUInt32Value(GAMEOBJECT_FLAGS,33); obj->SetUInt32Value(GAMEOBJECT_STATE,0); //open //obj->SetUInt32Value(GAMEOBJECT_TIMESTAMP,0x465EE6D2); //load timestamp obj->SetLootState(GO_CLOSED); obj->SetRespawnTime(5); //close door in 5 seconds return; case GAMEOBJECT_TYPE_QUESTGIVER: // 2 _player->PrepareQuestMenu( guid ); _player->SendPreparedQuest( guid ); return; //Sitting: Wooden bench, chairs enzz case GAMEOBJECT_TYPE_CHAIR: //7 info = obj->GetGOInfo(); if(info) { spellId = info->sound0; //guid=GetPlayer()->GetGUID(); _player->TeleportTo(obj->GetMapId(), obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), obj->GetOrientation(),false,false); //offset 3 is related to the DB _player->SetUInt32Value(UNIT_FIELD_BYTES_1, _player->GetUInt32Value(UNIT_FIELD_BYTES_1) | (3 + spellId) ); return; } break; //big gun, its a spell/aura case GAMEOBJECT_TYPE_GOOBER: //10 //chest locked case GAMEOBJECT_TYPE_SPELLCASTER: //22 obj->SetUInt32Value(GAMEOBJECT_FLAGS,2); info = obj->GetGOInfo(); if(info) { spellId = info->sound0; if (spellId == 0) spellId = info->sound3; guid=_player->GetGUID(); } break; //fishing bobber case GAMEOBJECT_TYPE_FISHINGNODE: //17 { if(_player->GetGUID() != obj->GetOwnerGUID()) return; switch(obj->getLootState()) { case GO_CLOSED: // ready for loot { // 1) skill must beb >= base_zone_skill // 2) if skill == base_zone_skill => 5% chance // 3) chance is liniar dependence from (base_zone_skill-skill) int32 skill = _player->GetSkillValue(SKILL_FISHING); int32 zone_skill = _player->FishingMinSkillForCurrentZone(); int32 chance = skill - zone_skill + 5; int32 roll = irand(1,100); DEBUG_LOG("Fishing check (skill: %i zone min skill: %i chance %i roll: %i",skill,zone_skill,chance,roll); if(skill >= zone_skill && chance >= roll) { // prevent removing GO at spell cancel _player->RemoveGameObject(obj,false); obj->SetOwnerGUID(_player->GetGUID()); //fish catched _player->UpdateFishingSkill(); _player->SendLoot(obj->GetGUID(),LOOT_FISHING); } else { // fish escaped obj->SetLootState(GO_LOOTED); // can be deleted now WorldPacket data(SMSG_FISH_ESCAPED, 0); SendPacket(&data); } break; } case GO_LOOTED: // nothing to do, wiil be deleted at next update break; default: { obj->SetLootState(GO_LOOTED); WorldPacket data(SMSG_FISH_NOT_HOOKED, 0); SendPacket(&data); break; } } if(_player->m_currentSpell) { _player->m_currentSpell->SendChannelUpdate(0); _player->m_currentSpell->finish(); } return; } obj->CountUseTimes(); case GAMEOBJECT_TYPE_FLAGSTAND: //24 //GB flag info = obj->GetGOInfo(); if(info) { spellId = info->sound0; guid=_player->GetGUID(); } break; case GAMEOBJECT_TYPE_FLAGDROP: //26 //GB flag dropped info = obj->GetGOInfo(); if(info) { spellId = info->sound0; guid=_player->GetGUID(); } break; case GAMEOBJECT_TYPE_CUSTOM_TELEPORTER: info = obj->GetGOInfo(); if(info) { AreaTrigger *fields = objmgr.GetAreaTrigger( info->sound0 ); if(fields) { sLog.outDebug( "Teleporting player %u with coordinates X: %f Y: %f Z: %f Orientation: %f Map: %u\n", _player->GetGUIDLow(), fields->X,fields->Y,fields->Z,fields->Orientation,fields->mapId); _player->TeleportTo(fields->mapId, fields->X,fields->Y,fields->Z,fields->Orientation); sLog.outDebug( "Player %u teleported by %u\n", _player->GetGUIDLow(), info->sound0); } else sLog.outDebug( "Unknown areatrigger_template id %u\n", info->sound0); delete fields; return; } break; default: sLog.outDebug( "Unknown Object Type %u\n", obj->GetUInt32Value(GAMEOBJECT_TYPE_ID)); break; } SpellEntry const *spellInfo = sSpellStore.LookupEntry( spellId ); if(!spellInfo) { sLog.outError("WORLD: unknown spell id %i\n", spellId); return; } Spell *spell = new Spell(_player, spellInfo, false, 0); SpellCastTargets targets; targets.setUnitTarget( _player ); targets.m_GOTarget = obj; spell->prepare(&targets); }
void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket & recv_data) { bool isCurrency = recv_data.GetOpcode() == CMSG_AUTOSTORE_LOOT_CURRENCY; sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_AUTOSTORE_LOOT_ITEM"); Player* player = GetPlayer(); uint64 lguid = player->GetLootGUID(); Loot* loot = NULL; uint8 lootSlot = 0; uint32 objEntry = 0; uint32 objType = 0; recv_data >> lootSlot; if (IS_GAMEOBJECT_GUID(lguid)) { GameObject* go = player->GetMap()->GetGameObject(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; } objEntry = go->GetGOInfo()->entry; objType = 3; loot = &go->loot; } else if (IS_ITEM_GUID(lguid)) { Item* pItem = player->GetItemByGuid(lguid); if (!pItem) { player->SendLootRelease(lguid); return; } objEntry = pItem->GetTemplate()->ItemId; objType = 2; 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* creature = GetPlayer()->GetMap()->GetCreature(lguid); bool ok_loot = creature && creature->isAlive() == (player->getClass() == CLASS_ROGUE && creature->lootForPickPocketed); if (!ok_loot || !creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) { player->SendLootRelease(lguid); return; } objEntry = creature->GetCreatureTemplate()->Entry; objType = 1; loot = &creature->loot; } if (isCurrency && loot) { uint8 currencys = 0; std::list<CurrencyLoot> temp = sObjectMgr->GetCurrencyLoot(objEntry, objType); for (std::list<CurrencyLoot>::iterator i = temp.begin(); i != temp.end(); ++i) { if (currencys == lootSlot) player->SetCurrency(i->CurrencyId, i->CurrencyAmount * 100); ++currencys; } } else if (loot) player->StoreLootItem(lootSlot, loot); }
void WorldSession::DoLootRelease(ObjectGuid lguid) { Player *player = GetPlayer(); Loot *loot; player->SetLootGUID(ObjectGuid()); player->SendLootRelease(lguid); player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING); if(!player->IsInWorld()) return; switch(lguid.GetHigh()) { case HIGHGUID_GAMEOBJECT: { GameObject *go = GetPlayer()->GetMap()->GetGameObject(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))) return; loot = &go->loot; if (go->GetGoType() == GAMEOBJECT_TYPE_DOOR) { // locked doors are opened with spelleffect openlock, prevent remove its as looted go->UseDoorOrButton(); } else if (loot->isLooted() || go->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE) { // GO is mineral vein? so it is not removed after its looted if(go->GetGoType() == GAMEOBJECT_TYPE_CHEST) { uint32 go_min = go->GetGOInfo()->chest.minSuccessOpens; uint32 go_max = go->GetGOInfo()->chest.maxSuccessOpens; // only vein pass this check if(go_min != 0 && go_max > go_min) { float amount_rate = sWorld.getConfig(CONFIG_FLOAT_RATE_MINING_AMOUNT); float min_amount = go_min*amount_rate; float max_amount = go_max*amount_rate; go->AddUse(); float uses = float(go->GetUseCount()); if(uses < max_amount) { if(uses >= min_amount) { float chance_rate = sWorld.getConfig(CONFIG_FLOAT_RATE_MINING_NEXT); int32 ReqValue = 175; LockEntry const *lockInfo = sLockStore.LookupEntry(go->GetGOInfo()->chest.lockId); if(lockInfo) ReqValue = lockInfo->Skill[0]; float skill = float(player->GetSkillValue(SKILL_MINING))/(ReqValue+25); double chance = pow(0.8*chance_rate,4*(1/double(max_amount))*double(uses)); if(roll_chance_f(float(100.0f*chance+skill))) { go->SetLootState(GO_READY); } else // not have more uses go->SetLootState(GO_JUST_DEACTIVATED); } else // 100% chance until min uses go->SetLootState(GO_READY); } else // max uses already go->SetLootState(GO_JUST_DEACTIVATED); } else // not vein go->SetLootState(GO_JUST_DEACTIVATED); } else if (go->GetGoType() == GAMEOBJECT_TYPE_FISHINGHOLE) { // The fishing hole used once more go->AddUse(); // if the max usage is reached, will be despawned at next tick if (go->GetUseCount() >= urand(go->GetGOInfo()->fishinghole.minSuccessOpens,go->GetGOInfo()->fishinghole.maxSuccessOpens)) { go->SetLootState(GO_JUST_DEACTIVATED); } else go->SetLootState(GO_READY); } else // not chest (or vein/herb/etc) go->SetLootState(GO_JUST_DEACTIVATED); loot->clear(); } else // not fully looted object go->SetLootState(GO_ACTIVATED); break; } case HIGHGUID_CORPSE: // ONLY remove insignia at BG { Corpse *corpse = _player->GetMap()->GetCorpse(lguid); if (!corpse || !corpse->IsWithinDistInMap(_player,INTERACTION_DISTANCE) ) return; loot = &corpse->loot; if (loot->isLooted()) { loot->clear(); corpse->RemoveFlag(CORPSE_FIELD_DYNAMIC_FLAGS, CORPSE_DYNFLAG_LOOTABLE); } break; } case HIGHGUID_ITEM: { Item *pItem = player->GetItemByGuid(lguid ); if (!pItem) return; switch (pItem->loot.loot_type) { // temporary loot in stacking items, clear loot state, no auto loot move case LOOT_MILLING: case LOOT_PROSPECTING: { uint32 count = pItem->GetCount(); // >=5 checked in spell code, but will work for cheating cases also with removing from another stacks. if(count > 5) count = 5; // reset loot for allow repeat looting if stack > 5 pItem->loot.clear(); pItem->SetLootState(ITEM_LOOT_REMOVED); player->DestroyItemCount(pItem, count, true); break; } // temporary loot, auto loot move case LOOT_DISENCHANTING: { if (!pItem->loot.isLooted()) player->AutoStoreLoot(pItem->loot); // can be lost if no space pItem->loot.clear(); pItem->SetLootState(ITEM_LOOT_REMOVED); player->DestroyItem( pItem->GetBagSlot(),pItem->GetSlot(), true); break; } // normal persistence loot default: { // must be destroyed only if no loot if (pItem->loot.isLooted()) { pItem->SetLootState(ITEM_LOOT_REMOVED); player->DestroyItem( pItem->GetBagSlot(),pItem->GetSlot(), true); } break; } } return; // item can be looted only single player } case HIGHGUID_UNIT: case HIGHGUID_VEHICLE: { Creature* pCreature = GetPlayer()->GetMap()->GetCreature(lguid); bool ok_loot = pCreature && pCreature->isAlive() == (player->getClass()==CLASS_ROGUE && pCreature->lootForPickPocketed); if ( !ok_loot || !pCreature->IsWithinDistInMap(_player,INTERACTION_DISTANCE) ) return; loot = &pCreature->loot; // update next looter if(Group* group = pCreature->GetGroupLootRecipient()) if (group->GetLooterGuid() == player->GetObjectGuid()) group->UpdateLooterGuid(pCreature); if (loot->isLooted()) { // for example skinning after normal loot pCreature->PrepareBodyLootState(); if(!pCreature->isAlive()) pCreature->AllLootRemovedFromCorpse(); } break; } default: { sLog.outError("%s is unsupported for looting.", lguid.GetString().c_str()); return; } } //Player is not looking at loot list, he doesn't need to see updates on the loot list loot->RemoveLooter(player->GetGUID()); }
void LootObject::Refresh(Player* bot, ObjectGuid guid) { skillId = SKILL_NONE; reqSkillValue = 0; reqItem = NULL; this->guid = ObjectGuid(); PlayerbotAI* ai = bot->GetPlayerbotAI(); Creature *creature = ai->GetCreature(guid); if (creature && creature->getDeathState() == CORPSE) { if (creature->HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE)) this->guid = guid; if (creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE)) { skillId = creature->GetCreatureTemplate()->GetRequiredLootSkill(); uint32 targetLevel = creature->getLevel(); reqSkillValue = targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel - 10) * 10 : targetLevel * 5; if (bot->HasSkill(skillId) && bot->GetSkillValue(skillId) >= reqSkillValue) this->guid = guid; } return; } GameObject* go = ai->GetGameObject(guid); if (go && go->isSpawned()) { uint32 lockId = go->GetGOInfo()->GetLockId(); LockEntry const *lockInfo = sLockStore.LookupEntry(lockId); if (!lockInfo) return; // TODO: remove? /*for(uint32 i = 0; i < 6; ++i) { if (go->GetGOInfo()->questItems[i]) { this->guid = guid; return; } }*/ for (int i = 0; i < 8; ++i) { switch (lockInfo->Type[i]) { case LOCK_KEY_ITEM: if (lockInfo->Index[i] > 0) { reqItem = lockInfo->Index[i]; this->guid = guid; } break; case LOCK_KEY_SKILL: if (SkillByLockType(LockType(lockInfo->Index[i])) > 0) { skillId = SkillByLockType(LockType(lockInfo->Index[i])); reqSkillValue = lockInfo->Skill[i]; this->guid = guid; } break; default: break; } } } }
void WorldSession::DoLootRelease(ObjectGuid lguid) { Player *player = GetPlayer(); Loot *loot; player->SetLootGUID(ObjectGuid()); player->SendLootRelease(lguid); player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING); if(!player->IsInWorld()) return; switch(lguid.GetHigh()) { case HIGHGUID_GAMEOBJECT: { GameObject *go = GetPlayer()->GetMap()->GetGameObject(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))) return; loot = &go->loot; if (go->GetGoType() == GAMEOBJECT_TYPE_DOOR) { // locked doors are opened with spelleffect openlock, prevent remove its as looted go->UseDoorOrButton(); } else if (loot->isLooted() || go->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE) { // GO is mineral vein? so it is not removed after its looted if(go->GetGoType() == GAMEOBJECT_TYPE_CHEST) { uint32 go_min = go->GetGOInfo()->chest.minSuccessOpens; uint32 go_max = go->GetGOInfo()->chest.maxSuccessOpens; if (player->GetInstanceId()) { Map *map = go->GetMap(); if (map->IsDungeon()) { if (map->IsRaidOrHeroicDungeon()) { ((InstanceMap *)map)->PermBindAllPlayers(player); } else { // the reset time is set but not added to the scheduler // until the players leave the instance time_t resettime = go->GetRespawnTimeEx() + 2 * HOUR; if(InstanceSave *save = player->GetMap()->GetInstanceSave()) if(save->GetResetTime() < resettime) save->SetResetTime(resettime); } } } // only vein pass this check if(go_min != 0 && go_max > go_min) { float amount_rate = sWorld.getConfig(CONFIG_FLOAT_RATE_MINING_AMOUNT); float min_amount = go_min*amount_rate; float max_amount = go_max*amount_rate; go->AddUse(); float uses = float(go->GetUseCount()); if(uses < max_amount) { if(uses >= min_amount) { float chance_rate = sWorld.getConfig(CONFIG_FLOAT_RATE_MINING_NEXT); int32 ReqValue = 175; LockEntry const *lockInfo = sLockStore.LookupEntry(go->GetGOInfo()->chest.lockId); if(lockInfo) ReqValue = lockInfo->Skill[0]; float skill = float(player->GetSkillValue(SKILL_MINING))/(ReqValue+25); double chance = pow(0.8*chance_rate,4*(1/double(max_amount))*double(uses)); if(roll_chance_f(float(100.0f*chance+skill))) { go->SetLootState(GO_READY); } else // not have more uses go->SetLootState(GO_JUST_DEACTIVATED); } else // 100% chance until min uses go->SetLootState(GO_READY); } else // max uses already go->SetLootState(GO_JUST_DEACTIVATED); } else // not vein go->SetLootState(GO_JUST_DEACTIVATED); } else if (go->GetGoType() == GAMEOBJECT_TYPE_FISHINGHOLE) { // The fishing hole used once more go->AddUse(); // if the max usage is reached, will be despawned at next tick if (go->GetUseCount() >= urand(go->GetGOInfo()->fishinghole.minSuccessOpens,go->GetGOInfo()->fishinghole.maxSuccessOpens)) { go->SetLootState(GO_JUST_DEACTIVATED); } else go->SetLootState(GO_READY); } else // not chest (or vein/herb/etc) go->SetLootState(GO_JUST_DEACTIVATED); loot->clear(); } else // not fully looted object go->SetLootState(GO_ACTIVATED); if (player->GetInstanceId()) { Map *map = go->GetMap(); if (map->IsDungeon()) { if (map->IsRaidOrHeroicDungeon()) { ((InstanceMap *)map)->PermBindAllPlayers(player); } else { // the reset time is set but not added to the scheduler // until the players leave the instance time_t resettime = go->GetRespawnTimeEx() + 2 * HOUR; if(InstanceSave *save = player->GetMap()->GetInstanceSave()) if(save->GetResetTime() < resettime) save->SetResetTime(resettime); } } } break; } case HIGHGUID_CORPSE: // ONLY remove insignia at BG { Corpse *corpse = _player->GetMap()->GetCorpse(lguid); if (!corpse || !corpse->IsWithinDistInMap(_player,INTERACTION_DISTANCE) ) return; loot = &corpse->loot; if (loot->isLooted()) { loot->clear(); corpse->RemoveFlag(CORPSE_FIELD_DYNAMIC_FLAGS, CORPSE_DYNFLAG_LOOTABLE); } break; } case HIGHGUID_ITEM: { Item *pItem = player->GetItemByGuid(lguid ); if(!pItem) return; ItemPrototype const* proto = pItem->GetProto(); // destroy only 5 items from stack in case prospecting and milling if( (proto->BagFamily & (BAG_FAMILY_MASK_MINING_SUPP|BAG_FAMILY_MASK_HERBS)) && proto->Class == ITEM_CLASS_TRADE_GOODS) { pItem->m_lootGenerated = false; pItem->loot.clear(); uint32 count = pItem->GetCount(); // >=5 checked in spell code, but will work for cheating cases also with removing from another stacks. if(count > 5) count = 5; player->DestroyItemCount(pItem, count, true); } else // FIXME: item don't must be deleted in case not fully looted state. But this pre-request implement loot saving in DB at item save. Or checting possible. player->DestroyItem( pItem->GetBagSlot(),pItem->GetSlot(), true); return; // item can be looted only single player } case HIGHGUID_UNIT: { Creature* pCreature = GetPlayer()->GetMap()->GetCreature(lguid); bool ok_loot = pCreature && pCreature->isAlive() == (player->getClass()==CLASS_ROGUE && pCreature->lootForPickPocketed); if ( !ok_loot || !pCreature->IsWithinDistInMap(_player,INTERACTION_DISTANCE) ) return; loot = &pCreature->loot; // update next looter if(Group* group = pCreature->GetGroupLootRecipient()) if (group->GetLooterGuid() == player->GetObjectGuid()) group->UpdateLooterGuid(pCreature); if (loot->isLooted()) { // for example skinning after normal loot pCreature->PrepareBodyLootState(); if(!pCreature->isAlive()) pCreature->AllLootRemovedFromCorpse(); } break; } default: { sLog.outError("%s is unsupported for looting.", lguid.GetString().c_str()); return; } } //Player is not looking at loot list, he doesn't need to see updates on the loot list loot->RemoveLooter(player->GetGUID()); }
GameObject* Garrison::Plot::CreateGameObject(Map* map, GarrisonFactionIndex faction) { uint32 entry = EmptyGameObjectId; if (BuildingInfo.PacketInfo) { GarrPlotInstanceEntry const* plotInstance = sGarrPlotInstanceStore.AssertEntry(PacketInfo.GarrPlotInstanceID); GarrPlotEntry const* plot = sGarrPlotStore.AssertEntry(plotInstance->GarrPlotID); GarrBuildingEntry const* building = sGarrBuildingStore.AssertEntry(BuildingInfo.PacketInfo->GarrBuildingID); entry = faction == GARRISON_FACTION_INDEX_HORDE ? plot->HordeConstructionGameObjectID : plot->AllianceConstructionGameObjectID; if (BuildingInfo.PacketInfo->Active || !entry) entry = faction == GARRISON_FACTION_INDEX_HORDE ? building->HordeGameObjectID : building->AllianceGameObjectID; } if (!sObjectMgr->GetGameObjectTemplate(entry)) { TC_LOG_ERROR("garrison", "Garrison attempted to spawn gameobject whose template doesn't exist (%u)", entry); return nullptr; } Position const& pos = PacketInfo.PlotPos; GameObject* building = new GameObject(); if (!building->Create(entry, map, 0, pos, G3D::Quat(), 255, GO_STATE_READY)) { delete building; return nullptr; } if (BuildingInfo.CanActivate() && BuildingInfo.PacketInfo && !BuildingInfo.PacketInfo->Active) { if (FinalizeGarrisonPlotGOInfo const* finalizeInfo = sGarrisonMgr.GetPlotFinalizeGOInfo(PacketInfo.GarrPlotInstanceID)) { Position const& pos2 = finalizeInfo->FactionInfo[faction].Pos; GameObject* finalizer = new GameObject(); if (finalizer->Create(finalizeInfo->FactionInfo[faction].GameObjectId, map, 0, pos2, G3D::Quat(), 255, GO_STATE_READY)) { // set some spell id to make the object delete itself after use finalizer->SetSpellId(finalizer->GetGOInfo()->goober.spell); finalizer->SetRespawnTime(0); if (uint16 animKit = finalizeInfo->FactionInfo[faction].AnimKitId) finalizer->SetAnimKitId(animKit, false); map->AddToMap(finalizer); } else delete finalizer; } } if (building->GetGoType() == GAMEOBJECT_TYPE_GARRISON_BUILDING && building->GetGOInfo()->garrisonBuilding.SpawnMap) { for (CellObjectGuidsMap::value_type const& cellGuids : sObjectMgr->GetMapObjectGuids(building->GetGOInfo()->garrisonBuilding.SpawnMap, map->GetSpawnMode())) { for (ObjectGuid::LowType spawnId : cellGuids.second.creatures) if (Creature* spawn = BuildingSpawnHelper<Creature, &Creature::SetHomePosition>(building, spawnId, map)) BuildingInfo.Spawns.insert(spawn->GetGUID()); for (ObjectGuid::LowType spawnId : cellGuids.second.gameobjects) if (GameObject* spawn = BuildingSpawnHelper<GameObject, &GameObject::RelocateStationaryPosition>(building, spawnId, map)) BuildingInfo.Spawns.insert(spawn->GetGUID()); } } BuildingInfo.Guid = building->GetGUID(); return building; }