mirror of
https://github.com/ornfelt/azerothcore_lua_scripts
synced 2026-08-22 06:26:03 -04:00
706 lines
25 KiB
C++
706 lines
25 KiB
C++
#include "AccountMgr.h"
|
|
#include "Player.h"
|
|
#include "Creature.h"
|
|
#include "GameObject.h"
|
|
#include "DatabaseEnv.h"
|
|
#include "WorldSession.h"
|
|
#include "MapManager.h"
|
|
#include "ObjectMgr.h"
|
|
#include "PersonalInstance.h"
|
|
#include "ObjectExtension.cpp"
|
|
#include "GameTime.h"
|
|
|
|
#define DEBUG_PERSONAL_INSTANCE false //show debug info in console
|
|
#define DEFAULT_PERSONAL_INSTANCE_MAP // to not require to creae one for every account, we are allowed to use these by default
|
|
#define PERSONAL_INSTANCE_FACTION 35 // friendly to everyone
|
|
#define DEFAULT_CREATURE_SPAWN_LIMIT 10
|
|
#define DEFAULT_GAMEOBJECT_SPAWN_LIMIT 50
|
|
#define ENABLE_DEFAULT_GAMOBJECT_ENTRY_LIST // a list of gameobject will be available to all players even if they did not donate
|
|
#define ENABLE_DEFAULT_CREATURE_ENTRY_LIST // a list of creatures will be available to all players even if they did not donate
|
|
|
|
void SpawnAssistant(Player *player, PersonalInstanceStore *Pi);
|
|
|
|
uint32 PersonalInstanceStore::GetInstanceID(uint32 MapId)
|
|
{
|
|
int RetID;
|
|
if (InstanceIDs.find(MapId) == InstanceIDs.end())
|
|
{
|
|
RetID = sMapMgr->GenerateInstanceId();
|
|
InstanceIDs[MapId] = RetID;
|
|
}
|
|
else
|
|
{
|
|
RetID = InstanceIDs[MapId];
|
|
}
|
|
return RetID;
|
|
}
|
|
|
|
bool PersonalInstanceStore::CanAccesMap(uint32 MapId)
|
|
{
|
|
return AllowedMaps.find(MapId) != AllowedMaps.end();
|
|
}
|
|
|
|
PersonalInstanceStore::PersonalInstanceStore(Player *player)
|
|
{
|
|
PlayerGUID = player->GetGUID().GetRawValue();
|
|
CreatureLimit = DEFAULT_CREATURE_SPAWN_LIMIT;
|
|
GameobjectLimit = DEFAULT_GAMEOBJECT_SPAWN_LIMIT;
|
|
EnteredMapFrom = player->GetWorldLocation(); // avoid uninitialized values
|
|
LoadFromDB(player);
|
|
}
|
|
|
|
PersonalInstanceStore::~PersonalInstanceStore()
|
|
{
|
|
std::list<PersonalSpawnStore*>::iterator it;
|
|
for (it = MapSpawns.begin(); it != MapSpawns.end(); it++)
|
|
delete *it;
|
|
MapSpawns.clear();
|
|
}
|
|
|
|
void PersonalInstanceStore::LoadFromDB(Player *player)
|
|
{
|
|
//load settings
|
|
char Query[5000];
|
|
sprintf_s(Query, sizeof(Query), "Select CreatureLimit,GameobjectLimit from account_PersonalMapSettings where AcctId=%d", (uint32)PlayerGUID);
|
|
QueryResult result = CharacterDatabase.Query(Query);
|
|
if (result)
|
|
{
|
|
Field* fields = result->Fetch();
|
|
CreatureLimit = DEFAULT_CREATURE_SPAWN_LIMIT + fields[0].GetUInt32();
|
|
GameobjectLimit = DEFAULT_GAMEOBJECT_SPAWN_LIMIT + fields[1].GetUInt32();
|
|
}
|
|
|
|
//load allowed maps from DB
|
|
sprintf_s(Query, sizeof(Query), "Select MapId from account_PersonalMaps where AcctId=%d", (uint32)player->GetSession()->GetAccountId());
|
|
QueryResult result2 = CharacterDatabase.Query(Query);
|
|
if (result2)
|
|
{
|
|
do {
|
|
Field* fields = result2->Fetch();
|
|
uint32 MapId = fields[0].GetUInt32();
|
|
AllowedMaps.insert(MapId);
|
|
} while (result2->NextRow());
|
|
}
|
|
|
|
//in case this is a new account. By default we will allow them to use these maps
|
|
#ifdef DEFAULT_PERSONAL_INSTANCE_MAP
|
|
AllowedMaps.insert(615);
|
|
AllowedMaps.insert(ENDURANCE_MAP);
|
|
#endif
|
|
|
|
//load what kinda spawns can we use
|
|
sprintf_s(Query, sizeof(Query), "Select SpawnType,SpawnEntry from account_PersonalMapAllowedEntries where AcctId=%d", (uint32)player->GetSession()->GetAccountId());
|
|
QueryResult result3 = CharacterDatabase.Query(Query);
|
|
if (result3)
|
|
{
|
|
do {
|
|
Field* fields = result3->Fetch();
|
|
uint32 SpawnType = fields[0].GetUInt32();
|
|
uint32 SpawnEntry = fields[1].GetUInt32();
|
|
if (SpawnType == 0)
|
|
AllowedCreatures.insert(SpawnEntry);
|
|
else
|
|
AllowedGameObjects.insert(SpawnEntry);
|
|
} while (result3->NextRow());
|
|
}
|
|
|
|
#ifdef ENABLE_DEFAULT_GAMOBJECT_ENTRY_LIST
|
|
//Normal Players default spawns
|
|
//Chairs
|
|
AllowedGameObjects.insert(22713); //Wooden Chair 1
|
|
AllowedGameObjects.insert(2489); //High Back Chair
|
|
AllowedGameObjects.insert(28611); //Dwarven High Back Chair
|
|
AllowedGameObjects.insert(186715); //Wooden Bench
|
|
AllowedGameObjects.insert(174698); //Stone Bench
|
|
AllowedGameObjects.insert(136929); //Stone Throne 1
|
|
AllowedGameObjects.insert(142947); //Stone Throne 2
|
|
AllowedGameObjects.insert(191244); //Wood Bench X
|
|
AllowedGameObjects.insert(191886); //small weird chair
|
|
//Tables
|
|
AllowedGameObjects.insert(177724); // Dredan's Table (Simple Wood)
|
|
AllowedGameObjects.insert(183994); //Amadi Table (Wood taller)
|
|
AllowedGameObjects.insert(180885); //Inn Table
|
|
AllowedGameObjects.insert(180698); //Party Table
|
|
AllowedGameObjects.insert(180884); //DwarvenTableSmall
|
|
AllowedGameObjects.insert(183105); //Orc Table
|
|
AllowedGameObjects.insert(184657); //Ironridge Table
|
|
//Banners
|
|
AllowedGameObjects.insert(180773); // Banner
|
|
|
|
//Donators Only by Rank
|
|
if (player->GetSession())
|
|
{
|
|
uint32 rank = AccountMgr::GetSecurity(player->GetSession()->GetAccountId(), 1); //1 is RealmId
|
|
if (rank = SEC_BRONZE)
|
|
{
|
|
//chairs
|
|
AllowedGameObjects.insert(184732); //Chair with small tables X
|
|
AllowedGameObjects.insert(184733); //Prev as Set X
|
|
AllowedGameObjects.insert(178934); //The chair X
|
|
//tables
|
|
AllowedGameObjects.insert(182093); //Blood Elf Table - Small
|
|
AllowedGameObjects.insert(180879); //ElvenWoodenTable
|
|
}
|
|
if (rank = SEC_SILVER)
|
|
{
|
|
//chairs
|
|
AllowedGameObjects.insert(112068); //Festive Red Chair X
|
|
AllowedGameObjects.insert(182654); //Red Royal X
|
|
//tables
|
|
AllowedGameObjects.insert(189289); //Long Table set 1
|
|
AllowedGameObjects.insert(190190); //Long Table set 2
|
|
}
|
|
if (rank = SEC_GOLD)
|
|
{
|
|
//chairs
|
|
AllowedGameObjects.insert(182598); //Blue Royal 1 X
|
|
AllowedGameObjects.insert(184671); //Blue Royal 2 X
|
|
//tables
|
|
AllowedGameObjects.insert(195191); //Dwarven Table Simple 05 (Zen)
|
|
AllowedGameObjects.insert(193701); //Doodad_gnometable01 (Fine)
|
|
}
|
|
if (rank = SEC_PLATINUM)
|
|
{
|
|
//chairs
|
|
AllowedGameObjects.insert(182762); //Black Royal X
|
|
AllowedGameObjects.insert(183753); //Imperial X
|
|
AllowedGameObjects.insert(186695); //Imperial High X
|
|
//tables
|
|
AllowedGameObjects.insert(190689); //Apothecary Table, Round
|
|
AllowedGameObjects.insert(191785); //Horde Table (circle flat with horns)
|
|
}
|
|
if (rank = SEC_DIAMOND)
|
|
{
|
|
//chairs
|
|
AllowedGameObjects.insert(192010); //Yellow X
|
|
AllowedGameObjects.insert(191475); //Futurist X
|
|
AllowedGameObjects.insert(190683); //Barbershop Chair (HIGH DONATION) X
|
|
//tables
|
|
AllowedGameObjects.insert(180324); //Dwarven Table Ornate 01
|
|
AllowedGameObjects.insert(187114); //Alchemy Table (Lux design)
|
|
AllowedGameObjects.insert(184949); //Doctor's Alchemy Table
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//load spawns
|
|
sprintf_s(Query, sizeof(Query), "SELECT MapId,x,y,z,o,entry,spawntype FROM account_PersonalMapSpawns where AcctId=%d", (uint32)player->GetSession()->GetAccountId());
|
|
QueryResult result4 = CharacterDatabase.Query(Query);
|
|
if (result4)
|
|
{
|
|
do {
|
|
Field* fields = result4->Fetch();
|
|
PersonalSpawnStore *ps = new PersonalSpawnStore;
|
|
ps->MapId = fields[0].GetUInt32();
|
|
ps->pos = Position(fields[1].GetFloat(), fields[2].GetFloat(), fields[3].GetFloat(), fields[4].GetFloat());
|
|
ps->Entry = fields[5].GetUInt32();
|
|
ps->SpawnType = fields[6].GetUInt32();
|
|
|
|
MapSpawns.push_back(ps);
|
|
} while (result4->NextRow());
|
|
}
|
|
#ifdef ENABLE_DEFAULT_CREATURE_ENTRY_LIST
|
|
AllowedCreatures.insert(123456); //Taxi
|
|
#endif
|
|
}
|
|
|
|
Map *PersonalInstanceStore::GetPersonalMap(uint32 MapId, bool CreateNew)
|
|
{
|
|
bool IsNew = false;
|
|
|
|
// do we have an active instance already ? Fetch that
|
|
uint32 InstanceIdForMap = GetInstanceID(MapId);
|
|
|
|
// get our personal instance ID for this map type
|
|
if (InstanceIdForMap == 0)
|
|
{
|
|
if (DEBUG_PERSONAL_INSTANCE) printf("Error. Could not obtain instance ID to use for this map\n");
|
|
return NULL;
|
|
}
|
|
// Get the base map that has a list of instances
|
|
Map *m = sMapMgr->CreateBaseMap(MapId);
|
|
if (!m)
|
|
{
|
|
if (DEBUG_PERSONAL_INSTANCE) printf("Failed to create/obtain base map");
|
|
return NULL;
|
|
}
|
|
|
|
//unique maps can not have instances
|
|
if (m->Instanceable() == false)
|
|
{
|
|
return m;
|
|
}
|
|
|
|
// check if we already have our personal map instantiated
|
|
Map *map = ((MapInstanced*)m)->FindInstanceMap(InstanceIdForMap);
|
|
//if not, create a new one
|
|
if (!map)
|
|
{
|
|
if (CreateNew == true)
|
|
{
|
|
map = ((MapInstanced*)m)->CreateInstance(InstanceIdForMap, nullptr, Difficulty::REGULAR_DIFFICULTY);
|
|
IsNew = true;
|
|
// printf("Could not find existing map. Created a new one\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (DEBUG_PERSONAL_INSTANCE) printf("Found existing map. Will try to enter that\n");
|
|
// if (map->GetExtension<int64>(OE_MAP_IS_CUSTOM_INSTANCE))
|
|
// printf("The reused map is a custom instance map\n");
|
|
}
|
|
|
|
// make sure this map does not load default spawns on it
|
|
if (map && IsNew == true)
|
|
{
|
|
map->GetCreateIn64Extension(OE_MAP_IS_CUSTOM_INSTANCE, false, InstanceIdForMap);
|
|
map->GetCreateIn64Extension(OE_MAP_IS_CUSTOM_INSTANCE_CREATOR, false, PlayerGUID);
|
|
}
|
|
|
|
return map;
|
|
}
|
|
|
|
void PersonalInstanceStore::TeleportPlayerToPersonalInstance(Player *player, uint32 MapId)
|
|
{
|
|
// teleport player inside the instance
|
|
const AreaTrigger *areaTrigger = sObjectMgr->GetMapEntranceTrigger(MapId);
|
|
if (areaTrigger == NULL)
|
|
{
|
|
player->BroadcastMessage("Could not find the entrance to the instance");
|
|
return;
|
|
}
|
|
|
|
//if this is not a personal map. Remember the location where we go back
|
|
if (player->GetMap()->GetExtension<int64>(OE_MAP_IS_CUSTOM_INSTANCE) == NULL)
|
|
{
|
|
EnteredMapFrom = player->GetWorldLocation();
|
|
}
|
|
|
|
//force player to change map to this newly created one
|
|
if (player->TeleportTo(MapId, areaTrigger->target_X, areaTrigger->target_Y, areaTrigger->target_Z, areaTrigger->target_Orientation) == false)
|
|
{
|
|
player->BroadcastMessage("Could not teleport to the instance");
|
|
return;
|
|
}
|
|
|
|
//make sure we will join a personal instance on next "enter map"
|
|
QueuePersonalInstanceNextTeleport(player, MapId);
|
|
}
|
|
|
|
void PersonalInstanceStore::BindToPersonalInstance(Player *player, Map *map)
|
|
{
|
|
uint32 MapId = map->GetId();
|
|
uint32 InstanceId = map->GetInstanceId();
|
|
InstanceIDs[MapId] = InstanceId;
|
|
//bind player to this map
|
|
InstancePlayerBind* playerBind = player->GetBoundInstance(MapId, Difficulty::DUNGEON_DIFFICULTY_NORMAL);
|
|
//get rid of the old bind
|
|
if (playerBind != NULL)
|
|
player->UnbindInstance(MapId, Difficulty::DUNGEON_DIFFICULTY_NORMAL);
|
|
//get the save to this map
|
|
InstanceSave* mapSave = sInstanceSaveMgr->GetInstanceSave(InstanceId);
|
|
if (!mapSave)
|
|
mapSave = sInstanceSaveMgr->AddInstanceSave(MapId, InstanceId, Difficulty::DUNGEON_DIFFICULTY_NORMAL, 0, true, false);
|
|
//bind to this save
|
|
if (playerBind == NULL || playerBind->save != mapSave)
|
|
player->BindToInstance(mapSave, false);
|
|
}
|
|
|
|
//have to find out how to force a player to enter a specific instance
|
|
void PersonalInstanceStore::QueuePersonalInstanceNextTeleport(Player *player, uint32 MapId)
|
|
{
|
|
//get the map of the personal instance
|
|
Map *map = GetPersonalMap(MapId);
|
|
if (!map)
|
|
{
|
|
if (DEBUG_PERSONAL_INSTANCE) printf("Failed to create new map instance\n");
|
|
player->BroadcastMessage("Failed to create instance");
|
|
return;
|
|
}
|
|
QueuePersonalInstanceNextTeleport(player, map);
|
|
}
|
|
|
|
void PersonalInstanceStore::QueuePersonalInstanceNextTeleport(Player *player, Map *map)
|
|
{
|
|
if (map == NULL)
|
|
return;
|
|
//force the player to join this specific map on the next teleport. Yuck. There has gotto be a better way to do this
|
|
ScriptQueuedMapJoin *QI = player->GetCreateExtension<ScriptQueuedMapJoin>(OE_PLAYER_QUEUE_JOIN_SPECIFIC_INSTANCE);
|
|
QI->MapId = map->GetId();
|
|
QI->InstanceId = map->GetInstanceId();
|
|
|
|
//bind it to this new instance
|
|
BindToPersonalInstance(player, map);
|
|
}
|
|
|
|
void SpawnAssistantFollowing(Player *player);
|
|
void PersonalInstanceStore::SpawnObjectsOnMap(Player *player)
|
|
{
|
|
Map *m = player->GetMap();
|
|
uint32 MapId = m->GetId();
|
|
if (m->GetExtension<int64>(OE_MAP_IS_CUSTOM_INSTANCE_CREATURE_SPAWNS) == NULL)
|
|
{
|
|
int64 *CreaturesSpawend = m->GetCreateIn64Extension(OE_MAP_IS_CUSTOM_INSTANCE_CREATURE_SPAWNS);
|
|
int64 *GameobjectsSpawend = m->GetCreateIn64Extension(OE_MAP_IS_CUSTOM_INSTANCE_GAMEOBJECT_SPAWNS);
|
|
std::list<PersonalSpawnStore*>::iterator it;
|
|
for (it = MapSpawns.begin(); it != MapSpawns.end(); it++)
|
|
if ((*it)->MapId == MapId)
|
|
{
|
|
if ((*it)->SpawnType == SPAWN_TYPE_CREATURE)
|
|
{
|
|
SpawnCreature(player, (*it)->Entry, &(*it)->pos, true);
|
|
}
|
|
else if ((*it)->SpawnType == SPAWN_TYPE_GAMEOBJECT)
|
|
{
|
|
if (MapId == ENDURANCE_MAP) //don't spawn objects on Endurance map
|
|
return;
|
|
//create a new gameobject spawn
|
|
SpawnGameObject(player, (*it)->Entry, &(*it)->pos, true);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
if (DEBUG_PERSONAL_INSTANCE) printf("Map should already have spawns. Skipping respawning\n");
|
|
|
|
if (MapId == ENDURANCE_MAP) //spawn Assistant only on Endurance map
|
|
SpawnAssistant(player, this);
|
|
else
|
|
SpawnAssistantFollowing(player);
|
|
}
|
|
|
|
bool PersonalInstanceStore::InitMapRetry(Player *player)
|
|
{
|
|
//not yet time to initialize
|
|
if (GameTime::GetGameTimeMS() < MapInitStartStamp)
|
|
return false;
|
|
|
|
//already initialized
|
|
if (MapInitStartStamp == 0)
|
|
return true;
|
|
|
|
//no more need to initialize map
|
|
MapInitStartStamp = 0;
|
|
|
|
// it's time to spawn stuff
|
|
SpawnObjectsOnMap(player);
|
|
|
|
return true;
|
|
}
|
|
|
|
void DelayMapInit(void *p, void *)
|
|
{
|
|
Player *player = (Player*)p;
|
|
//not ingame yet ? Kicked out ?
|
|
if (player->FindMap() == NULL)
|
|
return;
|
|
//not ingame yet ? Kicked out ?
|
|
if (player->GetMap()->GetExtension<int64>(OE_MAP_IS_CUSTOM_INSTANCE) == NULL)
|
|
return;
|
|
PersonalInstanceStore *pi = player->GetExtension<PersonalInstanceStore>(OE_PLAYER_CUSTOM_INSTANCE_STORE);
|
|
//not ingame yet ? Kicked out ?
|
|
if (pi == NULL)
|
|
return;
|
|
//could not initialize yet
|
|
if (pi->InitMapRetry(player) == false)
|
|
return;
|
|
//must be the last thing we do. This suicides self
|
|
player->UnRegisterCallbackFunc(CALLBACK_TYPE_PLAYER_PERIODIC_TICK, DelayMapInit);
|
|
}
|
|
|
|
void PersonalInstanceStore::OnMapChanged(Player *player)
|
|
{
|
|
player->RegisterCallbackFunc(CALLBACK_TYPE_PLAYER_PERIODIC_TICK, DelayMapInit);
|
|
MapInitStartStamp = GameTime::GetGameTimeMS() + 2000; // because spawning mobs right when player enters map will make some of the spawns not show
|
|
}
|
|
|
|
// spawn a creature if possible. Save it to DB
|
|
bool PersonalInstanceStore::SpawnCreature(Player *player, uint32 Entry, Position *pos, bool FromDB, bool TempSpawn)
|
|
{
|
|
if (player->FindMap() == NULL)
|
|
{
|
|
if (DEBUG_PERSONAL_INSTANCE) printf("Player is not in a map. Can't spawn now\n");
|
|
return false;
|
|
}
|
|
|
|
int64 *CreaturesSpawend = player->GetMap()->GetCreateIn64Extension(OE_MAP_IS_CUSTOM_INSTANCE_CREATURE_SPAWNS);
|
|
|
|
if (DEBUG_PERSONAL_INSTANCE) printf("Creatures spawned: %I64d Limit: %d\n", *CreaturesSpawend, CreatureLimit);
|
|
//do we have enough spawn slots to add more spawns ?
|
|
if (TempSpawn == false)
|
|
{
|
|
if (*CreaturesSpawend >= CreatureLimit)
|
|
{
|
|
if (DEBUG_PERSONAL_INSTANCE) printf("Creature spawn limit reached\n");
|
|
if (FromDB == false)
|
|
player->BroadcastMessage("You can't spawn more creatures");
|
|
return false;
|
|
}
|
|
|
|
//are we allowed to spawn this creature ?
|
|
if (HasCreatureEntry(Entry) == false)
|
|
{
|
|
if (DEBUG_PERSONAL_INSTANCE) printf("Creature is not added to account\n");
|
|
if (FromDB == false)
|
|
player->BroadcastMessage("You do not have this creature in your spawn list");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//create a new creature spawn
|
|
Creature* creature = new Creature();
|
|
if (DEBUG_PERSONAL_INSTANCE) printf("Create creature %s\n", creature->GetName().c_str());
|
|
if (!creature->Create(player->GetMap()->GenerateLowGuid<HighGuid::Unit>(), player->GetMap(), player->GetPhaseMaskForSpawn(), Entry, *pos, NULL, 0, true))
|
|
{
|
|
delete creature;
|
|
if (DEBUG_PERSONAL_INSTANCE) printf("Could not create creature\n");
|
|
if (FromDB == false)
|
|
player->BroadcastMessage("Could not create creature");
|
|
return false;
|
|
}
|
|
|
|
//make sure he is friendly to everyone
|
|
creature->SetFaction(PERSONAL_INSTANCE_FACTION);
|
|
|
|
//mark him we are he's owner
|
|
creature->SetGuidValue(OBJECT_FIELD_CREATED_BY, player->GetGUID());
|
|
|
|
//remove any AI it may have
|
|
creature->SetAI(NULL);
|
|
|
|
//pimp their health hard
|
|
creature->SetMaxHealth(0x07FFFFFF);
|
|
creature->SetHealth(0x07FFFFFF);
|
|
|
|
//try tp push it to the map
|
|
if (!player->GetMap()->AddToMap(creature))
|
|
{
|
|
delete creature;
|
|
if (DEBUG_PERSONAL_INSTANCE) printf("Could not add creature to the map\n");
|
|
if (FromDB == false)
|
|
player->BroadcastMessage("Could not add creature to the map");
|
|
return false;
|
|
}
|
|
|
|
creature->SetHomePosition(creature->GetPosition());
|
|
|
|
if (TempSpawn == false)
|
|
{
|
|
//note down the number of spawns we have
|
|
*CreaturesSpawend += 1;
|
|
|
|
//save creature to the DB
|
|
if (FromDB == false)
|
|
{
|
|
PersonalSpawnStore *sp = new PersonalSpawnStore;
|
|
sp->Entry = Entry;
|
|
sp->MapId = player->GetMap()->GetId();
|
|
sp->SpawnType = SPAWN_TYPE_CREATURE;
|
|
sp->pos = *pos;
|
|
|
|
//real db save
|
|
SaveSpawnToDB(player, sp);
|
|
|
|
//also add to local spawn list in case the player resets it's instance
|
|
MapSpawns.push_back(sp);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// delete an already spawned creature. From DB also
|
|
void PersonalInstanceStore::DeleteCreature(Player *player, Creature *spawn)
|
|
{
|
|
//sanity checks
|
|
if (player == NULL || player->GetMap() == NULL || spawn == NULL)
|
|
{
|
|
if (DEBUG_PERSONAL_INSTANCE) printf("Sanity check failed. Exiting \n");
|
|
return;
|
|
}
|
|
//make sure he is our spawn
|
|
if (spawn->GetGuidValue(OBJECT_FIELD_CREATED_BY) != player->GetGUID())
|
|
{
|
|
if (DEBUG_PERSONAL_INSTANCE) printf("Creature belongs to another player\n");
|
|
player->BroadcastMessage("Creature belongs to another player");
|
|
return;
|
|
}
|
|
//find it in our list of spawns
|
|
std::list<PersonalSpawnStore*>::iterator it;
|
|
PersonalSpawnStore *ps = NULL;
|
|
for (it = MapSpawns.begin(); it != MapSpawns.end(); it++)
|
|
if ((*it)->pos == spawn->GetHomePosition() && (*it)->Entry == spawn->GetEntry())
|
|
{
|
|
ps = *it;
|
|
break;
|
|
}
|
|
if (it == MapSpawns.end() || ps == NULL)
|
|
{
|
|
if (DEBUG_PERSONAL_INSTANCE) printf("Could not find spawn in spawn list\n");
|
|
player->BroadcastMessage("Creature belongs to another player");
|
|
return;
|
|
}
|
|
|
|
//delete from list
|
|
MapSpawns.remove(ps);
|
|
|
|
//delete from DB
|
|
DeleteSpawnFromDB(player, ps);
|
|
|
|
//delete object
|
|
delete ps;
|
|
|
|
//remove from world
|
|
spawn->AddObjectToRemoveList();
|
|
}
|
|
|
|
// spawn a gameobject if possible. Save it to DB
|
|
Object *PersonalInstanceStore::SpawnGameObject(Player *player, uint32 Entry, Position *pos, bool FromDB)
|
|
{
|
|
if (player->FindMap() == NULL)
|
|
{
|
|
if (DEBUG_PERSONAL_INSTANCE) printf("Player is not in a map. Can't spawn now\n");
|
|
return NULL;
|
|
}
|
|
|
|
if (player->GetMap()->GetId() == ENDURANCE_MAP) //Skip on Endurance
|
|
return NULL;
|
|
|
|
int64 *GOsSpawend = player->GetMap()->GetCreateIn64Extension(OE_MAP_IS_CUSTOM_INSTANCE_GAMEOBJECT_SPAWNS);
|
|
|
|
//do we have enough spawn slots to add more spawns ?
|
|
if (*GOsSpawend >= GameobjectLimit)
|
|
{
|
|
if (DEBUG_PERSONAL_INSTANCE) printf("gameobjects spawn limit reached\n");
|
|
if (FromDB == false)
|
|
player->BroadcastMessage("You can't spawn more gameobjects");
|
|
return NULL;
|
|
}
|
|
|
|
//are we allowed to spawn this creature ?
|
|
if (HasGameObjectEntry(Entry) == false)
|
|
{
|
|
if (DEBUG_PERSONAL_INSTANCE) printf("gameobjects is not added to account\n");
|
|
if (FromDB == false)
|
|
player->BroadcastMessage("You do not have this gameobjects in your spawn list");
|
|
return NULL;
|
|
}
|
|
|
|
GameObjectTemplate const* objectInfo = sObjectMgr->GetGameObjectTemplate(Entry);
|
|
if (objectInfo == NULL)
|
|
{
|
|
if (DEBUG_PERSONAL_INSTANCE) printf("gameobject template does not exist\n");
|
|
if (FromDB == false)
|
|
player->BroadcastMessage("Gameobject template does not exist");
|
|
return NULL;
|
|
}
|
|
GameObject* object = new GameObject();
|
|
ObjectGuid::LowType guidLow = player->GetMap()->GenerateLowGuid<HighGuid::GameObject>();
|
|
|
|
QuaternionData rot = QuaternionData::fromEulerAnglesZYX(pos->GetOrientation(), 0.f, 0.f);
|
|
if (!object->Create(guidLow, Entry, player->GetMap(), player->GetPhaseMaskForSpawn(), *pos, rot, 255, GO_STATE_READY))
|
|
{
|
|
delete object;
|
|
return NULL;
|
|
}
|
|
|
|
//note down the number of spawns we have
|
|
*GOsSpawend += 1;
|
|
|
|
//save creature to the DB
|
|
if (FromDB == false)
|
|
{
|
|
PersonalSpawnStore *sp = new PersonalSpawnStore;
|
|
sp->Entry = Entry;
|
|
sp->MapId = player->GetMap()->GetId();
|
|
sp->SpawnType = SPAWN_TYPE_GAMEOBJECT;
|
|
sp->pos = *pos;
|
|
|
|
//real db save
|
|
SaveSpawnToDB(player, sp);
|
|
|
|
//also add to local spawn list in case the player resets it's instance
|
|
MapSpawns.push_back(sp);
|
|
}
|
|
|
|
//try tp push it to the map
|
|
if (!player->GetMap()->AddToMap(object))
|
|
{
|
|
delete object;
|
|
if (DEBUG_PERSONAL_INSTANCE) printf("Could not add Gameobject to the map\n");
|
|
if (FromDB == false)
|
|
player->BroadcastMessage("Could not add Gameobject to the map");
|
|
return NULL;
|
|
}
|
|
|
|
//mark him we are he's owner
|
|
object->SetGuidValue(OBJECT_FIELD_CREATED_BY, player->GetGUID());
|
|
|
|
return object;
|
|
}
|
|
|
|
// delete an already spawned gameobject. From DB also
|
|
void PersonalInstanceStore::DeleteGameObject(Player *player, GameObject *spawn)
|
|
{
|
|
//sanity checks
|
|
if (player == NULL || player->GetMap() == NULL || spawn == NULL)
|
|
{
|
|
if (DEBUG_PERSONAL_INSTANCE) printf("Sanity check failed. Exiting \n");
|
|
return;
|
|
}
|
|
|
|
if (player->GetMap()->GetId() == ENDURANCE_MAP) //Skip on Endurance, just to be safe, should not happen
|
|
return;
|
|
|
|
//make sure he is our spawn
|
|
if (spawn->GetOwnerGUID() != player->GetGUID())
|
|
{
|
|
if (DEBUG_PERSONAL_INSTANCE) printf("GameObject belongs to another player\n");
|
|
player->BroadcastMessage("GameObject belongs to another player");
|
|
return;
|
|
}
|
|
//find it in our list of spawns
|
|
std::list<PersonalSpawnStore*>::iterator it;
|
|
PersonalSpawnStore *ps = NULL;
|
|
for (it = MapSpawns.begin(); it != MapSpawns.end(); it++)
|
|
if ((*it)->pos == spawn->GetPosition() && (*it)->Entry == spawn->GetEntry())
|
|
{
|
|
ps = *it;
|
|
break;
|
|
}
|
|
if (it == MapSpawns.end() || ps == NULL)
|
|
{
|
|
if (DEBUG_PERSONAL_INSTANCE) printf("Could not find spawn in spawn list\n");
|
|
player->BroadcastMessage("GameObject belongs to another player");
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
//delete from list
|
|
MapSpawns.remove(ps);
|
|
}
|
|
|
|
//delete from DB
|
|
DeleteSpawnFromDB(player, ps);
|
|
|
|
//delete object
|
|
delete ps;
|
|
|
|
//remove from world
|
|
spawn->AddObjectToRemoveList();
|
|
}
|
|
|
|
// save a spawn to the DB
|
|
void PersonalInstanceStore::SaveSpawnToDB(Player *player, PersonalSpawnStore *sp)
|
|
{
|
|
char Query[5000];
|
|
sprintf_s(Query, sizeof(Query), "INSERT into account_PersonalMapSpawns (AcctId,MapId,x,y,z,o,entry,spawntype) values (%d,%d,%f,%f,%f,%f,%d,%d)",
|
|
player->GetSession()->GetAccountId(), sp->MapId, sp->pos.GetPositionX(), sp->pos.GetPositionY(), sp->pos.GetPositionZ(), sp->pos.GetOrientation(), sp->Entry, sp->SpawnType);
|
|
CharacterDatabase.Execute(Query);
|
|
}
|
|
|
|
void PersonalInstanceStore::DeleteSpawnFromDB(Player *player, PersonalSpawnStore *sp)
|
|
{
|
|
char Query[5000];
|
|
sprintf_s(Query, sizeof(Query), "Delete from account_PersonalMapSpawns where AcctId=%d and MapId=%d and ABS(x-%f)<0.1 and ABS(y-%f)<0.1 and ABS(z-%f)<0.1 and ABS(o-%f)<0.1 and entry=%d and spawntype=%d",
|
|
player->GetSession()->GetAccountId(), sp->MapId, sp->pos.GetPositionX(), sp->pos.GetPositionY(), sp->pos.GetPositionZ(), sp->pos.GetOrientation(), sp->Entry, sp->SpawnType);
|
|
CharacterDatabase.Execute(Query);
|
|
}
|