void InstanceMgr::BuildSavedRaidInstancesForPlayer(Player* plr) { WorldPacket data(SMSG_RAID_INSTANCE_INFO, 200); Instance * in; InstanceMap::iterator itr; uint32 i; uint32 counter = 0; data << counter; for(i = 0; i < NUM_MAPS; i++) { MapEntry* map = dbcMap.LookupEntry(i); if(map) { in = GetSavedInstance(i, plr->GetLowGUID(), plr->iRaidType); if(in && map->israid()) { data << in->m_mapId; data << in->m_difficulty; data << uint64(in->m_instanceId); data << uint8(in->m_expiration < UNIXTIME ? 0 : 1); data << uint8(0); if( in->m_expiration > UNIXTIME ) data << uint32(in->m_expiration - UNIXTIME); else data << uint32(0); ++counter; } } } *(uint32*)&data.contents()[0] = counter; plr->GetSession()->SendPacket(&data); }
void InstanceMgr::ResetSavedInstances(Player* plr) { WorldPacket data(SMSG_INSTANCE_RESET, 4); Instance * in; InstanceMap::iterator itr; InstanceMap* instancemap; MapEntry* map; uint32 i; if(plr == NULL || !plr->IsInWorld() || plr->GetMapMgr()->GetMapInfo()->type != INSTANCE_NULL) return; m_mapLock.Acquire(); for(i = 0; i < NUM_MAPS; i++) { if(m_instances[i] != NULL) { instancemap = m_instances[i]; map = dbcMap.LookupEntry(i); for(itr = instancemap->begin(); itr != instancemap->end();) { in = itr->second; ++itr; if((!map->israid()) && in->m_mapInfo->type == INSTANCE_MULTIMODE && plr->GetGroupID() == in->m_creatorGroup) { if( in->m_difficulty == MODE_5PLAYER_HEROIC && in->m_SavedPlayers.size() )//heroic instances can't be reset once they are saved. { plr->GetSession()->SystemMessage("Heroic instances are reset daily at 08:00 CET!"); continue; } if(plr->GetGroup() != NULL && plr->GetGroup()->GetLeader() != plr->m_playerInfo) { plr->GetSession()->SystemMessage("Can't reset instance %u (%s), you are not the group leader!", in->m_instanceId, in->m_mapMgr->GetMapInfo()->name); continue; } if(in->m_mapMgr && in->m_mapMgr->HasPlayers()) { plr->GetSession()->SystemMessage("Can't reset instance %u (%s) when there are still players inside!", in->m_instanceId, in->m_mapMgr->GetMapInfo()->name); continue; } // destroy the instance bool destroyed = _DeleteInstance(in, true); if(destroyed) { // <mapid> has been reset. data << uint32(in->m_mapId); plr->GetSession()->SendPacket(&data); } } } } } m_mapLock.Release(); }
void WorldSession::_HandleAreaTriggerOpcode(uint32 id) { DEBUG_LOG( "WorldSession","HandleAreaTriggerOpcode: %u", id); // Are we REALLY here? CHECK_INWORLD_RETURN; // Search quest log, find any exploration quests sQuestMgr.OnPlayerExploreArea(GetPlayer(),id); AreaTrigger* pAreaTrigger = AreaTriggerStorage.LookupEntry( id ); sHookInterface.OnAreaTrigger(_player, id); CALL_INSTANCE_SCRIPT_EVENT( _player->GetMapMgr(), OnAreaTrigger )( _player, id ); // if in BG handle is triggers if( _player->m_bg ) { _player->m_bg->HookOnAreaTrigger(_player, id); return; } // Hook for Scripted Areatriggers _player->GetMapMgr()->HookOnAreaTrigger(_player, id); if( _player->GetSession()->CanUseCommand('z') ) { if( pAreaTrigger != NULL ) sChatHandler.BlueSystemMessage( this, "[%sSystem%s] |rEntered areatrigger: %s%u (%s).", MSG_COLOR_WHITE, MSG_COLOR_LIGHTBLUE, MSG_COLOR_SUBWHITE, id, pAreaTrigger->Name ); else sChatHandler.BlueSystemMessage( this, "[%sSystem%s] |rEntered areatrigger: %s%u", MSG_COLOR_WHITE, MSG_COLOR_LIGHTBLUE, MSG_COLOR_SUBWHITE, id); } if( pAreaTrigger == NULL ) { OUT_DEBUG("Missing AreaTrigger: %u", id); return; } switch(pAreaTrigger->Type) { case ATTYPE_INSTANCE: { if(_player->GetPlayerStatus() != TRANSFER_PENDING) //only ports if player is out of pendings { MapInfo * pMi = WorldMapInfoStorage.LookupEntry(pAreaTrigger->Mapid); MapEntry* map = dbcMap.LookupEntry(pAreaTrigger->Mapid); if(!pMi) return; //do we meet the map requirements? uint8 reason = CheckTeleportPrerequsites(pAreaTrigger, this, _player, pAreaTrigger->Mapid); if(reason != AREA_TRIGGER_FAILURE_OK) { const char * pReason = AreaTriggerFailureMessages[reason]; char msg[200]; WorldPacket data(SMSG_AREA_TRIGGER_MESSAGE, 50); data << uint32(0); switch (reason) { case AREA_TRIGGER_FAILURE_LEVEL: { snprintf(msg,200,pReason,pAreaTrigger->required_level); data << msg; }break; case AREA_TRIGGER_FAILURE_NO_ATTUNE_I: { ItemPrototype * pItem = ItemPrototypeStorage.LookupEntry(pMi->required_item); snprintf(msg, 200, pReason, pItem ? pItem->Name1 : "UNKNOWN"); data << msg; }break; case AREA_TRIGGER_FAILURE_NO_ATTUNE_Q: { Quest * pQuest = QuestStorage.LookupEntry(pMi->required_quest); snprintf(msg, 200, pReason, pQuest ? pQuest->title : "UNKNOWN"); data << msg; }break; case AREA_TRIGGER_FAILURE_NO_KEY: { string temp_msg[2]; string tmp_msg; for(uint32 i = 0; i < 2; ++i) { if (pMi->heroic_key[i] && _player->GetItemInterface()->GetItemCount(pMi->heroic_key[i], false)==0) { ItemPrototype * pKey = ItemPrototypeStorage.LookupEntry(pMi->heroic_key[i]); if(pKey) temp_msg[i] += pKey->Name1; else temp_msg[i] += "UNKNOWN"; } } tmp_msg += temp_msg[0]; if(temp_msg[0].size() && temp_msg[1].size()) tmp_msg += "\" and \""; tmp_msg += temp_msg[1]; snprintf(msg, 200, pReason, tmp_msg.c_str()); data << msg; }break; case AREA_TRIGGER_FAILURE_LEVEL_HEROIC: { snprintf(msg, 200, pReason, pMi->HasFlag(WMI_INSTANCE_XPACK_02) ? 80 : 70); data << msg; }break; default: { data << pReason; }break; } data << uint8(0); SendPacket(&data); return; } if( _player->IsMounted()) TO_UNIT(_player)->Dismount(); uint32 InstanceID = 0; // Try to find a saved instance and // do not handle Hyjal Inn (trigger 4319), since we need a unique mapid when generating our instance_id. if( id != 4319 && pMi && ( map->israid() || _player->iRaidType >= MODE_NORMAL_25MEN && pMi->type == INSTANCE_MULTIMODE ) ) { //Do we have a saved instance we should use? Instance * in = NULL; in = sInstanceMgr.GetSavedInstance( pMi->mapid,_player->GetLowGUID(), _player->iRaidType ); if( in != NULL && in->m_instanceId ) { //If we are the first to enter this instance, also set our current group id. if( in->m_mapMgr == NULL || (!in->m_mapMgr->HasPlayers() && _player->GetGroupID() != in->m_creatorGroup)) in->m_creatorGroup =_player->GetGroupID(); InstanceID = in->m_instanceId; } } //Save our entry point and try to teleport to our instance _player->SaveEntryPoint(pAreaTrigger->Mapid); _player->SafeTeleport(pAreaTrigger->Mapid, InstanceID, LocationVector(pAreaTrigger->x, pAreaTrigger->y, pAreaTrigger->z, pAreaTrigger->o)); } }break; case ATTYPE_QUESTTRIGGER: { }break; case ATTYPE_INN: { if( _player->IsMounted()) TO_UNIT(_player)->Dismount(); // Inn if (!_player->m_isResting) _player->ApplyPlayerRestState(true); }break; case ATTYPE_TELEPORT: { if( _player->GetPlayerStatus() != TRANSFER_PENDING) //only ports if player is out of pendings { if( _player->IsMounted() ) TO_UNIT(_player)->Dismount(); _player->SaveEntryPoint(pAreaTrigger->Mapid); _player->SafeTeleport(pAreaTrigger->Mapid, 0, LocationVector(pAreaTrigger->x, pAreaTrigger->y, pAreaTrigger->z, pAreaTrigger->o)); } }break; default:break; } }
uint32 InstanceMgr::PreTeleport(uint32 mapid, Player* plr, uint32 instanceid) { // preteleport is where all the magic happens :P instance creation, etc. MapInfo * inf = LimitedMapInfoStorage.LookupEntry(mapid); MapEntry* map = dbcMap.LookupEntry(mapid); InstanceMap * instancemap; Instance * in = NULL; //is the map vaild? if(inf == NULL || mapid >= NUM_MAPS) return INSTANCE_ABORT_NOT_FOUND; // main continent check. if(inf->type == INSTANCE_NULL) // we can check if the destination world server is online or not and then cancel them before they load. return (m_singleMaps[mapid] != NULL) ? INSTANCE_OK : INSTANCE_ABORT_NOT_FOUND; // shouldn't happen if(inf->type == INSTANCE_PVP) return INSTANCE_ABORT_NOT_FOUND; if(map->israid()) // check that heroic mode is available if the player has requested it. { if(plr->iRaidType > 1 && inf->type != INSTANCE_MULTIMODE) return INSTANCE_ABORT_HEROIC_MODE_NOT_AVAILABLE; } else if(plr->iInstanceType && inf->type != INSTANCE_MULTIMODE) return INSTANCE_ABORT_HEROIC_MODE_NOT_AVAILABLE; //do we need addition raid/heroic checks? Group * pGroup = plr->GetGroup() ; if( !plr->triggerpass_cheat ) { // players without groups cannot enter raid instances (no soloing them:P) if( pGroup == NULL && (map->israid() || inf->type == INSTANCE_MULTIMODE)) return INSTANCE_ABORT_NOT_IN_RAID_GROUP; //and has the required level if( plr->getLevel() < 80) { if(!map->israid()) { //otherwise we still need to be lvl 70/80 for heroic. if( plr->iInstanceType && plr->getLevel() < uint32(inf->HasFlag(WMI_INSTANCE_XPACK_02) ? 80 : 70)) return INSTANCE_ABORT_HEROIC_MODE_NOT_AVAILABLE; } else //otherwise we still need to be lvl 70/80 for heroic. if( plr->iRaidType > 1 && plr->getLevel() < uint32(inf->HasFlag(WMI_INSTANCE_XPACK_02) ? 80 : 70)) return INSTANCE_ABORT_HEROIC_MODE_NOT_AVAILABLE; //and we might need a key too. bool reqkey = (inf->heroic_key[0] || inf->heroic_key[1])? true : false; bool haskey = (plr->GetItemInterface()->GetItemCount(inf->heroic_key[0], false) || plr->GetItemInterface()->GetItemCount(inf->heroic_key[1], false))? true : false; if(reqkey && !haskey) return INSTANCE_ABORT_HEROIC_MODE_NOT_AVAILABLE; } } // if we are here, it means: // 1) we're a non-raid instance // 2) we're a raid instance, and the person is in a group. // so, first we have to check if they have an instance on this map already, if so, allow them to teleport to that. // next we check if there is a saved instance belonging to him. // otherwise, we can create them a new one. m_mapLock.Acquire(); //find all instances for our map instancemap = m_instances[mapid]; if(instancemap) { InstanceMap::iterator itr; // do we have a specific instance id we should enter (saved or active). // don't bother looking for saved instances, if we had one we found it in areatrigger.cpp if(instanceid != 0) { itr = instancemap->find(instanceid); if(itr != instancemap->end()) { in = itr->second; //we have an instance,but can we enter it? uint8 owns = PlayerOwnsInstance( in, plr ); if( owns >= OWNER_CHECK_OK ) { // If the map is active and has players if(in->m_mapMgr && in->m_mapMgr->HasPlayers() && !plr->triggerpass_cheat) { //check if combat is in progress if( in->m_mapMgr->IsCombatInProgress()) { m_mapLock.Release(); return INSTANCE_ABORT_ENCOUNTER; } // check if we are full if( in->m_mapMgr->GetPlayerCount() >= inf->playerlimit ) { m_mapLock.Release(); return INSTANCE_ABORT_FULL; } } uint32 plrdiff = map->israid() ? plr->iRaidType : plr->iInstanceType; if(in->m_difficulty == plrdiff) { //wakeup call for saved instances if(!in->m_mapMgr) in->m_mapMgr = _CreateInstance(in); if(owns == OWNER_CHECK_SAVED_OK && !in->m_mapMgr->HasPlayers()) { if(plr->GetGroup()) in->m_creatorGroup = plr->GetGroupID(); } m_mapLock.Release(); return INSTANCE_OK; } else { m_mapLock.Release(); return INSTANCE_ABORT_TOO_MANY; } } else DEBUG_LOG("InstanceMgr","Check failed %s, return code %u",plr->GetName(), owns); } m_mapLock.Release(); return INSTANCE_ABORT_NOT_FOUND; } else { // search all active instances and see if we have one here. for(itr = instancemap->begin(); itr != instancemap->end();) { in = itr->second; ++itr; //we have an instance,but do we own it? uint8 owns = PlayerOwnsInstance(in, plr); if( owns >= OWNER_CHECK_OK ) { // check the player count and in combat status. if(in->m_mapMgr && in->m_mapMgr->HasPlayers() && !plr->triggerpass_cheat) { if( in->m_mapMgr->IsCombatInProgress()) { m_mapLock.Release(); return INSTANCE_ABORT_ENCOUNTER; } // check if we are full if( in->m_mapMgr->GetPlayerCount() >= inf->playerlimit ) { m_mapLock.Release(); return INSTANCE_ABORT_FULL; } } uint32 plrdiff = map->israid() ? plr->iRaidType : plr->iInstanceType; if(in->m_difficulty == plrdiff) { //wakeup call for saved instances if(!in->m_mapMgr) in->m_mapMgr = _CreateInstance(in); if(owns == OWNER_CHECK_SAVED_OK && !in->m_mapMgr->HasPlayers()) { if(plr->GetGroup()) in->m_creatorGroup = plr->GetGroupID(); } // found our instance, allow him in. m_mapLock.Release(); return INSTANCE_OK; } } else DEBUG_LOG("InstanceMgr","Check failed %s, return code %u",plr->GetName(), owns); } } } else { if(instanceid != 0) { // wtf, how can we have an instance_id for a mapid which doesn't even exist? m_mapLock.Release(); return INSTANCE_ABORT_NOT_FOUND; } // this mapid hasn't been added yet, so we gotta create the hashmap now. m_instances[mapid] = new InstanceMap; instancemap = m_instances[mapid]; } // if we're here, it means we need to create a new instance. bool raid = map->israid(); in = new Instance; in->m_creation = UNIXTIME; in->m_expiration = (raid ? UNIXTIME + inf->cooldown : 0); // expire time 0 is 10 minutes after last player leaves in->m_creatorGuid = plr->GetLowGUID(); in->m_creatorGroup = (pGroup ? pGroup->GetID() : 0); in->m_difficulty = (raid ? plr->iRaidType : plr->iInstanceType); in->m_instanceId = GenerateInstanceID(); in->m_mapId = mapid; in->m_mapMgr = NULLMAPMGR; // always start off without a map manager, it is created in _CreateInstance(in) //crash fix; GM's without group will start up raid instances as if they where nonraids //this to avoid exipring check, this is mainly for developers purpose; GM's should NOT invite any players here! if( plr->triggerpass_cheat && !plr->GetGroup() && raid) { const char * message = "Started this instance for development purposes only, do not invite players!!"; sEventMgr.AddEvent( plr, &Player::_Warn, message, EVENT_UNIT_SENDMESSAGE, 5000, 1, 0); } in->m_mapInfo = inf; in->m_dbcMap = map; in->m_isBattleground = false; plr->SetInstanceID(in->m_instanceId); DEBUG_LOG("InstanceMgr", "Prepared new %s %u for player %u and group %u on map %u with difficulty %u. (%u)", raid ? "Raid" : "Instance" ,in->m_instanceId, in->m_creatorGuid, in->m_creatorGroup, in->m_mapId, in->m_difficulty, in->m_instanceId); // apply it in the instance map instancemap->insert( InstanceMap::value_type( in->m_instanceId, in ) ); // create the actual instance (if we don't GetInstance() won't be able to access it). in->m_mapMgr = _CreateInstance(in); // instance created ok, i guess? return the ok for him to transport. m_mapLock.Release(); return INSTANCE_OK; }