/* EQEMu: Everquest Server Emulator Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.net) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY except by those people which sell it, which are required to give you total support for your newly bought product; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "../common/debug.h" #include #include #include #include #include #include using namespace std; #ifdef _WINDOWS #include #else #include #include "../common/unix.h" #endif #include "net.h" #include "masterentity.h" #include "worldserver.h" #include "PlayerCorpse.h" #include "../common/guilds.h" #include "../common/packet_dump.h" #include "../common/packet_functions.h" #include "petitions.h" #include "../common/spdat.h" #include "../common/features.h" #include "StringIDs.h" #include "parser.h" #include "../common/dbasync.h" #include "guild_mgr.h" #include "raids.h" #include "QuestParserCollection.h" #ifdef _WINDOWS #define snprintf _snprintf #if (_MSC_VER < 1500) #define vsnprintf _vsnprintf #endif #define strncasecmp _strnicmp #define strcasecmp _stricmp #endif extern Zone* zone; extern volatile bool ZoneLoaded; extern WorldServer worldserver; extern NetConnection net; extern uint32 numclients; extern PetitionList petition_list; extern DBAsync *dbasync; extern char errorname[32]; extern uint16 adverrornum; Entity::Entity() { id = 0; pDBAsyncWorkID = 0; } Entity::~Entity() { dbasync->CancelWork(pDBAsyncWorkID); } void Entity::SetID(uint16 set_id) { id = set_id; } Client* Entity::CastToClient() { if(this==0x00){ cout << "CastToClient error (NULL)" << endl; DebugBreak(); return 0; } #ifdef _EQDEBUG if(!IsClient()) { cout << "CastToClient error (not client?)" << endl; DebugBreak(); return 0; } #endif return static_cast(this); } NPC* Entity::CastToNPC() { #ifdef _EQDEBUG if(!IsNPC()) { cout << "CastToNPC error" << endl; DebugBreak(); return 0; } #endif return static_cast(this); } Mob* Entity::CastToMob() { #ifdef _EQDEBUG if(!IsMob()) { cout << "CastToMob error" << endl; DebugBreak(); return 0; } #endif return static_cast(this); } Merc* Entity::CastToMerc() { #ifdef _EQDEBUG if(!IsMerc()) { cout << "CastToMerc error" << endl; DebugBreak(); return 0; } #endif return static_cast(this); } Trap* Entity::CastToTrap() { #ifdef DEBUG if(!IsTrap()) { //cout << "CastToTrap error" << endl; return 0; } #endif return static_cast(this); } Corpse* Entity::CastToCorpse() { #ifdef _EQDEBUG if(!IsCorpse()) { cout << "CastToCorpse error" << endl; DebugBreak(); return 0; } #endif return static_cast(this); } Object* Entity::CastToObject() { #ifdef _EQDEBUG if(!IsObject()) { cout << "CastToObject error" << endl; DebugBreak(); return 0; } #endif return static_cast(this); } /*Group* Entity::CastToGroup() { #ifdef _EQDEBUG if(!IsGroup()) { cout << "CastToGroup error" << endl; DebugBreak(); return 0; } #endif return static_cast(this); }*/ Doors* Entity::CastToDoors() { return static_cast(this); } Beacon* Entity::CastToBeacon() { return static_cast(this); } const Client* Entity::CastToClient() const { if(this==0x00){ cout << "CastToClient error (NULL)" << endl; DebugBreak(); return 0; } #ifdef _EQDEBUG if(!IsClient()) { cout << "CastToClient error (not client?)" << endl; DebugBreak(); return 0; } #endif return static_cast(this); } const NPC* Entity::CastToNPC() const { #ifdef _EQDEBUG if(!IsNPC()) { cout << "CastToNPC error" << endl; DebugBreak(); return 0; } #endif return static_cast(this); } const Mob* Entity::CastToMob() const { #ifdef _EQDEBUG if(!IsMob()) { cout << "CastToMob error" << endl; DebugBreak(); return 0; } #endif return static_cast(this); } const Merc* Entity::CastToMerc() const { #ifdef _EQDEBUG if(!IsMerc()) { cout << "CastToMerc error" << endl; DebugBreak(); return 0; } #endif return static_cast(this); } const Trap* Entity::CastToTrap() const { #ifdef DEBUG if(!IsTrap()) { //cout << "CastToTrap error" << endl; return 0; } #endif return static_cast(this); } const Corpse* Entity::CastToCorpse() const { #ifdef _EQDEBUG if(!IsCorpse()) { cout << "CastToCorpse error" << endl; DebugBreak(); return 0; } #endif return static_cast(this); } const Object* Entity::CastToObject() const { #ifdef _EQDEBUG if(!IsObject()) { cout << "CastToObject error" << endl; DebugBreak(); return 0; } #endif return static_cast(this); } const Doors* Entity::CastToDoors() const { return static_cast(this); } const Beacon* Entity::CastToBeacon() const { return static_cast(this); } #ifdef BOTS Bot* Entity::CastToBot() { #ifdef _EQDEBUG if(!IsBot()) { cout << "CastToBot error" << endl; DebugBreak(); return 0; } #endif return static_cast(this); } #endif EntityList::EntityList() { last_insert_id = 0; } EntityList::~EntityList() { //must call this before the list is destroyed, or else it will try to //delete the NPCs in the list, which it cannot do. RemoveAllLocalities(); } bool EntityList::CanAddHateForMob(Mob *p) { LinkedListIterator iterator(npc_list); int count = 0; iterator.Reset(); while( iterator.MoreElements()) { NPC *npc=iterator.GetData(); if (npc->IsOnHatelist(p)) count++; // no need to continue if we already hit the limit if (count > 3) return false; iterator.Advance(); } if (count <= 2) return true; return false; } void EntityList::AddClient(Client* client) { client->SetID(GetFreeID()); client_list.Insert(client); mob_list.Insert(client); if(!client_list.dont_delete) client_list.dont_delete=true; } void EntityList::TrapProcess() { if(numclients < 1) return; _ZP(EntityList_TrapProcess); LinkedListIterator iterator(trap_list); iterator.Reset(); uint32 count=0; while(iterator.MoreElements()) { count++; if(!iterator.GetData()->Process()){ iterator.RemoveCurrent(); } else iterator.Advance(); } if(count==0) net.trap_timer.Disable();//No traps in list, disable until one is added } // Debug function -- checks to see if group_list has any NULL entries. // Meant to be called after each group-related function, in order // to track down bugs. void EntityList::CheckGroupList (const char *fname, const int fline) { list::iterator it; for (it = group_list.begin(); it != group_list.end(); it++) { if (*it == NULL) { LogFile->write(EQEMuLog::Error, "NULL group, %s:%i", fname, fline); } } } void EntityList::GroupProcess() { list::iterator iterator; uint32 count = 0; if(numclients < 1) return; _ZP(EntityList_GroupProcess); iterator = group_list.begin(); while(iterator != group_list.end()) { count++; (*iterator)->Process(); /* if(!iterator.GetData()->Process()){ iterator.RemoveCurrent(); } else iterator.Advance(); */ iterator++; } if(count == 0) net.group_timer.Disable();//No groups in list, disable until one is added #if EQDEBUG >= 5 CheckGroupList (__FILE__, __LINE__); #endif } void EntityList::QueueToGroupsForNPCHealthAA(Mob* sender, const EQApplicationPacket* app) { list::iterator iterator = group_list.begin(); _ZP(EntityList_QueueToGroupsForNPCHealthAA); while(iterator != group_list.end()) { (*iterator)->QueueHPPacketsForNPCHealthAA(sender, app); iterator++; } } void EntityList::RaidProcess() { list::iterator iterator; uint32 count = 0; if(numclients < 1) return; _ZP(EntityList_RaidProcess); iterator = raid_list.begin(); while(iterator != raid_list.end()) { count++; (*iterator)->Process(); iterator++; } if(count == 0) net.raid_timer.Disable();//No groups in list, disable until one is added } void EntityList::DoorProcess() { #ifdef IDLE_WHEN_EMPTY if(numclients < 1) return; #endif _ZP(EntityList_DoorProcess); LinkedListIterator iterator(door_list); iterator.Reset(); uint32 count=0; while(iterator.MoreElements()) { count++; if(!iterator.GetData()->Process()){ iterator.RemoveCurrent(); } else iterator.Advance(); } if (count==0) net.door_timer.Disable();//No doors in list, disable until one is added } void EntityList::ObjectProcess() { _ZP(EntityList_ObjectProcess); LinkedListIterator iterator(object_list); iterator.Reset(); uint32 count=0; while(iterator.MoreElements()) { count++; if(!iterator.GetData()->Process()){ iterator.RemoveCurrent(); } else iterator.Advance(); } if(count==0) net.object_timer.Disable();//No objects in list, disable until one is added } void EntityList::CorpseProcess() { _ZP(EntityList_CorpseProcess); LinkedListIterator iterator(corpse_list); iterator.Reset(); uint32 count=0; while(iterator.MoreElements()) { count++; if(!iterator.GetData()->Process()){ iterator.RemoveCurrent(); } else iterator.Advance(); } if(count==0) net.corpse_timer.Disable();//No corpses in list, disable until one is added } void EntityList::MobProcess() { #ifdef IDLE_WHEN_EMPTY if(numclients < 1) return; #endif _ZP(EntityList_MobProcess); LinkedListIterator iterator(mob_list); iterator.Reset(); while(iterator.MoreElements()) { if(!iterator.GetData()) { iterator.Advance(); continue; } if(!iterator.GetData()->Process()){ Mob* mob=iterator.GetData(); if(mob->IsNPC()) entity_list.RemoveNPC(mob->CastToNPC()->GetID()); else if(mob->IsMerc()) { entity_list.RemoveMerc(mob->CastToMerc()->GetID()); } #ifdef BOTS else if(mob->IsBot()) { entity_list.RemoveBot(mob->CastToBot()->GetID()); } #endif else{ #ifdef _WINDOWS struct in_addr in; in.s_addr = mob->CastToClient()->GetIP(); cout << "Dropping client: Process=false, ip=" << inet_ntoa(in) << ", port=" << mob->CastToClient()->GetPort() << endl; #endif zone->StartShutdownTimer(); Group *g = GetGroupByMob(mob); if(g) { LogFile->write(EQEMuLog::Error, "About to delete a client still in a group."); g->DelMember(mob); } Raid *r = entity_list.GetRaidByClient(mob->CastToClient()); if(r) { LogFile->write(EQEMuLog::Error, "About to delete a client still in a raid."); r->MemberZoned(mob->CastToClient()); } entity_list.RemoveClient(mob->GetID()); } iterator.RemoveCurrent(); } else iterator.Advance(); } } void EntityList::BeaconProcess() { _ZP(EntityList_BeaconProcess); LinkedListIterator iterator(beacon_list); int count; for(iterator.Reset(), count = 0; iterator.MoreElements(); count++) { if(!iterator.GetData()->Process()) iterator.RemoveCurrent(); else iterator.Advance(); } } void EntityList::AddGroup(Group* group) { if(group == NULL) //this seems to be happening somehow... return; uint32 gid = worldserver.NextGroupID(); if(gid == 0) { LogFile->write(EQEMuLog::Error, "Unable to get new group ID from world server. group is going to be broken."); return; } AddGroup(group, gid); #if EQDEBUG >= 5 CheckGroupList (__FILE__, __LINE__); #endif } void EntityList::AddGroup(Group* group, uint32 gid) { group->SetID(gid); //group_list.Insert(group); group_list.push_back(group); if(!net.group_timer.Enabled()) net.group_timer.Start(); #if EQDEBUG >= 5 CheckGroupList (__FILE__, __LINE__); #endif } void EntityList::AddRaid(Raid* raid) { if(raid == NULL) return; uint32 gid = worldserver.NextGroupID(); if(gid == 0) { LogFile->write(EQEMuLog::Error, "Unable to get new group ID from world server. group is going to be broken."); return; } AddRaid(raid, gid); } void EntityList::AddRaid(Raid* raid, uint32 gid) { raid->SetID(gid); raid_list.push_back(raid); if(!net.raid_timer.Enabled()) net.raid_timer.Start(); } void EntityList::AddCorpse(Corpse* corpse, uint32 in_id) { if (corpse == 0) return; if (in_id == 0xFFFFFFFF) corpse->SetID(GetFreeID()); else corpse->SetID(in_id); corpse->CalcCorpseName(); corpse_list.Insert(corpse); if(!net.corpse_timer.Enabled()) net.corpse_timer.Start(); } void EntityList::AddNPC(NPC* npc, bool SendSpawnPacket, bool dontqueue) { npc->SetID(GetFreeID()); parse->EventNPC(EVENT_SPAWN, npc, NULL, "", 0); uint16 emoteid = npc->GetEmoteID(); if(emoteid != 0) npc->DoNPCEmote(ONSPAWN,emoteid); if (SendSpawnPacket) { if (dontqueue) { // aka, SEND IT NOW BITCH! EQApplicationPacket* app = new EQApplicationPacket; npc->CreateSpawnPacket(app,npc); QueueClients(npc, app); safe_delete(app); } else { NewSpawn_Struct* ns = new NewSpawn_Struct; memset(ns, 0, sizeof(NewSpawn_Struct)); npc->FillSpawnStruct(ns, 0); // Not working on player newspawns, so it's safe to use a ForWho of 0 AddToSpawnQueue(npc->GetID(), &ns); safe_delete(ns); } if(npc->IsFindable()) UpdateFindableNPCState(npc, false); } npc_list.Insert(npc); if(!npc_list.dont_delete) npc_list.dont_delete=true; mob_list.Insert(npc); } void EntityList::AddMerc(Merc* merc, bool SendSpawnPacket, bool dontqueue) { if(merc) { merc->SetID(GetFreeID()); if(SendSpawnPacket) { if(dontqueue) { // Send immediately EQApplicationPacket* outapp = new EQApplicationPacket(); merc->CreateSpawnPacket(outapp); outapp->priority = 6; QueueClients(merc, outapp, true); safe_delete(outapp); } else { // Queue the packet NewSpawn_Struct* ns = new NewSpawn_Struct; memset(ns, 0, sizeof(NewSpawn_Struct)); merc->FillSpawnStruct(ns, merc); AddToSpawnQueue(merc->GetID(), &ns); safe_delete(ns); } //parse->EventMERC(EVENT_SPAWN, merc, NULL, "", 0); } merc_list.Insert(merc); mob_list.Insert(merc); if(!merc_list.dont_delete) merc_list.dont_delete=true; } } void EntityList::AddObject(Object* obj, bool SendSpawnPacket) { obj->SetID(GetFreeID()); if (SendSpawnPacket) { EQApplicationPacket app; obj->CreateSpawnPacket(&app); #if (EQDEBUG >= 6) DumpPacket(&app); #endif QueueClients(0, &app,false); } object_list.Insert(obj); if(!net.object_timer.Enabled()) net.object_timer.Start(); } void EntityList::AddDoor(Doors* door) { door->SetEntityID(GetFreeID()); door_list.Insert(door); if(!net.door_timer.Enabled()) net.door_timer.Start(); } void EntityList::AddTrap(Trap* trap) { trap->SetID(GetFreeID()); trap_list.Insert(trap); if(!net.trap_timer.Enabled()) net.trap_timer.Start(); } void EntityList::AddBeacon(Beacon *beacon) { beacon->SetID(GetFreeID()); beacon_list.Insert(beacon); } void EntityList::AddToSpawnQueue(uint16 entityid, NewSpawn_Struct** ns) { uint32 count; if((count=(client_list.Count()))==0) return; SpawnQueue.Append(*ns); NumSpawnsOnQueue++; if (tsFirstSpawnOnQueue == 0xFFFFFFFF) tsFirstSpawnOnQueue = Timer::GetCurrentTime(); *ns = 0; // make it so the calling function cant fuck us and delete the data =) } void EntityList::CheckSpawnQueue() { // Send the stuff if the oldest packet on the queue is older than 50ms -Quagmire if (tsFirstSpawnOnQueue != 0xFFFFFFFF && (Timer::GetCurrentTime() - tsFirstSpawnOnQueue) > 50) { //if (NumSpawnsOnQueue <= 5) { LinkedListIterator iterator(SpawnQueue); EQApplicationPacket* outapp = 0; iterator.Reset(); while(iterator.MoreElements()) { outapp = new EQApplicationPacket; Mob::CreateSpawnPacket(outapp, iterator.GetData()); // cout << "Sending spawn packet: " << iterator.GetData()->spawn.name << endl; QueueClients(0, outapp); safe_delete(outapp); iterator.RemoveCurrent(); } //sending Spawns like this after zone in causes the client to freeze... /*} else { uint32 spawns_per_pack = MAX_SPAWNS_PER_PACKET; if(NumSpawnsOnQueue < spawns_per_pack) spawns_per_pack = NumSpawnsOnQueue; BulkZoneSpawnPacket* bzsp = new BulkZoneSpawnPacket(0, spawns_per_pack); LinkedListIterator iterator(SpawnQueue); iterator.Reset(); while(iterator.MoreElements()) { bzsp->AddSpawn(iterator.GetData()); iterator.RemoveCurrent(); } safe_delete(bzsp); }*/ tsFirstSpawnOnQueue = 0xFFFFFFFF; NumSpawnsOnQueue = 0; } } Doors* EntityList::FindDoor(uint8 door_id) { if (door_id == 0) return 0; LinkedListIterator iterator(door_list); iterator.Reset(); while(iterator.MoreElements()) { Doors* door=iterator.GetData(); if (door->GetDoorID() == door_id) { return door; } iterator.Advance(); } return 0; } Object* EntityList::FindObject(uint32 object_id) { LinkedListIterator iterator(object_list); iterator.Reset(); while(iterator.MoreElements()) { Object* object=iterator.GetData(); if (object->GetDBID() == object_id) { return object; } iterator.Advance(); } return NULL; } Object* EntityList::FindNearbyObject(float x, float y, float z, float radius) { LinkedListIterator iterator(object_list); iterator.Reset(); float ox; float oy; float oz; while(iterator.MoreElements()) { Object* object=iterator.GetData(); object->GetLocation(&ox, &oy, &oz); ox = (x < ox) ? (ox - x) : (x - ox); oy = (y < oy) ? (oy - y) : (y - oy); oz = (z < oz) ? (oz - z) : (z - oz); if ((ox <= radius) && (oy <= radius) && (oz <= radius)) { return object; } iterator.Advance(); } return NULL; } bool EntityList::MakeDoorSpawnPacket(EQApplicationPacket* app, Client *client) { uint32 mask_test = client->GetClientVersionBit(); int count = 0; LinkedListIterator iterator(door_list); iterator.Reset(); while(iterator.MoreElements()) { if((iterator.GetData()->GetClientVersionMask() & mask_test) && strlen(iterator.GetData()->GetDoorName()) > 3) { count++; } iterator.Advance(); } if(count == 0 || count > 500) { return false; } uint32 length = count * sizeof(Door_Struct); uchar* packet_buffer = new uchar[length]; memset(packet_buffer, 0, length); uchar* ptr = packet_buffer; Doors *door; Door_Struct nd; iterator.Reset(); while(iterator.MoreElements()) { door = iterator.GetData(); if(door && (door->GetClientVersionMask() & mask_test) && strlen(door->GetDoorName()) > 3) { memset(&nd, 0, sizeof(nd)); memcpy(nd.name, door->GetDoorName(), 32); nd.xPos = door->GetX(); nd.yPos = door->GetY(); nd.zPos = door->GetZ(); nd.heading = door->GetHeading(); nd.incline = door->GetIncline(); nd.size = door->GetSize(); nd.doorId = door->GetDoorID(); nd.opentype = door->GetOpenType(); nd.state_at_spawn = door->GetInvertState() ? !door->IsDoorOpen() : door->IsDoorOpen(); nd.invert_state = door->GetInvertState(); nd.door_param = door->GetDoorParam(); memcpy(ptr, &nd, sizeof(nd)); ptr+=sizeof(nd); *(ptr-1)=0x01; *(ptr-3)=0x01; } iterator.Advance(); } app->SetOpcode(OP_SpawnDoor); app->size = length; app->pBuffer = packet_buffer; return true; } Entity* EntityList::GetEntityMob(uint16 id){ LinkedListIterator iterator(mob_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->GetID() == id) { return iterator.GetData(); } iterator.Advance(); } return 0; } Entity* EntityList::GetEntityMerc(uint16 id){ LinkedListIterator iterator(merc_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->GetID() == id) { return iterator.GetData(); } iterator.Advance(); } return 0; } Entity* EntityList::GetEntityMob(const char *name) { if (name == 0) return 0; LinkedListIterator iterator(mob_list); for(iterator.Reset(); iterator.MoreElements(); iterator.Advance()) { if (strcasecmp(iterator.GetData()->GetName(), name) == 0) { return iterator.GetData(); } } return 0; } Entity* EntityList::GetEntityDoor(uint16 id){ LinkedListIterator iterator(door_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->GetID() == id) { return iterator.GetData(); } iterator.Advance(); } return 0; } Entity* EntityList::GetEntityCorpse(uint16 id){ LinkedListIterator iterator(corpse_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->GetID() == id) { return iterator.GetData(); } iterator.Advance(); } return 0; } Entity* EntityList::GetEntityCorpse(const char *name) { if (name == 0) return 0; LinkedListIterator iterator(corpse_list); for(iterator.Reset(); iterator.MoreElements(); iterator.Advance()) { if (strcasecmp(iterator.GetData()->GetName(), name) == 0) { return iterator.GetData(); } } return 0; } Entity* EntityList::GetEntityTrap(uint16 id){ LinkedListIterator iterator(trap_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->GetID() == id) { return iterator.GetData(); } iterator.Advance(); } return 0; } Entity* EntityList::GetEntityObject(uint16 id){ LinkedListIterator iterator(object_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->GetID() == id) { return iterator.GetData(); } iterator.Advance(); } return 0; } /* Entity* EntityList::GetEntityGroup(uint16 id){ LinkedListIterator iterator(group_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->GetID() == id) { return iterator.GetData(); } iterator.Advance(); } return 0; } */ Entity* EntityList::GetEntityBeacon(uint16 id) { LinkedListIterator iterator(beacon_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->GetID() == id) { return iterator.GetData(); } iterator.Advance(); } return 0; } Entity* EntityList::GetID(uint16 get_id) { Entity* ent=0; if((ent=entity_list.GetEntityMob(get_id))!=0) return ent; else if((ent=entity_list.GetEntityDoor(get_id))!=0) return ent; else if((ent=entity_list.GetEntityCorpse(get_id))!=0) return ent; // else if((ent=entity_list.GetEntityGroup(get_id))!=0) // return ent; else if((ent=entity_list.GetEntityObject(get_id))!=0) return ent; else if((ent=entity_list.GetEntityTrap(get_id))!=0) return ent; else if((ent=entity_list.GetEntityBeacon(get_id))!=0) return ent; else return 0; } NPC* EntityList::GetNPCByID(uint16 id) { LinkedListIterator iterator(npc_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()) { if (iterator.GetData()->GetID() == id) { return iterator.GetData(); } } iterator.Advance(); } return 0; } NPC* EntityList::GetNPCByNPCTypeID(uint32 npc_id) { if (npc_id == 0) return 0; LinkedListIterator iterator(npc_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->GetNPCTypeID() == npc_id) { return iterator.GetData(); } iterator.Advance(); } return 0; } Merc* EntityList::GetMercByID(uint16 id) { LinkedListIterator iterator(merc_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()) { if (iterator.GetData()->GetID() == id) { return iterator.GetData(); } } iterator.Advance(); } return 0; } Mob* EntityList::GetMob(uint16 get_id) { Entity* ent=0; if (get_id == 0) return 0; if((ent=entity_list.GetEntityMob(get_id))!=0) return ent->CastToMob(); else if((ent=entity_list.GetEntityCorpse(get_id))!=0) return ent->CastToMob(); return 0; } Mob* EntityList::GetMob(const char* name) { Entity* ent=0; if (name == 0) return 0; if((ent=entity_list.GetEntityMob(name))!=0) return ent->CastToMob(); else if((ent=entity_list.GetEntityCorpse(name))!=0) return ent->CastToMob(); return 0; } Mob* EntityList::GetMobByNpcTypeID(uint32 get_id) { if (get_id == 0) return 0; LinkedListIterator iterator(mob_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->GetNPCTypeID() == get_id) { return iterator.GetData(); } iterator.Advance(); } return 0; } Object* EntityList::GetObjectByDBID(uint32 id) { if (id == 0) return 0; LinkedListIterator iterator(object_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()) { if (iterator.GetData()->CastToObject()->GetDBID() == id) { return iterator.GetData(); } } iterator.Advance(); } return 0; } Object* EntityList::GetObjectByID(uint16 id) { if (id == 0) return 0; LinkedListIterator iterator(object_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()) { if (iterator.GetData()->CastToObject()->GetID() == id) { return iterator.GetData(); } } iterator.Advance(); } return 0; } Doors* EntityList::GetDoorsByID(uint16 id) { if (id == 0) return 0; LinkedListIterator iterator(door_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()) { if (iterator.GetData()->CastToDoors()->GetEntityID() == id) { return iterator.GetData(); } } iterator.Advance(); } return 0; } Doors* EntityList::GetDoorsByDBID(uint32 id) { if (id == 0) return 0; LinkedListIterator iterator(door_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()) { if (iterator.GetData()->CastToDoors()->GetDoorDBID() == id) { return iterator.GetData(); } } iterator.Advance(); } return 0; } Doors* EntityList::GetDoorsByDoorID(uint32 id) { if (id == 0) return 0; LinkedListIterator iterator(door_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()) { if (iterator.GetData()->CastToDoors()->GetDoorID() == id) { return iterator.GetData(); } } iterator.Advance(); } return 0; } uint16 EntityList::GetFreeID() { if(last_insert_id > 1500) last_insert_id = 0; uint16 getid=last_insert_id; while(1) { getid++; if (GetID(getid) == 0) { last_insert_id = getid; return getid; } } } // if no language skill is specified, sent with 100 skill void EntityList::ChannelMessage(Mob* from, uint8 chan_num, uint8 language, const char* message, ...) { ChannelMessage(from, chan_num, language, 100, message); } void EntityList::ChannelMessage(Mob* from, uint8 chan_num, uint8 language, uint8 lang_skill, const char* message, ...) { LinkedListIterator iterator(client_list); va_list argptr; char buffer[4096]; va_start(argptr, message); vsnprintf(buffer, 4096, message, argptr); va_end(argptr); iterator.Reset(); while(iterator.MoreElements()) { Client* client = iterator.GetData(); eqFilterType filter = FilterNone; if(chan_num==3)//shout filter=FilterShouts; else if(chan_num==4) //auction filter=FilterAuctions; if (chan_num != 8 || client->Dist(*from) < 200) // Only say is limited in range { if(filter==FilterNone || client->GetFilter(filter)!=FilterHide) client->ChannelMessageSend(from->GetName(), 0, chan_num, language, lang_skill, buffer); } iterator.Advance(); } } void EntityList::ChannelMessageSend(Mob* to, uint8 chan_num, uint8 language, const char* message, ...) { LinkedListIterator iterator(client_list); va_list argptr; char buffer[4096]; va_start(argptr, message); vsnprintf(buffer, 4096, message, argptr); va_end(argptr); iterator.Reset(); while(iterator.MoreElements()) { Client* client = iterator.GetData(); if (client->GetID() == to->GetID()) { client->ChannelMessageSend(0, 0, chan_num, language, buffer); break; } iterator.Advance(); } } void EntityList::SendZoneSpawns(Client* client) { LinkedListIterator iterator(mob_list); EQApplicationPacket* app; iterator.Reset(); while(iterator.MoreElements()) { Mob* ent = iterator.GetData(); if (!( ent->InZone() ) || (ent->IsClient())) { if(ent->CastToClient()->GMHideMe(client) || ent->CastToClient()->IsHoveringForRespawn()) { iterator.Advance(); continue; } } app = new EQApplicationPacket; iterator.GetData()->CastToMob()->CreateSpawnPacket(app); // TODO: Use zonespawns opcode instead client->QueuePacket(app, true, Client::CLIENT_CONNECTED); safe_delete(app); iterator.Advance(); } } void EntityList::SendZoneSpawnsBulk(Client* client) { //float rate = client->Connection()->GetDataRate(); LinkedListIterator iterator(mob_list); NewSpawn_Struct ns; Mob *spawn; uint32 maxspawns=100; //rate = rate > 1.0 ? (rate < 10.0 ? rate : 10.0) : 1.0; //maxspawns = (uint32)rate * SPAWNS_PER_POINT_DATARATE; // FYI > 10240 entities will cause BulkZoneSpawnPacket to throw exception if(maxspawns > mob_list.Count()) maxspawns = mob_list.Count(); BulkZoneSpawnPacket* bzsp = new BulkZoneSpawnPacket(client, maxspawns); for(iterator.Reset(); iterator.MoreElements(); iterator.Advance()) { spawn = iterator.GetData(); if(spawn && spawn->InZone()) { if(spawn->IsClient() && (spawn->CastToClient()->GMHideMe(client) || spawn->CastToClient()->IsHoveringForRespawn())) continue; memset(&ns, 0, sizeof(NewSpawn_Struct)); spawn->FillSpawnStruct(&ns, client); bzsp->AddSpawn(&ns); } } safe_delete(bzsp); } //this is a hack to handle a broken spawn struct void EntityList::SendZonePVPUpdates(Client *to) { LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { Client *c = iterator.GetData(); if(c->GetPVP()) c->SendAppearancePacket(AT_PVP, c->GetPVP(), true, false, to); iterator.Advance(); } } void EntityList::SendZoneCorpses(Client* client) { EQApplicationPacket* app; LinkedListIterator iterator(corpse_list); for(iterator.Reset(); iterator.MoreElements(); iterator.Advance()) { Corpse *ent = iterator.GetData(); app = new EQApplicationPacket; ent->CreateSpawnPacket(app); client->QueuePacket(app, true, Client::CLIENT_CONNECTED); safe_delete(app); } } void EntityList::SendZoneCorpsesBulk(Client* client) { //float rate = client->Connection()->GetDataRate(); LinkedListIterator iterator(corpse_list); NewSpawn_Struct ns; Corpse *spawn; uint32 maxspawns=100; //rate = rate > 1.0 ? (rate < 10.0 ? rate : 10.0) : 1.0; //maxspawns = (uint32)rate * SPAWNS_PER_POINT_DATARATE; // FYI > 10240 entities will cause BulkZoneSpawnPacket to throw exception BulkZoneSpawnPacket* bzsp = new BulkZoneSpawnPacket(client, maxspawns); for(iterator.Reset(); iterator.MoreElements(); iterator.Advance()) { spawn = iterator.GetData(); if(spawn && spawn->InZone()) { memset(&ns, 0, sizeof(NewSpawn_Struct)); spawn->FillSpawnStruct(&ns, client); bzsp->AddSpawn(&ns); } } safe_delete(bzsp); } void EntityList::SendZoneObjects(Client* client) { LinkedListIterator iterator(object_list); iterator.Reset(); while(iterator.MoreElements()) { EQApplicationPacket *app = new EQApplicationPacket; iterator.GetData()->CreateSpawnPacket(app); client->FastQueuePacket(&app); iterator.Advance(); } } void EntityList::Save() { LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { iterator.GetData()->Save(); iterator.Advance(); } } void EntityList::ReplaceWithTarget(Mob* pOldMob, Mob*pNewTarget) { if(!pNewTarget) return; LinkedListIterator iterator(mob_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->IsAIControlled()) { // replace the old mob with the new one if (iterator.GetData()->RemoveFromHateList(pOldMob)) iterator.GetData()->AddToHateList(pNewTarget, 1, 0); } iterator.Advance(); } } void EntityList::RemoveFromTargets(Mob* mob, bool RemoveFromXTargets) { LinkedListIterator iterator(mob_list); iterator.Reset(); while(iterator.MoreElements()) { Mob *m = iterator.GetData(); iterator.Advance(); if(!m) continue; m->RemoveFromHateList(mob); if(RemoveFromXTargets) if(m->IsClient()) m->CastToClient()->RemoveXTarget(mob, false); // FadingMemories calls this function passing the client. else if(mob->IsClient()) mob->CastToClient()->RemoveXTarget(m, false); } } void EntityList::RemoveFromXTargets(Mob* mob) { LinkedListIterator iterator(mob_list); iterator.Reset(); while(iterator.MoreElements()) { Mob *m = iterator.GetData(); iterator.Advance(); if(!m) continue; if(m->IsClient()) m->CastToClient()->RemoveXTarget(mob, false); } } void EntityList::RemoveFromAutoXTargets(Mob* mob) { LinkedListIterator iterator(mob_list); iterator.Reset(); while(iterator.MoreElements()) { Mob *m = iterator.GetData(); iterator.Advance(); if(!m) continue; if(m->IsClient()) m->CastToClient()->RemoveXTarget(mob, true); } } void EntityList::RefreshAutoXTargets(Client *c) { if(!c) return; LinkedListIterator iterator(mob_list); iterator.Reset(); while(iterator.MoreElements()) { Mob *m = iterator.GetData(); iterator.Advance(); if(!m || m->GetHP() <= 0) continue; if(m->CheckAggro(c) && !c->IsXTarget(m)) { c->AddAutoXTarget(m); break; } } } void EntityList::RefreshClientXTargets(Client *c) { if(!c) return; LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { Client *c2 = iterator.GetData(); iterator.Advance(); if(!c2) continue; if(c2->IsClientXTarget(c)) c2->UpdateClientXTarget(c); } } void EntityList::QueueClientsByTarget(Mob* sender, const EQApplicationPacket* app, bool iSendToSender, Mob* SkipThisMob, bool ackreq, bool HoTT, uint32 ClientVersionBits) { LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { Client *c = iterator.GetData(); iterator.Advance(); Mob *Target = c->GetTarget(); if(!Target) continue; Mob *TargetsTarget = NULL; if(Target) TargetsTarget = Target->GetTarget(); bool Send = false; if(c == SkipThisMob) continue; if(iSendToSender) if(c == sender) Send = true; if(c != sender) { if(Target == sender) { Send = true; } else if(HoTT) { if(TargetsTarget == sender) Send = true; } } if(Send && (c->GetClientVersionBit() & ClientVersionBits)) c->QueuePacket(app, ackreq); } } void EntityList::QueueClientsByXTarget(Mob* sender, const EQApplicationPacket* app, bool iSendToSender) { LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { Client *c = iterator.GetData(); iterator.Advance(); if(!c || ((c == sender) && !iSendToSender)) continue; if(!c->IsXTarget(sender)) continue; c->QueuePacket(app); } } void EntityList::QueueCloseClients(Mob* sender, const EQApplicationPacket* app, bool ignore_sender, float dist, Mob* SkipThisMob, bool ackreq, eqFilterType filter) { if (sender == NULL) { QueueClients(sender, app, ignore_sender); return; } if(dist <= 0) { dist = 600; } float dist2 = dist * dist; //pow(dist, 2); LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { Client* ent = iterator.GetData(); if ((!ignore_sender || ent != sender) && (ent != SkipThisMob)) { eqFilterMode filter2 = ent->GetFilter(filter); if(ent->Connected() && ( filter==FilterNone || filter2 == FilterShow || (filter2 == FilterShowGroupOnly && (sender == ent || (ent->GetGroup() && ent->GetGroup()->IsGroupMember(sender)))) || (filter2 == FilterShowSelfOnly && ent==sender)) && (ent->DistNoRoot(*sender) <= dist2)) { ent->QueuePacket(app, ackreq, Client::CLIENT_CONNECTED); } } iterator.Advance(); } } //sender can be null void EntityList::QueueClients(Mob* sender, const EQApplicationPacket* app, bool ignore_sender, bool ackreq) { LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { Client* ent = iterator.GetData(); if ((!ignore_sender || ent != sender)) { ent->QueuePacket(app, ackreq, Client::CLIENT_CONNECTED); } iterator.Advance(); } } /* rewrite of all the queue close methods to use the update manager void EntityList::FilterQueueCloseClients(uint8 filter, uint8 required, Mob* sender, const EQApplicationPacket* app, bool ignore_sender, float dist, Mob* SkipThisMob, bool ackreq){ if(dist <= 0) { dist = 600; } #ifdef PACKET_UPDATE_MANAGER EQApplicationPacket* tmp_app = app->Copy(); #else float dist2 = dist * dist; //pow(dist, 2); #endif LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { Client* ent = iterator.GetData(); uint8 filterval=ent->GetFilter(filter); if(required==0) required=1; if(filterval==required){ if ((!ignore_sender || ent != sender) && (ent != SkipThisMob) ) { #ifdef PACKET_UPDATE_MANAGER if(ent->Connected()) { ent->GetUpdateManager()->QueuePacket(tmp_app, ackreq, sender, ent->DistNoRoot(*sender)); } #else if(ent->Connected() && (ent->DistNoRoot(*sender) <= dist2 || dist == 0)) { ent->QueuePacket(app, ackreq); } #endif } } iterator.Advance(); } #ifdef PACKET_UPDATE_MANAGER EQApplicationPacket::PacketUsed(&tmp_app); #endif } void EntityList::QueueCloseClients(Mob* sender, const EQApplicationPacket* app, bool ignore_sender, float dist, Mob* SkipThisMob, bool ackreq,uint8 filter) { if (sender == 0) { QueueClients(sender, app, ignore_sender); return; } if(dist <= 0) { dist = 600; } #ifdef PACKET_UPDATE_MANAGER EQApplicationPacket* tmp_app = app->Copy(); #else float dist2 = dist * dist; //pow(dist, 2); #endif LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { Client* ent = iterator.GetData(); if ((!ignore_sender || ent != sender) && (ent != SkipThisMob)) { uint8 filter2=ent->GetFilter(filter); if(ent->Connected() && (filter==0 || (filter2==1 || (filter2==99 && entity_list.GetGroupByClient(ent)!=0 && entity_list.GetGroupByClient(ent)->IsGroupMember(sender)) || (filter2==98 && ent==sender))) #ifdef PACKET_UPDATE_MANAGER ) { ent->GetUpdateManager()->QueuePacket(tmp_app, ackreq, sender, ent->DistNoRoot(*sender)); } #else && (ent->DistNoRoot(*sender) <= dist2 || dist == 0)) { ent->QueuePacket(app, ackreq, Client::CLIENT_CONNECTED); } #endif } iterator.Advance(); } #ifdef PACKET_UPDATE_MANAGER EQApplicationPacket::PacketUsed(&tmp_app); #endif } void EntityList::QueueClients(Mob* sender, const EQApplicationPacket* app, bool ignore_sender, bool ackreq) { LinkedListIterator iterator(client_list); #ifdef PACKET_UPDATE_MANAGER EQApplicationPacket* tmp_app = app->Copy(); #endif iterator.Reset(); while(iterator.MoreElements()) { Client* ent = iterator.GetData(); if ((!ignore_sender || ent != sender)) { #ifdef PACKET_UPDATE_MANAGER ent->GetUpdateManager()->QueuePacket(tmp_app, ackreq, sender, ent->DistNoRoot(*sender)); #else ent->QueuePacket(app, ackreq, Client::CLIENT_CONNECTED); #endif } iterator.Advance(); } #ifdef PACKET_UPDATE_MANAGER EQApplicationPacket::PacketUsed(&tmp_app); #endif } */ /* void EntityList::QueueManaged(Mob* sender, const EQApplicationPacket* app, bool ignore_sender, bool ackreq) { LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { Client* ent = iterator.GetData(); if ((!ignore_sender || ent != sender)) { ent->QueuePacket(app, ackreq, Client::CLIENT_CONNECTED); } iterator.Advance(); } }*/ void EntityList::QueueManaged(Mob* sender, const EQApplicationPacket* app, bool ignore_sender, bool ackreq) { LinkedListIterator iterator(client_list); #ifdef PACKET_UPDATE_MANAGER EQApplicationPacket* tmp_app = app->Copy(); #endif iterator.Reset(); while(iterator.MoreElements()) { Client* ent = iterator.GetData(); if ((!ignore_sender || ent != sender)) { #ifdef PACKET_UPDATE_MANAGER ent->GetUpdateManager()->QueuePacket(tmp_app, ackreq, sender, ent->DistNoRoot(*sender)); #else ent->QueuePacket(app, ackreq, Client::CLIENT_CONNECTED); #endif } iterator.Advance(); } #ifdef PACKET_UPDATE_MANAGER EQApplicationPacket::PacketUsed(&tmp_app); #endif } void EntityList::QueueClientsStatus(Mob* sender, const EQApplicationPacket* app, bool ignore_sender, uint8 minstatus, uint8 maxstatus) { LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { if ((!ignore_sender || iterator.GetData() != sender) && (iterator.GetData()->Admin() >= minstatus && iterator.GetData()->Admin() <= maxstatus)) { iterator.GetData()->QueuePacket(app); } iterator.Advance(); } } void EntityList::DuelMessage(Mob* winner, Mob* loser, bool flee) { LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { Client *cur = iterator.GetData(); //might want some sort of distance check in here? if (cur != winner && cur != loser) { if (flee) cur->Message_StringID(15, DUEL_FLED, winner->GetName(),loser->GetName(),loser->GetName()); else cur->Message_StringID(15, DUEL_FINISHED, winner->GetName(),loser->GetName()); } iterator.Advance(); } } Client* EntityList::GetClientByName(const char *checkname) { LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { if (strcasecmp(iterator.GetData()->GetName(), checkname) == 0) { return iterator.GetData(); } iterator.Advance(); } return 0; } Client* EntityList::GetClientByCharID(uint32 iCharID) { LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->CharacterID() == iCharID) { return iterator.GetData(); } iterator.Advance(); } return 0; } Client* EntityList::GetClientByWID(uint32 iWID) { LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->GetWID() == iWID) { return iterator.GetData(); } iterator.Advance(); } return 0; } Client* EntityList::GetRandomClient(float x, float y, float z, float Distance, Client* ExcludeClient) { vector ClientsInRange; LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { if((iterator.GetData() != ExcludeClient) && (iterator.GetData()->DistNoRoot(x, y, z) <= Distance)) { ClientsInRange.push_back(iterator.GetData()); } iterator.Advance(); } if(ClientsInRange.size() == 0) return NULL; return ClientsInRange[MakeRandomInt(0, ClientsInRange.size() - 1)]; } Corpse* EntityList::GetCorpseByOwner(Client* client){ LinkedListIterator iterator(corpse_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->IsPlayerCorpse()) { if (strcasecmp(iterator.GetData()->GetOwnerName(), client->GetName()) == 0) { return iterator.GetData(); } } iterator.Advance(); } return 0; } Corpse* EntityList::GetCorpseByOwnerWithinRange(Client* client, Mob* center, int range){ LinkedListIterator iterator(corpse_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->IsPlayerCorpse()) { if (center->DistNoRootNoZ(*iterator.GetData()) < range && strcasecmp(iterator.GetData()->GetOwnerName(), client->GetName()) == 0) { return iterator.GetData(); } } iterator.Advance(); } return 0; } Corpse* EntityList::GetCorpseByID(uint16 id){ LinkedListIterator iterator(corpse_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->id == id) { return iterator.GetData(); } iterator.Advance(); } return 0; } Corpse* EntityList::GetCorpseByDBID(uint32 dbid){ LinkedListIterator iterator(corpse_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->GetDBID() == dbid) { return iterator.GetData(); } iterator.Advance(); } return 0; } Corpse* EntityList::GetCorpseByName(const char* name){ LinkedListIterator iterator(corpse_list); iterator.Reset(); while(iterator.MoreElements()) { if (strcmp(iterator.GetData()->GetName(),name)==0) { return iterator.GetData(); } iterator.Advance(); } return 0; } void EntityList::RemoveAllCorpsesByCharID(uint32 charid) { LinkedListIterator iterator(corpse_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->GetCharID() == charid) iterator.RemoveCurrent(); else iterator.Advance(); } } void EntityList::RemoveCorpseByDBID(uint32 dbid) { LinkedListIterator iterator(corpse_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->GetDBID() == dbid) iterator.RemoveCurrent(); else iterator.Advance(); } } int EntityList::RezzAllCorpsesByCharID(uint32 charid) { int RezzExp = 0; LinkedListIterator iterator(corpse_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->GetCharID() == charid) { RezzExp += iterator.GetData()->GetRezzExp(); iterator.GetData()->Rezzed(true); iterator.GetData()->CompleteRezz(); } iterator.Advance(); } return RezzExp; } Group* EntityList::GetGroupByMob(Mob* mob) { list::iterator iterator; iterator = group_list.begin(); while(iterator != group_list.end()) { if ((*iterator)->IsGroupMember(mob)) { return *iterator; } iterator++; } #if EQDEBUG >= 5 CheckGroupList (__FILE__, __LINE__); #endif return 0; } Group* EntityList::GetGroupByLeaderName(char* leader){ list::iterator iterator; iterator = group_list.begin(); while(iterator != group_list.end()) { if (!strcmp((*iterator)->GetLeaderName(), leader)) { return *iterator; } iterator++; } #if EQDEBUG >= 5 CheckGroupList (__FILE__, __LINE__); #endif return 0; } Group* EntityList::GetGroupByID(uint32 group_id){ list::iterator iterator; iterator = group_list.begin(); while(iterator != group_list.end()) { if ((*iterator)->GetID() == group_id) { return *iterator; } iterator++; } #if EQDEBUG >= 5 CheckGroupList (__FILE__, __LINE__); #endif return 0; } Group* EntityList::GetGroupByClient(Client* client) { list ::iterator iterator; iterator = group_list.begin(); while(iterator != group_list.end()) { if ((*iterator)->IsGroupMember(client->CastToMob())) { return *iterator; } iterator++; } #if EQDEBUG >= 5 CheckGroupList (__FILE__, __LINE__); #endif return 0; } Raid* EntityList::GetRaidByLeaderName(const char *leader){ list::iterator iterator; iterator = raid_list.begin(); while(iterator != raid_list.end()) { if((*iterator)->GetLeader()){ if(strcmp((*iterator)->GetLeader()->GetName(), leader) == 0){ return *iterator; } } iterator++; } return 0; } Raid* EntityList::GetRaidByID(uint32 id){ list::iterator iterator; iterator = raid_list.begin(); while(iterator != raid_list.end()) { if ((*iterator)->GetID() == id) { return *iterator; } iterator++; } return 0; } Raid* EntityList::GetRaidByClient(Client* client) { list::iterator iterator; iterator = raid_list.begin(); while(iterator != raid_list.end()) { for(int x = 0; x < MAX_RAID_MEMBERS; x++) { if((*iterator)->members[x].member){ if((*iterator)->members[x].member == client) return *iterator; } } iterator++; } return 0; } Raid* EntityList::GetRaidByMob(Mob* mob) { list::iterator iterator; iterator = raid_list.begin(); while(iterator != raid_list.end()) { for(int x = 0; x < MAX_RAID_MEMBERS; x++) { // TODO: Implement support for Mob objects in Raid class /*if((*iterator)->members[x].member){ if((*iterator)->members[x].member == mob) return *iterator; }*/ } iterator++; } return 0; } Client* EntityList::GetClientByAccID(uint32 accid) { LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->AccountID() == accid) { return iterator.GetData(); } iterator.Advance(); } return 0; } Client* EntityList::GetClientByID(uint16 id) { LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()) { if (iterator.GetData()->GetID() == id) { return iterator.GetData(); } } iterator.Advance(); } return 0; } void EntityList::ChannelMessageFromWorld(const char* from, const char* to, uint8 chan_num, uint32 guild_id, uint8 language, const char* message) { LinkedListIterator iterator(client_list); iterator.Reset(); for(; iterator.MoreElements(); iterator.Advance()) { Client* client = iterator.GetData(); if(chan_num == 0) { if(!client->IsInGuild(guild_id)) continue; if(!guild_mgr.CheckPermission(guild_id, client->GuildRank(), GUILD_HEAR)) continue; if(client->GetFilter(FilterGuildChat) == FilterHide) continue; } else if(chan_num == 5) { if(client->GetFilter(FilterOOC) == FilterHide) continue; } client->ChannelMessageSend(from, to, chan_num, language, message); } } void EntityList::Message(uint32 to_guilddbid, uint32 type, const char* message, ...) { va_list argptr; char buffer[4096]; va_start(argptr, message); vsnprintf(buffer, 4096, message, argptr); va_end(argptr); LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { Client* client = iterator.GetData(); if (to_guilddbid == 0 || client->IsInGuild(to_guilddbid)) client->Message(type, buffer); iterator.Advance(); } } void EntityList::QueueClientsGuild(Mob* sender, const EQApplicationPacket* app, bool ignore_sender, uint32 guild_id){ LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { Client* client = iterator.GetData()->CastToClient(); if (client->IsInGuild(guild_id)) client->QueuePacket(app); iterator.Advance(); } } void EntityList::QueueClientsGuildBankItemUpdate(const GuildBankItemUpdate_Struct *gbius, uint32 GuildID) { EQApplicationPacket *outapp = new EQApplicationPacket(OP_GuildBank, sizeof(GuildBankItemUpdate_Struct)); GuildBankItemUpdate_Struct *outgbius = (GuildBankItemUpdate_Struct*)outapp->pBuffer; memcpy(outgbius, gbius, sizeof(GuildBankItemUpdate_Struct)); const Item_Struct *Item = database.GetItem(gbius->ItemID); LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { Client* client = iterator.GetData()->CastToClient(); if (client->IsInGuild(GuildID)) { if(Item && (gbius->Permissions == GuildBankPublicIfUsable)) outgbius->Useable = Item->IsEquipable(client->GetBaseRace(), client->GetBaseClass()); client->QueuePacket(outapp); } iterator.Advance(); } safe_delete(outapp); } void EntityList::MessageStatus(uint32 to_guild_id, int to_minstatus, uint32 type, const char* message, ...) { va_list argptr; char buffer[4096]; va_start(argptr, message); vsnprintf(buffer, 4096, message, argptr); va_end(argptr); LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { Client* client = iterator.GetData(); if ((to_guild_id == 0 || client->IsInGuild(to_guild_id)) && client->Admin() >= to_minstatus) client->Message(type, buffer); iterator.Advance(); } } // works much like MessageClose, but with formatted strings void EntityList::MessageClose_StringID(Mob *sender, bool skipsender, float dist, uint32 type, uint32 string_id, const char* message1,const char* message2,const char* message3,const char* message4,const char* message5,const char* message6,const char* message7,const char* message8,const char* message9) { Client *c; LinkedListIterator iterator(client_list); float dist2 = dist * dist; for(iterator.Reset(); iterator.MoreElements(); iterator.Advance()) { c = iterator.GetData(); if(c && c->DistNoRoot(*sender) <= dist2 && (!skipsender || c != sender)) c->Message_StringID(type, string_id, message1, message2, message3, message4, message5, message6, message7, message8, message9); } } void EntityList::Message_StringID(Mob *sender, bool skipsender, uint32 type, uint32 string_id, const char* message1,const char* message2,const char* message3,const char* message4,const char* message5,const char* message6,const char* message7,const char* message8,const char* message9) { Client *c; LinkedListIterator iterator(client_list); for(iterator.Reset(); iterator.MoreElements(); iterator.Advance()) { c = iterator.GetData(); if(c && (!skipsender || c != sender)) c->Message_StringID(type, string_id, message1, message2, message3, message4, message5, message6, message7, message8, message9); } } void EntityList::MessageClose(Mob* sender, bool skipsender, float dist, uint32 type, const char* message, ...) { va_list argptr; char buffer[4096]; va_start(argptr, message); vsnprintf(buffer, 4095, message, argptr); va_end(argptr); float dist2 = dist * dist; LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->DistNoRoot(*sender) <= dist2 && (!skipsender || iterator.GetData() != sender)) { iterator.GetData()->Message(type, buffer); } iterator.Advance(); } } void EntityList::RemoveAllMobs(){ LinkedListIterator iterator(mob_list); iterator.Reset(); while(iterator.MoreElements()) iterator.RemoveCurrent(); } void EntityList::RemoveAllClients(){ LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) iterator.RemoveCurrent(false); } void EntityList::RemoveAllNPCs(){ LinkedListIterator iterator(npc_list); iterator.Reset(); while(iterator.MoreElements()) { iterator.RemoveCurrent(false); } npc_limit_list.clear(); } void EntityList::RemoveAllMercs(){ LinkedListIterator iterator(merc_list); iterator.Reset(); while(iterator.MoreElements()) { iterator.RemoveCurrent(false); } } void EntityList::RemoveAllGroups(){ while (group_list.size()) group_list.pop_front(); #if EQDEBUG >= 5 CheckGroupList (__FILE__, __LINE__); #endif } void EntityList::RemoveAllRaids(){ while (raid_list.size()) raid_list.pop_front(); } void EntityList::RemoveAllDoors(){ LinkedListIterator iterator(door_list); iterator.Reset(); while(iterator.MoreElements()) iterator.RemoveCurrent(); DespawnAllDoors(); } void EntityList::DespawnAllDoors(){ EQApplicationPacket* outapp = new EQApplicationPacket(OP_RemoveAllDoors, 0); this->QueueClients(0,outapp); safe_delete(outapp); } void EntityList::RespawnAllDoors(){ LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { if(iterator.GetData() != 0) { EQApplicationPacket* outapp = new EQApplicationPacket(); MakeDoorSpawnPacket(outapp, iterator.GetData()); iterator.GetData()->FastQueuePacket(&outapp); } iterator.Advance(); } } void EntityList::RemoveAllCorpses(){ LinkedListIterator iterator(corpse_list); iterator.Reset(); while(iterator.MoreElements()) iterator.RemoveCurrent(); } void EntityList::RemoveAllObjects(){ LinkedListIterator iterator(object_list); iterator.Reset(); while(iterator.MoreElements()) iterator.RemoveCurrent(); } void EntityList::RemoveAllTraps(){ LinkedListIterator iterator(trap_list); iterator.Reset(); while(iterator.MoreElements()) iterator.RemoveCurrent(); } bool EntityList::RemoveMob(uint16 delete_id){ if(delete_id==0) return true; LinkedListIterator iterator(mob_list); iterator.Reset(); while(iterator.MoreElements()) { if(iterator.GetData()->GetID()==delete_id){ if(iterator.GetData()->IsNPC()) entity_list.RemoveNPC(delete_id); else if(iterator.GetData()->IsClient()) entity_list.RemoveClient(delete_id); iterator.RemoveCurrent(); return true; } iterator.Advance(); } return false; } bool EntityList::RemoveMob(Mob *delete_mob) { if(delete_mob==0) return true; LinkedListIterator iterator(mob_list); iterator.Reset(); while(iterator.MoreElements()) { if(iterator.GetData()==delete_mob){ iterator.RemoveCurrent(); return true; } iterator.Advance(); } return false; } bool EntityList::RemoveNPC(uint16 delete_id){ LinkedListIterator iterator(npc_list); iterator.Reset(); while(iterator.MoreElements()) { if(iterator.GetData()->GetID()==delete_id){ //make sure its proximity is removed RemoveProximity(iterator.GetData()->GetID()); //take it out of the list iterator.RemoveCurrent(false);//Already Deleted //take it out of our limit list if(npc_limit_list.count(delete_id) == 1) npc_limit_list.erase(delete_id); return true; } iterator.Advance(); } return false; } bool EntityList::RemoveMerc(uint16 delete_id){ LinkedListIterator iterator(merc_list); iterator.Reset(); while(iterator.MoreElements()) { if(iterator.GetData()->GetID()==delete_id){ iterator.RemoveCurrent(false);//Already Deleted return true; } iterator.Advance(); } return false; } bool EntityList::RemoveClient(uint16 delete_id){ LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { if(iterator.GetData()->GetID()==delete_id){ iterator.RemoveCurrent(false);//Already Deleted return true; } iterator.Advance(); } return false; } bool EntityList::RemoveClient(Client *delete_client){ LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { if(iterator.GetData()==delete_client){ iterator.RemoveCurrent(false);//Already Deleted return true; } iterator.Advance(); } return false; } bool EntityList::RemoveObject(uint16 delete_id){ LinkedListIterator iterator(object_list); iterator.Reset(); while(iterator.MoreElements()) { if(iterator.GetData()->GetID()==delete_id){ iterator.RemoveCurrent(); return true; } iterator.Advance(); } return false; } bool EntityList::RemoveTrap(uint16 delete_id){ LinkedListIterator iterator(trap_list); iterator.Reset(); while(iterator.MoreElements()) { if(iterator.GetData()->GetID()==delete_id){ iterator.RemoveCurrent(); return true; } iterator.Advance(); } return false; } bool EntityList::RemoveDoor(uint16 delete_id){ LinkedListIterator iterator(door_list); iterator.Reset(); while(iterator.MoreElements()) { if(iterator.GetData()->GetID()==delete_id){ iterator.RemoveCurrent(); return true; } iterator.Advance(); } return false; } bool EntityList::RemoveCorpse(uint16 delete_id){ LinkedListIterator iterator(corpse_list); iterator.Reset(); while(iterator.MoreElements()) { if(iterator.GetData()->GetID()==delete_id){ iterator.RemoveCurrent(); return true; } iterator.Advance(); } return false; } bool EntityList::RemoveGroup(uint32 delete_id){ list::iterator iterator; iterator = group_list.begin(); while(iterator != group_list.end()) { if((*iterator)->GetID() == delete_id) { group_list.remove (*iterator); #if EQDEBUG >= 5 CheckGroupList (__FILE__, __LINE__); #endif return true; } iterator++; } #if EQDEBUG >= 5 CheckGroupList (__FILE__, __LINE__); #endif return false; } bool EntityList::RemoveRaid(uint32 delete_id){ list::iterator iterator; iterator = raid_list.begin(); while(iterator != raid_list.end()) { if((*iterator)->GetID() == delete_id) { raid_list.remove (*iterator); return true; } iterator++; } return false; } void EntityList::Clear() { RemoveAllClients(); entity_list.RemoveAllTraps(); //we can have child npcs so we go first entity_list.RemoveAllNPCs(); entity_list.RemoveAllMobs(); entity_list.RemoveAllCorpses(); entity_list.RemoveAllGroups(); entity_list.RemoveAllDoors(); entity_list.RemoveAllObjects(); entity_list.RemoveAllRaids(); entity_list.RemoveAllLocalities(); last_insert_id = 0; } void EntityList::UpdateWho(bool iSendFullUpdate) { if ((!worldserver.Connected()) || !ZoneLoaded) return; LinkedListIterator iterator(client_list); uint32 tmpNumUpdates = numclients + 5; ServerPacket* pack = 0; ServerClientListKeepAlive_Struct* sclka = 0; if (!iSendFullUpdate) { pack = new ServerPacket(ServerOP_ClientListKA, sizeof(ServerClientListKeepAlive_Struct) + (tmpNumUpdates * 4)); sclka = (ServerClientListKeepAlive_Struct*) pack->pBuffer; } iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->InZone()) { if (iSendFullUpdate) { iterator.GetData()->UpdateWho(); } else { if (sclka->numupdates >= tmpNumUpdates) { tmpNumUpdates += 10; uint8* tmp = pack->pBuffer; pack->pBuffer = new uint8[sizeof(ServerClientListKeepAlive_Struct) + (tmpNumUpdates * 4)]; memset(pack->pBuffer, 0, sizeof(ServerClientListKeepAlive_Struct) + (tmpNumUpdates * 4)); memcpy(pack->pBuffer, tmp, pack->size); pack->size = sizeof(ServerClientListKeepAlive_Struct) + (tmpNumUpdates * 4); safe_delete_array(tmp); } sclka->wid[sclka->numupdates] = iterator.GetData()->GetWID(); sclka->numupdates++; } } iterator.Advance(); } if (!iSendFullUpdate) { pack->size = sizeof(ServerClientListKeepAlive_Struct) + (sclka->numupdates * 4); worldserver.SendPacket(pack); safe_delete(pack); } } void EntityList::RemoveEntity(uint16 id) { if (id == 0) return; if(entity_list.RemoveMob(id)) return; else if(entity_list.RemoveCorpse(id)) return; else if(entity_list.RemoveDoor(id)) return; else if(entity_list.RemoveGroup(id)) return; else if(entity_list.RemoveTrap(id)) return; #ifdef BOTS // This block of code is necessary to clean up bot objects else if(entity_list.RemoveBot(id)) return; #endif //BOTS else entity_list.RemoveObject(id); } void EntityList::Process() { _ZP(EntityList_Process); CheckSpawnQueue(); } void EntityList::CountNPC(uint32* NPCCount, uint32* NPCLootCount, uint32* gmspawntype_count) { LinkedListIterator iterator(npc_list); *NPCCount = 0; *NPCLootCount = 0; iterator.Reset(); while(iterator.MoreElements()) { (*NPCCount)++; (*NPCLootCount) += iterator.GetData()->CastToNPC()->CountLoot(); if (iterator.GetData()->CastToNPC()->GetNPCTypeID() == 0) (*gmspawntype_count)++; iterator.Advance(); } } void EntityList::DoZoneDump(ZSDump_Spawn2* spawn2_dump, ZSDump_NPC* npc_dump, ZSDump_NPC_Loot* npcloot_dump, NPCType* gmspawntype_dump) { uint32 spawn2index = 0; uint32 NPCindex = 0; uint32 NPCLootindex = 0; uint32 gmspawntype_index = 0; if (npc_dump != 0) { LinkedListIterator iterator(npc_list); NPC* npc = 0; iterator.Reset(); while(iterator.MoreElements()) { npc = iterator.GetData()->CastToNPC(); if (spawn2_dump != 0) npc_dump[NPCindex].spawn2_dump_index = zone->DumpSpawn2(spawn2_dump, &spawn2index, npc->respawn2); npc_dump[NPCindex].npctype_id = npc->GetNPCTypeID(); npc_dump[NPCindex].cur_hp = npc->GetHP(); if (npc->IsCorpse()) { if (npc->CastToCorpse()->IsLocked()) npc_dump[NPCindex].corpse = 2; else npc_dump[NPCindex].corpse = 1; } else npc_dump[NPCindex].corpse = 0; npc_dump[NPCindex].decay_time_left = 0xFFFFFFFF; npc_dump[NPCindex].x = npc->GetX(); npc_dump[NPCindex].y = npc->GetY(); npc_dump[NPCindex].z = npc->GetZ(); npc_dump[NPCindex].heading = npc->GetHeading(); npc_dump[NPCindex].copper = npc->copper; npc_dump[NPCindex].silver = npc->silver; npc_dump[NPCindex].gold = npc->gold; npc_dump[NPCindex].platinum = npc->platinum; if (npcloot_dump != 0) npc->DumpLoot(NPCindex, npcloot_dump, &NPCLootindex); if (gmspawntype_dump != 0) { if (npc->GetNPCTypeID() == 0) { memcpy(&gmspawntype_dump[gmspawntype_index], npc->NPCTypedata, sizeof(NPCType)); npc_dump[NPCindex].gmspawntype_index = gmspawntype_index; gmspawntype_index++; } } NPCindex++; iterator.Advance(); } } if (spawn2_dump != 0) zone->DumpAllSpawn2(spawn2_dump, &spawn2index); } void EntityList::Depop(bool StartSpawnTimer) { LinkedListIterator iterator(npc_list); iterator.Reset(); for(; iterator.MoreElements(); iterator.Advance()) { NPC *it = iterator.GetData(); if(it) { Mob *own = it->GetOwner(); //do not depop player's pets... if(own && own->IsClient()) continue; if(it->IsFindable()) UpdateFindableNPCState(it, true); it->Depop(StartSpawnTimer); } } } void EntityList::DepopAll(int NPCTypeID, bool StartSpawnTimer) { LinkedListIterator iterator(npc_list); iterator.Reset(); for(; iterator.MoreElements(); iterator.Advance()) { NPC *it = iterator.GetData(); if(it && (it->GetNPCTypeID() == (uint32)NPCTypeID)) it->Depop(StartSpawnTimer); } } void EntityList::SendTraders(Client* client){ LinkedListIterator iterator(client_list); iterator.Reset(); Client* trader; while(iterator.MoreElements()) { trader=iterator.GetData(); if(trader->IsTrader()) client->SendTraderPacket(trader); if(trader->IsBuyer()) client->SendBuyerPacket(trader); iterator.Advance(); } } void EntityList::RemoveFromHateLists(Mob* mob, bool settoone) { LinkedListIterator iterator(npc_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->CheckAggro(mob)) { if (!settoone) { iterator.GetData()->RemoveFromHateList(mob); } else { iterator.GetData()->SetHate(mob,1); } } iterator.Advance(); } } void EntityList::RemoveDebuffs(Mob* caster) { LinkedListIterator iterator(mob_list); iterator.Reset(); while(iterator.MoreElements()) { iterator.GetData()->BuffFadeDetrimentalByCaster(caster); iterator.Advance(); } } // Currently, a new packet is sent per entity. // @todo: Come back and use FLAG_COMBINED to pack // all updates into one packet. void EntityList::SendPositionUpdates(Client* client, uint32 cLastUpdate, float range, Entity* alwayssend, bool iSendEvenIfNotChanged) { range = range * range; LinkedListIterator iterator(mob_list); EQApplicationPacket* outapp = 0; PlayerPositionUpdateServer_Struct* ppu = 0; Mob* mob = 0; iterator.Reset(); while(iterator.MoreElements()) { if (outapp == 0) { outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); ppu = (PlayerPositionUpdateServer_Struct*)outapp->pBuffer; } mob = iterator.GetData()->CastToMob(); if (mob && !mob->IsCorpse() && (iterator.GetData() != client) && (mob->IsClient() || iSendEvenIfNotChanged || (mob->LastChange() >= cLastUpdate)) && (!iterator.GetData()->IsClient() || !iterator.GetData()->CastToClient()->GMHideMe(client))) { //bool Grouped = client->HasGroup() && mob->IsClient() && (client->GetGroup() == mob->CastToClient()->GetGroup()); //if (range == 0 || (iterator.GetData() == alwayssend) || Grouped || (mob->DistNoRootNoZ(*client) <= range)) { if (range == 0 || (iterator.GetData() == alwayssend) || mob->IsClient() || (mob->DistNoRoot(*client) <= range)) { mob->MakeSpawnUpdate(ppu); } if(mob && mob->IsClient() && mob->GetID()>0) { client->QueuePacket(outapp, false, Client::CLIENT_CONNECTED); } } safe_delete(outapp); outapp = 0; iterator.Advance(); } safe_delete(outapp); } char* EntityList::MakeNameUnique(char* name) { bool used[300]; memset(used, 0, sizeof(used)); name[61] = 0; name[62] = 0; name[63] = 0; LinkedListIterator iterator(mob_list); iterator.Reset(); int len = strlen(name); while(iterator.MoreElements()) { if (iterator.GetData()->IsMob()) { if (strncasecmp(iterator.GetData()->CastToMob()->GetName(), name, len) == 0) { if (Seperator::IsNumber(&iterator.GetData()->CastToMob()->GetName()[len])) { used[atoi(&iterator.GetData()->CastToMob()->GetName()[len])] = true; } } } iterator.Advance(); } for (int i=0; i < 300; i++) { if (!used[i]) { #ifdef _WINDOWS snprintf(name, 64, "%s%03d", name, i); #else //glibc clears destination of snprintf //make a copy of name before snprintf--misanthropicfiend char temp_name[64]; strn0cpy(temp_name, name, 64); snprintf(name, 64, "%s%03d", temp_name, i); #endif return name; } } LogFile->write(EQEMuLog::Error, "Fatal error in EntityList::MakeNameUnique: Unable to find unique name for '%s'", name); char tmp[64] = "!"; strn0cpy(&tmp[1], name, sizeof(tmp) - 1); strcpy(name, tmp); return MakeNameUnique(name); } char* EntityList::RemoveNumbers(char* name) { char tmp[64]; memset(tmp, 0, sizeof(tmp)); int k = 0; for (unsigned int i=0; i '9') tmp[k++] = name[i]; } strn0cpy(name, tmp, sizeof(tmp)); return name; } void EntityList::ListNPCs(Client* client, const char* arg1, const char* arg2, uint8 searchtype) { if (arg1 == 0) searchtype = 0; else if (arg2 == 0 && searchtype >= 2) searchtype = 0; LinkedListIterator iterator(npc_list); uint32 x = 0; uint32 z = 0; char sName[36]; iterator.Reset(); client->Message(0, "NPCs in the zone:"); if(searchtype == 0) { while(iterator.MoreElements()) { NPC *n = iterator.GetData(); client->Message(0, " %5d: %s (%.0f, %0.f, %.0f)", n->GetID(), n->GetName(), n->GetX(), n->GetY(), n->GetZ()); x++; z++; iterator.Advance(); } } else if(searchtype == 1) { client->Message(0, "Searching by name method. (%s)",arg1); char* tmp = new char[strlen(arg1) + 1]; strcpy(tmp, arg1); strupr(tmp); while(iterator.MoreElements()) { z++; strcpy(sName, iterator.GetData()->GetName()); strupr(sName); if (strstr(sName, tmp)) { NPC *n = iterator.GetData(); client->Message(0, " %5d: %s (%.0f, %.0f, %.0f)", n->GetID(), n->GetName(), n->GetX(), n->GetY(), n->GetZ()); x++; } iterator.Advance(); } safe_delete_array(tmp); } else if(searchtype == 2) { client->Message(0, "Searching by number method. (%s %s)",arg1,arg2); while(iterator.MoreElements()) { z++; if ((iterator.GetData()->GetID() >= atoi(arg1)) && (iterator.GetData()->GetID() <= atoi(arg2)) && (atoi(arg1) <= atoi(arg2))) { client->Message(0, " %5d: %s", iterator.GetData()->GetID(), iterator.GetData()->GetName()); x++; } iterator.Advance(); } } client->Message(0, "%d npcs listed. There is a total of %d npcs in this zone.", x, z); } void EntityList::ListNPCCorpses(Client* client) { LinkedListIterator iterator(corpse_list); uint32 x = 0; iterator.Reset(); client->Message(0, "NPC Corpses in the zone:"); while(iterator.MoreElements()) { if (iterator.GetData()->IsNPCCorpse()) { client->Message(0, " %5d: %s", iterator.GetData()->GetID(), iterator.GetData()->GetName()); x++; } iterator.Advance(); } client->Message(0, "%d npc corpses listed.", x); } void EntityList::ListPlayerCorpses(Client* client) { LinkedListIterator iterator(corpse_list); uint32 x = 0; iterator.Reset(); client->Message(0, "Player Corpses in the zone:"); while(iterator.MoreElements()) { if (iterator.GetData()->IsPlayerCorpse()) { client->Message(0, " %5d: %s", iterator.GetData()->GetID(), iterator.GetData()->GetName()); x++; } iterator.Advance(); } client->Message(0, "%d player corpses listed.", x); } void EntityList::FindPathsToAllNPCs() { if(!zone->pathing) return; LinkedListIterator Iterator(npc_list); Iterator.Reset(); while(Iterator.MoreElements()) { VERTEX Node0 = zone->pathing->GetPathNodeCoordinates(0, false); VERTEX Dest(Iterator.GetData()->GetX(), Iterator.GetData()->GetY(), Iterator.GetData()->GetZ()); list Route = zone->pathing->FindRoute(Node0, Dest); if(Route.size() == 0) printf("Unable to find a route to %s\n", Iterator.GetData()->GetName()); else printf("Found a route to %s\n", Iterator.GetData()->GetName()); Iterator.Advance(); } fflush(stdout); } // returns the number of corpses deleted. A negative number indicates an error code. int32 EntityList::DeleteNPCCorpses() { LinkedListIterator iterator(corpse_list); int32 x = 0; iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->IsNPCCorpse()) { iterator.GetData()->Depop(); x++; } iterator.Advance(); } return x; } // returns the number of corpses deleted. A negative number indicates an error code. int32 EntityList::DeletePlayerCorpses() { LinkedListIterator iterator(corpse_list); int32 x = 0; iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->IsPlayerCorpse()) { iterator.GetData()->CastToCorpse()->Delete(); x++; } iterator.Advance(); } return x; } void EntityList::SendPetitionToAdmins(){ LinkedListIterator iterator(client_list); EQApplicationPacket* outapp = new EQApplicationPacket(OP_PetitionUpdate,sizeof(PetitionUpdate_Struct)); PetitionUpdate_Struct* pcus = (PetitionUpdate_Struct*) outapp->pBuffer; pcus->petnumber = 0; // Petition Number pcus->color = 0; pcus->status = 0xFFFFFFFF; pcus->senttime = 0; strcpy(pcus->accountid, ""); strcpy(pcus->gmsenttoo, ""); pcus->quetotal=0; iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->CastToClient()->Admin() >= 80) iterator.GetData()->CastToClient()->QueuePacket(outapp); iterator.Advance(); } safe_delete(outapp); } void EntityList::SendPetitionToAdmins(Petition* pet) { LinkedListIterator iterator(client_list); EQApplicationPacket* outapp = new EQApplicationPacket(OP_PetitionUpdate,sizeof(PetitionUpdate_Struct)); PetitionUpdate_Struct* pcus = (PetitionUpdate_Struct*) outapp->pBuffer; pcus->petnumber = pet->GetID(); // Petition Number if (pet->CheckedOut()) { pcus->color = 0x00; pcus->status = 0xFFFFFFFF; pcus->senttime = pet->GetSentTime(); strcpy(pcus->accountid, ""); strcpy(pcus->gmsenttoo, ""); } else { pcus->color = pet->GetUrgency(); // 0x00 = green, 0x01 = yellow, 0x02 = red pcus->status = pet->GetSentTime(); pcus->senttime = pet->GetSentTime(); // 4 has to be 0x1F strcpy(pcus->accountid, pet->GetAccountName()); strcpy(pcus->charname, pet->GetCharName()); } pcus->quetotal = petition_list.GetTotalPetitions(); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->CastToClient()->Admin() >= 80) { if (pet->CheckedOut()) strcpy(pcus->gmsenttoo, ""); else strcpy(pcus->gmsenttoo, iterator.GetData()->CastToClient()->GetName()); iterator.GetData()->CastToClient()->QueuePacket(outapp); } iterator.Advance(); } safe_delete(outapp); } void EntityList::ClearClientPetitionQueue() { EQApplicationPacket* outapp = new EQApplicationPacket(OP_PetitionUpdate,sizeof(PetitionUpdate_Struct)); PetitionUpdate_Struct* pet = (PetitionUpdate_Struct*) outapp->pBuffer; pet->color = 0x00; pet->status = 0xFFFFFFFF; pet->senttime = 0; strcpy(pet->accountid, ""); strcpy(pet->gmsenttoo, ""); strcpy(pet->charname, ""); pet->quetotal = petition_list.GetTotalPetitions(); LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->CastToClient()->Admin() >= 100) { int x = 0; for (x=0;x<64;x++) { pet->petnumber = x; iterator.GetData()->CastToClient()->QueuePacket(outapp); } } iterator.Advance(); } safe_delete(outapp); return; } void EntityList::WriteEntityIDs() { LinkedListIterator iterator(mob_list); iterator.Reset(); while(iterator.MoreElements()) { cout << "ID: " << iterator.GetData()->GetID() << " Name: " << iterator.GetData()->GetName() << endl; iterator.Advance(); } } BulkZoneSpawnPacket::BulkZoneSpawnPacket(Client* iSendTo, uint32 iMaxSpawnsPerPacket) { data = 0; pSendTo = iSendTo; pMaxSpawnsPerPacket = iMaxSpawnsPerPacket; } BulkZoneSpawnPacket::~BulkZoneSpawnPacket() { SendBuffer(); safe_delete_array(data) } bool BulkZoneSpawnPacket::AddSpawn(NewSpawn_Struct* ns) { if (!data) { data = new NewSpawn_Struct[pMaxSpawnsPerPacket]; memset(data, 0, sizeof(NewSpawn_Struct) * pMaxSpawnsPerPacket); index = 0; } memcpy(&data[index], ns, sizeof(NewSpawn_Struct)); index++; if (index >= pMaxSpawnsPerPacket) { SendBuffer(); return true; } return false; } void BulkZoneSpawnPacket::SendBuffer() { if (!data) return; uint32 tmpBufSize = (index * sizeof(NewSpawn_Struct)); EQApplicationPacket* outapp = new EQApplicationPacket(OP_ZoneSpawns, (unsigned char *)data, tmpBufSize); if (pSendTo) { pSendTo->FastQueuePacket(&outapp); } else { entity_list.QueueClients(0, outapp); safe_delete(outapp); } memset(data, 0, sizeof(NewSpawn_Struct) * pMaxSpawnsPerPacket); index = 0; } void EntityList::DoubleAggro(Mob* who) { LinkedListIterator iterator(npc_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->CheckAggro(who)) iterator.GetData()->SetHate(who,iterator.GetData()->CastToNPC()->GetHateAmount(who),iterator.GetData()->CastToNPC()->GetHateAmount(who)*2); iterator.Advance(); } } void EntityList::HalveAggro(Mob* who) { LinkedListIterator iterator(npc_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->CastToNPC()->CheckAggro(who)) iterator.GetData()->CastToNPC()->SetHate(who,iterator.GetData()->CastToNPC()->GetHateAmount(who)/2); iterator.Advance(); } } void EntityList::Evade(Mob *who) { uint32 flatval = who->GetLevel() * 13; int amt = 0; LinkedListIterator iterator(npc_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->CastToNPC()->CheckAggro(who)){ amt = iterator.GetData()->CastToNPC()->GetHateAmount(who); amt -= flatval; if(amt > 0) iterator.GetData()->CastToNPC()->SetHate(who, amt); else iterator.GetData()->CastToNPC()->SetHate(who, 0); } iterator.Advance(); } } //removes "targ" from all hate lists, including feigned, in the zone void EntityList::ClearAggro(Mob* targ) { LinkedListIterator iterator(npc_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->CheckAggro(targ)) iterator.GetData()->RemoveFromHateList(targ); iterator.GetData()->RemoveFromFeignMemory(targ->CastToClient()); //just in case we feigned iterator.Advance(); } } void EntityList::ClearFeignAggro(Mob* targ) { LinkedListIterator iterator(npc_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->CheckAggro(targ)) { if(iterator.GetData()->SpecAttacks[IMMUNE_FEIGN_DEATH]) { iterator.GetData()->SetHate(targ, 0); iterator.Advance(); continue; } iterator.GetData()->RemoveFromHateList(targ); // EverHood 6/24/06 // For client targets if the mob that hated us is 35+ // there is a 3 outta 5 chance he adds us to feign memory if(targ->IsClient()){ if (iterator.GetData()->GetLevel() >= 35 && (MakeRandomInt(1,100)<=60)){ iterator.GetData()->AddFeignMemory(targ->CastToClient()); } else { targ->CastToClient()->RemoveXTarget(iterator.GetData(), false); } } } iterator.Advance(); } } // EverHood 6/17/06 void EntityList::ClearZoneFeignAggro(Client* targ) { LinkedListIterator iterator(npc_list); iterator.Reset(); while(iterator.MoreElements()) { iterator.GetData()->RemoveFromFeignMemory(targ); targ->CastToClient()->RemoveXTarget(iterator.GetData(), false); iterator.Advance(); } } void EntityList::AggroZone(Mob* who, int hate) { LinkedListIterator iterator(npc_list); iterator.Reset(); while(iterator.MoreElements()) { iterator.GetData()->AddToHateList(who, hate); iterator.Advance(); } } // Signal Quest command function void EntityList::SignalMobsByNPCID(uint32 snpc, int signal_id) { LinkedListIterator iterator(npc_list); iterator.Reset(); while(iterator.MoreElements()) { NPC *it = iterator.GetData(); if (it->GetNPCTypeID() == snpc) { it->SignalNPC(signal_id); } iterator.Advance(); } } bool EntityList::MakeTrackPacket(Client* client) { uint32 distance = 0; float MobDistance; if(client->GetClass() == DRUID) distance = (client->GetSkill(TRACKING)*10); else if(client->GetClass() == RANGER) distance = (client->GetSkill(TRACKING)*12); else if(client->GetClass() == BARD) distance = (client->GetSkill(TRACKING)*7); if(distance <= 0) return false; if(distance<300) distance=300; uint32 spe= 0; bool ret = false; spe = mob_list.Count() + 50; uchar* buffer1 = new uchar[sizeof(Track_Struct)]; Track_Struct* track_ent = (Track_Struct*) buffer1; uchar* buffer2 = new uchar[sizeof(Track_Struct)*spe]; Tracking_Struct* track_array = (Tracking_Struct*) buffer2; memset(track_array, 0, sizeof(Track_Struct)*spe); uint32 array_counter = 0; LinkedListIterator iterator(mob_list); iterator.Reset(); Group *g = client->GetGroup(); while(iterator.MoreElements()) { if (iterator.GetData() && ((MobDistance = iterator.GetData()->DistNoZ(*client))<=distance)) { if((iterator.GetData() != client) && iterator.GetData()->IsTrackable()) { memset(track_ent, 0, sizeof(Track_Struct)); Mob* cur_entity = iterator.GetData(); track_ent->entityid = cur_entity->GetID(); track_ent->distance = MobDistance; track_ent->level = cur_entity->GetLevel(); track_ent->NPC = !cur_entity->IsClient(); if(g && cur_entity->IsClient() && g->IsGroupMember(cur_entity->CastToMob())) track_ent->GroupMember = 1; else track_ent->GroupMember = 0; strn0cpy(track_ent->name, cur_entity->GetName(), sizeof(track_ent->name)); memcpy(&track_array->Entrys[array_counter], track_ent, sizeof(Track_Struct)); array_counter++; } } iterator.Advance(); } if(array_counter <= spe) { EQApplicationPacket* outapp = new EQApplicationPacket(OP_Track,sizeof(Track_Struct)*(array_counter)); memcpy(outapp->pBuffer, track_array,sizeof(Track_Struct)*(array_counter)); outapp->priority = 6; client->QueuePacket(outapp); safe_delete(outapp); ret = true; } else { LogFile->write(EQEMuLog::Status, "ERROR: Unable to transmit a Tracking_Struct packet. Mobs in zone = %i. Mobs in packet = %i", array_counter, spe); } safe_delete_array(buffer1); safe_delete_array(buffer2); return ret; } void EntityList::MessageGroup(Mob* sender, bool skipclose, uint32 type, const char* message, ...) { va_list argptr; char buffer[4096]; va_start(argptr, message); vsnprintf(buffer, 4095, message, argptr); va_end(argptr); float dist2 = 100; if (skipclose) dist2 = 0; LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData() != sender && (iterator.GetData()->Dist(*sender) <= dist2 || iterator.GetData()->GetGroup() == sender->CastToClient()->GetGroup())) { iterator.GetData()->Message(type, buffer); } iterator.Advance(); } } bool EntityList::Fighting(Mob* targ) { LinkedListIterator iterator(npc_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->CheckAggro(targ)) { return true; } iterator.Advance(); } return false; } void EntityList::AddHealAggro(Mob* target, Mob* caster, uint16 thedam) { LinkedListIterator iterator(npc_list); iterator.Reset(); NPC *cur = NULL; uint16 count = 0; while(iterator.MoreElements()) { cur = iterator.GetData(); if(!cur->CheckAggro(target)) { iterator.Advance(); continue; } if (!cur->IsMezzed() && !cur->IsStunned() && !cur->IsFeared()) { ++count; } iterator.Advance(); } if(thedam > 1) { if(count > 0) thedam = (thedam / count); if(thedam < 1) thedam = 1; } cur = NULL; iterator.Reset(); while(iterator.MoreElements()) { cur = iterator.GetData(); if(!cur->CheckAggro(target)){ iterator.Advance(); continue; } if (!cur->IsMezzed() && !cur->IsStunned() && !cur->IsFeared()) { if(cur->IsPet()){ if(caster){ if(cur->CheckAggro(caster)) { cur->AddToHateList(caster, thedam); } } } else{ if(caster){ if(cur->CheckAggro(caster)) { cur->AddToHateList(caster, thedam); } else { cur->AddToHateList(caster, thedam*0.33); } } } } iterator.Advance(); } } void EntityList::OpenDoorsNear(NPC* who) { LinkedListIterator iterator(door_list); iterator.Reset(); while(iterator.MoreElements()) { Doors *cdoor = iterator.GetData(); if(cdoor && !cdoor->IsDoorOpen()) { float zdiff = who->GetZ() - cdoor->GetZ(); if(zdiff < 0) zdiff = 0 - zdiff; float curdist = 0; float tmp = who->GetX() - cdoor->GetX(); curdist += tmp * tmp; tmp = who->GetY() - cdoor->GetY(); curdist += tmp * tmp; if (zdiff < 10 && curdist <= 100) { cdoor->NPCOpen(who); } } iterator.Advance(); } } void EntityList::SendAlarm(Trap* trap, Mob* currenttarget, uint8 kos) { LinkedListIterator iterator(npc_list); iterator.Reset(); float val2 = trap->effectvalue * trap->effectvalue; while(iterator.MoreElements()) { NPC *cur = iterator.GetData(); float curdist = 0; float tmp = cur->GetX() - trap->x; curdist += tmp*tmp; tmp = cur->GetY() - trap->y; curdist += tmp*tmp; tmp = cur->GetZ() - trap->z; curdist += tmp*tmp; if (!cur->GetOwner() && /*!cur->CastToMob()->dead && */ !cur->IsEngaged() && curdist <= val2 ) { if(kos) { uint8 factioncon = currenttarget->GetReverseFactionCon(cur); if(factioncon == FACTION_THREATENLY || factioncon == FACTION_SCOWLS) { cur->AddToHateList(currenttarget,1); } } else { cur->AddToHateList(currenttarget,1); } } iterator.Advance(); } } void EntityList::AddProximity(NPC *proximity_for) { RemoveProximity(proximity_for->GetID()); proximity_list.Insert(proximity_for); proximity_for->proximity = new NPCProximity; } bool EntityList::RemoveProximity(uint16 delete_npc_id) { LinkedListIterator iterator(proximity_list); iterator.Reset(); while(iterator.MoreElements()) { NPC *d = iterator.GetData(); if(d->GetID() == delete_npc_id) { //safe_delete(d->proximity); iterator.RemoveCurrent(false); return true; } iterator.Advance(); } return false; } void EntityList::RemoveAllLocalities() { LinkedListIterator iterator(proximity_list); iterator.Reset(); while(iterator.MoreElements()) iterator.RemoveCurrent(false); } void EntityList::ProcessMove(Client *c, float x, float y, float z) { /* We look through each proximity, looking to see if last_* was in(out) the proximity, and the new supplied coords are out(in)... */ LinkedListIterator iterator(proximity_list); std::list skip_ids; float last_x = c->ProximityX(); float last_y = c->ProximityY(); float last_z = c->ProximityZ(); for(iterator.Reset(); iterator.MoreElements(); iterator.Advance()) { NPC *d = iterator.GetData(); NPCProximity *l = d->proximity; if(l == NULL) continue; //This is done to address the issue of this code not being reentrant //because perl can call clear_proximity() while we're still iterating through the list //This causes our list to become invalid but we don't know it. On GCC it's basic heap //corruption and it doesn't appear to catch it at all. //MSVC it's a crash with 0xfeeefeee debug address (freed memory off the heap) std::list::iterator iter = skip_ids.begin(); bool skip = false; while(iter != skip_ids.end()) { if(d->GetID() == (*iter)) { skip = true; break; } iter++; } if(skip) { continue; } //check both bounding boxes, if either coords pairs //cross a boundary, send the event. bool old_in = true; bool new_in = true; if( last_x < l->min_x || last_x > l->max_x || last_y < l->min_y || last_y > l->max_y || last_z < l->min_z || last_z > l->max_z ) { old_in = false; } if( x < l->min_x || x > l->max_x || y < l->min_y || y > l->max_y || z < l->min_z || z > l->max_z ) { new_in = false; } if(old_in && !new_in) { //we were in the proximity, we are no longer, send event exit parse->EventNPC(EVENT_EXIT, d, c, "", 0); //Reentrant fix iterator.Reset(); skip_ids.push_back(d->GetID()); } else if(new_in && !old_in) { //we were not in the proximity, we are now, send enter event parse->EventNPC(EVENT_ENTER, d, c, "", 0); //Reentrant fix iterator.Reset(); skip_ids.push_back(d->GetID()); } } } void EntityList::ProcessProximitySay(const char *Message, Client *c, uint8 language) { if(!Message || !c) return; LinkedListIterator iterator(proximity_list); for(iterator.Reset(); iterator.MoreElements(); iterator.Advance()) { NPC *d = iterator.GetData(); NPCProximity *l = d->proximity; if(l == NULL || !l->say) continue; if( c->GetX() < l->min_x || c->GetX() > l->max_x || c->GetY() < l->min_y || c->GetY() > l->max_y || c->GetZ() < l->min_z || c->GetZ() > l->max_z ) continue; parse->EventNPC(EVENT_PROXIMITY_SAY, d, c, Message, language); } } void EntityList::SaveAllClientsTaskState() { if(!taskmanager) return; LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { Client* client = iterator.GetData(); if(client->IsTaskStateLoaded()) { client->SaveTaskState(); } iterator.Advance(); } } void EntityList::ReloadAllClientsTaskState(int TaskID) { if(!taskmanager) return; LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { Client* client = iterator.GetData(); if(client->IsTaskStateLoaded()) { // If we have been passed a TaskID, only reload the client state if they have // that Task active. if((!TaskID) || (TaskID && client->IsTaskActive(TaskID))) { _log(TASKS__CLIENTLOAD, "Reloading Task State For Client %s", client->GetName()); client->RemoveClientTaskState(); client->LoadClientTaskState(); taskmanager->SendActiveTasksToClient(client); } } iterator.Advance(); } } bool EntityList::IsMobInZone(Mob *who) { LinkedListIterator iterator(mob_list); iterator.Reset(); while(iterator.MoreElements()) { if(who == iterator.GetData()) return(true); iterator.Advance(); } return(false); } /* Code to limit the ammount of certain NPCs in a given zone. Primarily used to make a named mob unique within the zone, but written to be more generic allowing limits larger than 1. Maintain this stuff in a seperate list since the number of limited NPCs will most likely be much smaller than the number of NPCs in the entire zone. */ void EntityList::LimitAddNPC(NPC *npc) { if(!npc) return; SpawnLimitRecord r; uint16 eid = npc->GetID(); r.spawngroup_id = npc->GetSp2(); r.npc_type = npc->GetNPCTypeID(); npc_limit_list[eid] = r; } void EntityList::LimitRemoveNPC(NPC *npc) { if(!npc) return; uint16 eid = npc->GetID(); npc_limit_list.erase(eid); } //check a limit over the entire zone. //returns true if the limit has not been reached bool EntityList::LimitCheckType(uint32 npc_type, int count) { if(count < 1) return(true); map::iterator cur,end; cur = npc_limit_list.begin(); end = npc_limit_list.end(); for(; cur != end; cur++) { if(cur->second.npc_type == npc_type) { count--; if(count == 0) { return(false); } } } return(true); } //check limits on an npc type in a given spawn group. //returns true if the limit has not been reached bool EntityList::LimitCheckGroup(uint32 spawngroup_id, int count) { if(count < 1) return(true); map::iterator cur,end; cur = npc_limit_list.begin(); end = npc_limit_list.end(); for(; cur != end; cur++) { if(cur->second.spawngroup_id == spawngroup_id) { count--; if(count == 0) { return(false); } } } return(true); } //check limits on an npc type in a given spawn group, and //checks limits on the entire zone in one pass. //returns true if neither limit has been reached bool EntityList::LimitCheckBoth(uint32 npc_type, uint32 spawngroup_id, int group_count, int type_count) { if(group_count < 1 && type_count < 1) return(true); map::iterator cur,end; cur = npc_limit_list.begin(); end = npc_limit_list.end(); for(; cur != end; cur++) { if(cur->second.npc_type == npc_type) { type_count--; if(type_count == 0) { return(false); } } if(cur->second.spawngroup_id == spawngroup_id) { group_count--; if(group_count == 0) { return(false); } } } return(true); } bool EntityList::LimitCheckName(const char *npc_name) { LinkedListIterator iterator(npc_list); iterator.Reset(); while(iterator.MoreElements()) { NPC* npc = iterator.GetData(); if(npc) { if(strcasecmp(npc_name, npc->GetRawNPCTypeName()) == 0) { return false; } } iterator.Advance(); } return true; } void EntityList::RadialSetLogging(Mob *around, bool enabled, bool clients, bool non_clients, float range) { float range2 = range * range; LinkedListIterator iterator(mob_list); iterator.Reset(); while(iterator.MoreElements()) { Mob* mob = iterator.GetData(); iterator.Advance(); if(mob->IsClient()) { if(!clients) continue; } else { if(!non_clients) continue; } if(around->DistNoRoot(*mob) > range2) continue; if(enabled) mob->EnableLogging(); else mob->DisableLogging(); } } void EntityList::UpdateHoTT(Mob* target) { LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { Client* c = iterator.GetData(); if (c->GetTarget() == target) { if (target->GetTarget()) c->SetHoTT(target->GetTarget()->GetID()); else c->SetHoTT(0); c->UpdateXTargetType(TargetsTarget, target->GetTarget()); } iterator.Advance(); } } void EntityList::DestroyTempPets(Mob *owner) { LinkedListIterator iterator(npc_list); iterator.Reset(); while(iterator.MoreElements()) { NPC* n = iterator.GetData(); if(n->GetSwarmInfo()) { if(n->GetSwarmInfo()->owner_id == owner->GetID()) { n->Depop(); } } iterator.Advance(); } } bool Entity::CheckCoordLosNoZLeaps(float cur_x, float cur_y, float cur_z, float trg_x, float trg_y, float trg_z, float perwalk) { if(zone->zonemap == NULL) { return(true); } VERTEX myloc; VERTEX oloc; VERTEX hit; myloc.x = cur_x; myloc.y = cur_y; myloc.z = cur_z+5; oloc.x = trg_x; oloc.y = trg_y; oloc.z = trg_z+5; if (myloc.x == oloc.x && myloc.y == oloc.y && myloc.z == oloc.z) return true; FACE *onhit; if (!zone->zonemap->LineIntersectsZoneNoZLeaps(myloc,oloc,perwalk,&hit,&onhit)) return true; return false; } void EntityList::QuestJournalledSayClose(Mob *sender, Client *QuestInitiator, float dist, const char* mobname, const char* message) { Client *c; LinkedListIterator iterator(client_list); float dist2 = dist * dist; // Send the message to the quest initiator such that the client will enter it into the NPC Quest Journal if(QuestInitiator) { char *buf = new char[strlen(mobname) + strlen(message) + 10]; sprintf(buf, "%s says, '%s'", mobname, message); QuestInitiator->QuestJournalledMessage(mobname, buf); safe_delete_array(buf); } // Use the old method for all other nearby clients for(iterator.Reset(); iterator.MoreElements(); iterator.Advance()) { c = iterator.GetData(); if(c && (c != QuestInitiator) && c->DistNoRoot(*sender) <= dist2) c->Message_StringID(10, GENERIC_SAY, mobname, message); } } Corpse* EntityList::GetClosestCorpse(Mob* sender, const char* Name) { if(!sender) return NULL; uint32 CurrentDistance, ClosestDistance = 4294967295u; Corpse *CurrentCorpse, *ClosestCorpse = NULL; LinkedListIterator iterator(corpse_list); iterator.Reset(); while(iterator.MoreElements()) { CurrentCorpse = iterator.GetData(); iterator.Advance(); if(Name && strcasecmp(CurrentCorpse->GetOwnerName(), Name)) continue; CurrentDistance = ((CurrentCorpse->GetY() - sender->GetY()) * (CurrentCorpse->GetY() - sender->GetY())) + ((CurrentCorpse->GetX() - sender->GetX()) * (CurrentCorpse->GetX() - sender->GetX())); if(CurrentDistance < ClosestDistance) { ClosestDistance = CurrentDistance; ClosestCorpse = CurrentCorpse; } } return ClosestCorpse; } void EntityList::ForceGroupUpdate(uint32 gid) { LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { if(iterator.GetData()){ Group *g = NULL; g = iterator.GetData()->GetGroup(); if(g){ if(g->GetID() == gid) { database.RefreshGroupFromDB(iterator.GetData()); } } } iterator.Advance(); } } void EntityList::SendGroupLeave(uint32 gid, const char *name) { LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { Client *c = iterator.GetData(); if(c){ Group *g = NULL; g = c->GetGroup(); if(g){ if(g->GetID() == gid) { EQApplicationPacket* outapp = new EQApplicationPacket(OP_GroupUpdate,sizeof(GroupJoin_Struct)); GroupJoin_Struct* gj = (GroupJoin_Struct*) outapp->pBuffer; strcpy(gj->membername, name); gj->action = groupActLeave; strcpy(gj->yourname, c->GetName()); Mob *Leader = g->GetLeader(); if(Leader) Leader->CastToClient()->GetGroupAAs(&gj->leader_aas); c->QueuePacket(outapp); safe_delete(outapp); g->DelMemberOOZ(name); if(g->IsLeader(c) && c->IsLFP()) c->UpdateLFP(); } } } iterator.Advance(); } } void EntityList::SendGroupJoin(uint32 gid, const char *name) { LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { if(iterator.GetData()){ Group *g = NULL; g = iterator.GetData()->GetGroup(); if(g){ if(g->GetID() == gid) { EQApplicationPacket* outapp = new EQApplicationPacket(OP_GroupUpdate,sizeof(GroupJoin_Struct)); GroupJoin_Struct* gj = (GroupJoin_Struct*) outapp->pBuffer; strcpy(gj->membername, name); gj->action = groupActJoin; strcpy(gj->yourname, iterator.GetData()->GetName()); Mob *Leader = g->GetLeader(); if(Leader) Leader->CastToClient()->GetGroupAAs(&gj->leader_aas); iterator.GetData()->QueuePacket(outapp); safe_delete(outapp); } } } iterator.Advance(); } } void EntityList::GroupMessage(uint32 gid, const char *from, const char *message) { LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { if(iterator.GetData()){ Group *g = NULL; g = iterator.GetData()->GetGroup(); if(g){ if(g->GetID() == gid) { iterator.GetData()->ChannelMessageSend(from, iterator.GetData()->GetName(),2,0,message); } } } iterator.Advance(); } } uint16 EntityList::CreateGroundObject(uint32 itemid, float x, float y, float z, float heading, uint32 decay_time) { const Item_Struct* is = database.GetItem(itemid); if(is) { ItemInst *i = new ItemInst(is, is->MaxCharges); if(i) { Object* object = new Object(i,x,y,z,heading,decay_time); entity_list.AddObject(object, true); safe_delete(i); if(object) return object->GetID(); } return 0; // fell through itemstruct } return 0; // fell through everything, this is bad/incomplete from perl } uint16 EntityList::CreateGroundObjectFromModel(const char *model, float x, float y, float z, float heading, uint8 type, uint32 decay_time) { if(model) { Object* object = new Object(model,x,y,z,heading,type); entity_list.AddObject(object, true); if(object) return object->GetID(); } return 0; // fell through everything, this is bad/incomplete from perl } uint16 EntityList::CreateDoor(const char *model, float x, float y, float z, float heading, uint8 opentype, uint16 size) { if(model) { Doors* door = new Doors(model,x,y,z,heading,opentype, size); RemoveAllDoors(); zone->LoadZoneDoors(zone->GetShortName(), zone->GetInstanceVersion()); entity_list.AddDoor(door); entity_list.RespawnAllDoors(); if(door) return door->GetEntityID(); } return 0; // fell through everything, this is bad/incomplete from perl } Mob* EntityList::GetTargetForMez(Mob* caster) { if(!caster) return NULL; LinkedListIterator iterator(mob_list); iterator.Reset(); //TODO: make this smarter and not mez targets being damaged by dots while(iterator.MoreElements()) { Mob* d = iterator.GetData(); if(d){ if(d == caster){ //caster can't pick himself iterator.Advance(); continue; } if(caster->GetTarget() == d){ //caster can't pick his target iterator.Advance(); continue; } if(!caster->CheckAggro(d)){ //caster can't pick targets that aren't aggroed on himself iterator.Advance(); continue; } if(caster->DistNoRoot(*d) > 22250){ //only pick targets within 150 range iterator.Advance(); continue; } if(!caster->CheckLosFN(d)){ //this is wasteful but can't really think of another way to do it iterator.Advance(); //that wont have us trying to los the same target every time continue; //it's only in combat so it's impact should be minimal.. but stil. } return d; } iterator.Advance(); } return NULL; } void EntityList::SendZoneAppearance(Client *c) { if(!c) return; LinkedListIterator iterator(mob_list); iterator.Reset(); while(iterator.MoreElements()) { Mob *cur = iterator.GetData(); if(cur) { if(cur == c) { iterator.Advance(); continue; } if(cur->GetAppearance() != eaStanding) { cur->SendAppearancePacket(AT_Anim, cur->GetAppearanceValue(cur->GetAppearance()), false, true, c); } if(cur->GetSize() != cur->GetBaseSize()) { cur->SendAppearancePacket(AT_Size, (uint32)cur->GetSize(), false, true, c); } } iterator.Advance(); } } void EntityList::SendNimbusEffects(Client *c) { if(!c) return; LinkedListIterator iterator(mob_list); iterator.Reset(); while(iterator.MoreElements()) { Mob *cur = iterator.GetData(); if(cur) { if(cur == c) { iterator.Advance(); continue; } if(cur->GetNimbusEffect1() != 0) { cur->SendSpellEffect(cur->GetNimbusEffect1(), 1000, 0, 1, 3000, false, c); } if(cur->GetNimbusEffect2() != 0) { cur->SendSpellEffect(cur->GetNimbusEffect2(), 2000, 0, 1, 3000, false, c); } if(cur->GetNimbusEffect3() != 0) { cur->SendSpellEffect(cur->GetNimbusEffect3(), 3000, 0, 1, 3000, false, c); } } iterator.Advance(); } } void EntityList::SendUntargetable(Client *c) { if(!c) return; LinkedListIterator iterator(mob_list); iterator.Reset(); while(iterator.MoreElements()) { Mob *cur = iterator.GetData(); if(cur) { if(cur == c) { iterator.Advance(); continue; } if(!cur->IsTargetable()) { cur->SendTargetable(false, c); } } iterator.Advance(); } } void EntityList::ZoneWho(Client *c, Who_All_Struct* Who) { // This is only called for SoF clients, as regular /who is now handled server-side for that client. // uint32 PacketLength = 0; uint32 Entries = 0; uint8 WhomLength = strlen(Who->whom); LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { Client *ClientEntry = iterator.GetData(); iterator.Advance(); if(ClientEntry) { if(ClientEntry->GMHideMe(c)) continue; if((Who->wrace != 0xFFFFFFFF) && (ClientEntry->GetRace() != Who->wrace)) continue; if((Who->wclass != 0xFFFFFFFF) && (ClientEntry->GetClass() != Who->wclass)) continue; if((Who->lvllow != 0xFFFFFFFF) && (ClientEntry->GetLevel() < Who->lvllow)) continue; if((Who->lvlhigh != 0xFFFFFFFF) && (ClientEntry->GetLevel() > Who->lvlhigh)) continue; if(Who->guildid != 0xFFFFFFFF) { if((Who->guildid == 0xFFFFFFFC) && !ClientEntry->IsTrader()) continue; if((Who->guildid == 0xFFFFFFFB) && !ClientEntry->IsBuyer()) continue; if(Who->guildid != ClientEntry->GuildID()) continue; } if(WhomLength && strncasecmp(Who->whom, ClientEntry->GetName(), WhomLength) && strncasecmp(guild_mgr.GetGuildName(ClientEntry->GuildID()), Who->whom, WhomLength)) continue; Entries++; PacketLength = PacketLength + strlen(ClientEntry->GetName()); if(strlen(guild_mgr.GetGuildName(ClientEntry->GuildID())) > 0) PacketLength = PacketLength + strlen(guild_mgr.GetGuildName(ClientEntry->GuildID())) + 2; } } PacketLength = PacketLength + sizeof(WhoAllReturnStruct) + (47 * Entries); EQApplicationPacket* outapp = new EQApplicationPacket(OP_WhoAllResponse, PacketLength); char *Buffer = (char *)outapp->pBuffer; WhoAllReturnStruct *WARS = (WhoAllReturnStruct *)Buffer; WARS->id = 0; WARS->playerineqstring = 5001; strncpy(WARS->line, "---------------------------", sizeof(WARS->line)); WARS->unknown35 = 0x0a; WARS->unknown36 = 0; switch(Entries) { case 0: WARS->playersinzonestring = 5029; break; case 1: WARS->playersinzonestring = 5028; // 5028 There is %1 player in EverQuest. break; default: WARS->playersinzonestring = 5036; // 5036 There are %1 players in EverQuest. } WARS->unknown44[0] = 0; WARS->unknown44[1] = 0; WARS->unknown52 = Entries; WARS->unknown56 = Entries; WARS->playercount = Entries; Buffer += sizeof(WhoAllReturnStruct); iterator.Reset(); while(iterator.MoreElements()) { Client *ClientEntry = iterator.GetData(); iterator.Advance(); if(ClientEntry) { if(ClientEntry->GMHideMe(c)) continue; if((Who->wrace != 0xFFFFFFFF) && (ClientEntry->GetRace() != Who->wrace)) continue; if((Who->wclass != 0xFFFFFFFF) && (ClientEntry->GetClass() != Who->wclass)) continue; if((Who->lvllow != 0xFFFFFFFF) && (ClientEntry->GetLevel() < Who->lvllow)) continue; if((Who->lvlhigh != 0xFFFFFFFF) && (ClientEntry->GetLevel() > Who->lvlhigh)) continue; if(Who->guildid != 0xFFFFFFFF) { if((Who->guildid == 0xFFFFFFFC) && !ClientEntry->IsTrader()) continue; if((Who->guildid == 0xFFFFFFFB) && !ClientEntry->IsBuyer()) continue; if(Who->guildid != ClientEntry->GuildID()) continue; } if(WhomLength && strncasecmp(Who->whom, ClientEntry->GetName(), WhomLength) && strncasecmp(guild_mgr.GetGuildName(ClientEntry->GuildID()), Who->whom, WhomLength)) continue; string GuildName; if((ClientEntry->GuildID() != GUILD_NONE) && (ClientEntry->GuildID() > 0)) { GuildName = "<"; GuildName += guild_mgr.GetGuildName(ClientEntry->GuildID()); GuildName += ">"; } uint32 FormatMSGID=5025; // 5025 %T1[%2 %3] %4 (%5) %6 %7 %8 %9 if(ClientEntry->GetAnon() == 1) FormatMSGID = 5024; // 5024 %T1[ANONYMOUS] %2 %3 else if(ClientEntry->GetAnon() == 2) FormatMSGID = 5023; // 5023 %T1[ANONYMOUS] %2 %3 %4 uint32 PlayerClass = 0; uint32 PlayerLevel = 0; uint32 PlayerRace = 0; uint32 ZoneMSGID = 0xFFFFFFFF; if(ClientEntry->GetAnon()==0) { PlayerClass = ClientEntry->GetClass(); PlayerLevel = ClientEntry->GetLevel(); PlayerRace = ClientEntry->GetRace(); } WhoAllPlayerPart1* WAPP1 = (WhoAllPlayerPart1*)Buffer; WAPP1->FormatMSGID = FormatMSGID; WAPP1->PIDMSGID = 0xFFFFFFFF; strcpy(WAPP1->Name, ClientEntry->GetName()); Buffer += sizeof(WhoAllPlayerPart1) + strlen(WAPP1->Name); WhoAllPlayerPart2* WAPP2 = (WhoAllPlayerPart2*)Buffer; if(ClientEntry->IsTrader()) WAPP2->RankMSGID = 12315; else if(ClientEntry->IsBuyer()) WAPP2->RankMSGID = 6056; else if(ClientEntry->Admin() >= 10) WAPP2->RankMSGID = 12312; else WAPP2->RankMSGID = 0xFFFFFFFF; strcpy(WAPP2->Guild, GuildName.c_str()); Buffer += sizeof(WhoAllPlayerPart2) + strlen(WAPP2->Guild); WhoAllPlayerPart3* WAPP3 = (WhoAllPlayerPart3*)Buffer; WAPP3->Unknown80[0] = 0xFFFFFFFF; if(ClientEntry->IsLD()) WAPP3->Unknown80[1] = 12313; // LinkDead else WAPP3->Unknown80[1] = 0xFFFFFFFF; WAPP3->ZoneMSGID = ZoneMSGID; WAPP3->Zone = 0; WAPP3->Class_ = PlayerClass; WAPP3->Level = PlayerLevel; WAPP3->Race = PlayerRace; WAPP3->Account[0] = 0; Buffer += sizeof(WhoAllPlayerPart3); WhoAllPlayerPart4* WAPP4 = (WhoAllPlayerPart4*)Buffer; WAPP4->Unknown100 = 0; Buffer += sizeof(WhoAllPlayerPart4); } } c->QueuePacket(outapp); safe_delete(outapp); } void EntityList::UnMarkNPC(uint16 ID) { // Designed to be called from the Mob destructor, this method calls Group::UnMarkNPC for // each group to remove the dead mobs entity ID from the groups list of NPCs marked via the // Group Leadership AA Mark NPC ability. // LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { if(iterator.GetData()) { Group *g = NULL; g = iterator.GetData()->GetGroup(); if(g) g->UnMarkNPC(ID); } iterator.Advance(); } } uint32 EntityList::CheckNPCsClose(Mob *center) { LinkedListIterator iterator(npc_list); uint32 count = 0; iterator.Reset(); while(iterator.MoreElements()) { NPC *current = iterator.GetData(); if(!current) { iterator.Advance(); continue; } if(current == center) { iterator.Advance(); continue; } if(current->IsPet()) { iterator.Advance(); continue; } if(current->GetClass() == LDON_TREASURE) { iterator.Advance(); continue; } if(current->GetBodyType() == BT_NoTarget || current->GetBodyType() == BT_Special) { iterator.Advance(); continue; } float xDiff = current->GetX() - center->GetX(); float yDiff = current->GetY() - center->GetY(); float zDiff = current->GetZ() - center->GetZ(); float dist = ((xDiff * xDiff) + (yDiff * yDiff) + (zDiff * zDiff)); if(dist <= RuleR(Adventure, DistanceForRescueAccept)) { count++; } iterator.Advance(); } return count; } void EntityList::GateAllClients() { LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { Client *c = iterator.GetData(); if(c) { c->GoToBind(); } iterator.Advance(); } } void EntityList::SignalAllClients(uint32 data) { LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { Client *ent = iterator.GetData(); if(ent) { ent->Signal(data); } iterator.Advance(); } } void EntityList::GetMobList(list &m_list) { m_list.clear(); LinkedListIterator iterator(mob_list); iterator.Reset(); while(iterator.MoreElements()) { Mob *ent = iterator.GetData(); m_list.push_back(ent); iterator.Advance(); } } void EntityList::GetNPCList(list &n_list) { n_list.clear(); LinkedListIterator iterator(npc_list); iterator.Reset(); while(iterator.MoreElements()) { NPC *ent = iterator.GetData(); n_list.push_back(ent); iterator.Advance(); } } void EntityList::GetClientList(list &c_list) { c_list.clear(); LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { Client *ent = iterator.GetData(); c_list.push_back(ent); iterator.Advance(); } } void EntityList::GetCorpseList(list &c_list) { c_list.clear(); LinkedListIterator iterator(corpse_list); iterator.Reset(); while(iterator.MoreElements()) { Corpse *ent = iterator.GetData(); c_list.push_back(ent); iterator.Advance(); } } void EntityList::GetObjectList(list &o_list) { o_list.clear(); LinkedListIterator iterator(object_list); iterator.Reset(); while(iterator.MoreElements()) { Object *ent = iterator.GetData(); o_list.push_back(ent); iterator.Advance(); } } void EntityList::GetDoorsList(list &o_list) { o_list.clear(); LinkedListIterator iterator(door_list); iterator.Reset(); while(iterator.MoreElements()) { Doors *ent = iterator.GetData(); o_list.push_back(ent); iterator.Advance(); } } void EntityList::UpdateQGlobal(uint32 qid, QGlobal newGlobal) { LinkedListIterator iterator(mob_list); iterator.Reset(); while(iterator.MoreElements()) { Mob *ent = iterator.GetData(); if(ent->IsClient()) { QGlobalCache *qgc = ent->CastToClient()->GetQGlobals(); if(qgc) { uint32 char_id = ent->CastToClient()->CharacterID(); if(newGlobal.char_id == char_id && newGlobal.npc_id == 0) { qgc->AddGlobal(qid, newGlobal); } } } else if(ent->IsNPC()) { QGlobalCache *qgc = ent->CastToNPC()->GetQGlobals(); if(qgc) { uint32 npc_id = ent->GetNPCTypeID(); if(newGlobal.npc_id == npc_id) { qgc->AddGlobal(qid, newGlobal); } } } iterator.Advance(); } } void EntityList::DeleteQGlobal(std::string name, uint32 npcID, uint32 charID, uint32 zoneID) { LinkedListIterator iterator(mob_list); iterator.Reset(); while(iterator.MoreElements()) { Mob *ent = iterator.GetData(); if(ent->IsClient()) { QGlobalCache *qgc = ent->CastToClient()->GetQGlobals(); if(qgc) { qgc->RemoveGlobal(name, npcID, charID, zoneID); } } else if(ent->IsNPC()) { QGlobalCache *qgc = ent->CastToNPC()->GetQGlobals(); if(qgc) { qgc->RemoveGlobal(name, npcID, charID, zoneID); } } iterator.Advance(); } } void EntityList::SendFindableNPCList(Client *c) { if(!c) return; EQApplicationPacket* outapp = new EQApplicationPacket(OP_SendFindableNPCs, sizeof(FindableNPC_Struct)); FindableNPC_Struct *fnpcs = (FindableNPC_Struct *)outapp->pBuffer; fnpcs->Unknown109 = 0x16; fnpcs->Unknown110 = 0x06; fnpcs->Unknown111 = 0x24; fnpcs->Action = 0; LinkedListIterator iterator(npc_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()) { NPC *n = iterator.GetData(); if(n->IsFindable()) { fnpcs->EntityID = n->GetID(); strn0cpy(fnpcs->Name, n->GetCleanName(), sizeof(fnpcs->Name)); strn0cpy(fnpcs->LastName, n->GetLastName(), sizeof(fnpcs->LastName)); fnpcs->Race = n->GetRace(); fnpcs->Class = n->GetClass(); c->QueuePacket(outapp); } } iterator.Advance(); } safe_delete(outapp); } void EntityList::UpdateFindableNPCState(NPC *n, bool Remove) { if(!n || !n->IsFindable()) return; EQApplicationPacket* outapp = new EQApplicationPacket(OP_SendFindableNPCs, sizeof(FindableNPC_Struct)); FindableNPC_Struct *fnpcs = (FindableNPC_Struct *)outapp->pBuffer; fnpcs->Unknown109 = 0x16; fnpcs->Unknown110 = 0x06; fnpcs->Unknown111 = 0x24; fnpcs->Action = Remove ? 1: 0; fnpcs->EntityID = n->GetID(); strn0cpy(fnpcs->Name, n->GetCleanName(), sizeof(fnpcs->Name)); strn0cpy(fnpcs->LastName, n->GetLastName(), sizeof(fnpcs->LastName)); fnpcs->Race = n->GetRace(); fnpcs->Class = n->GetClass(); LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { Client *c = iterator.GetData(); if(c && (c->GetClientVersion() >= EQClientSoD)) c->QueuePacket(outapp); iterator.Advance(); } safe_delete(outapp); } void EntityList::HideCorpses(Client *c, uint8 CurrentMode, uint8 NewMode) { if(!c) return; if(NewMode == HideCorpseNone) { SendZoneCorpses(c); return; } Group *g = NULL; if(NewMode == HideCorpseAllButGroup) { g = c->GetGroup(); if(!g) NewMode = HideCorpseAll; } LinkedListIterator iterator(corpse_list); iterator.Reset(); while(iterator.MoreElements()) { Corpse *b = iterator.GetData(); if(b && (b->GetCharID() != c->CharacterID())) { if((NewMode == HideCorpseAll) || ((NewMode == HideCorpseNPC) && (b->IsNPCCorpse()))) { EQApplicationPacket outapp; b->CreateDespawnPacket(&outapp, false); c->QueuePacket(&outapp); } else if(NewMode == HideCorpseAllButGroup) { if(!g->IsGroupMember(b->GetOwnerName())) { EQApplicationPacket outapp; b->CreateDespawnPacket(&outapp, false); c->QueuePacket(&outapp); } else if((CurrentMode == HideCorpseAll)) { EQApplicationPacket outapp; b->CreateSpawnPacket(&outapp); c->QueuePacket(&outapp); } } } iterator.Advance(); } } void EntityList::AddLootToNPCS(uint32 item_id, uint32 count) { if(count == 0) return; int npc_count = 0; LinkedListIterator iterator(npc_list); iterator.Reset(); while(iterator.MoreElements()) { if(!iterator.GetData()->IsPet() && iterator.GetData()->GetClass() != LDON_TREASURE && iterator.GetData()->GetBodyType() != BT_NoTarget && iterator.GetData()->GetBodyType() != BT_NoTarget2 && iterator.GetData()->GetBodyType() != BT_Special) { npc_count++; } iterator.Advance(); } if(npc_count == 0) { return; } NPC **npcs = new NPC*[npc_count]; int *counts = new int[npc_count]; bool *marked = new bool[npc_count]; memset(counts, 0, sizeof(int) * npc_count); memset(marked, 0, sizeof(bool) * npc_count); int i = 0; iterator.Reset(); while(iterator.MoreElements()) { if(!iterator.GetData()->IsPet() && iterator.GetData()->GetClass() != LDON_TREASURE && iterator.GetData()->GetBodyType() != BT_NoTarget && iterator.GetData()->GetBodyType() != BT_NoTarget2 && iterator.GetData()->GetBodyType() != BT_Special) { npcs[i++] = iterator.GetData(); } iterator.Advance(); } while(count > 0) { vector selection; selection.reserve(npc_count); for(int j = 0; j < npc_count; ++j) { selection.push_back(j); } while(selection.size() > 0 && count > 0) { int k = MakeRandomInt(0, selection.size() - 1); counts[selection[k]]++; count--; selection.erase(selection.begin() + k); } } for(int j = 0; j < npc_count; ++j) { if(counts[j] > 0) { for(int k = 0; k < counts[j]; ++k) { npcs[j]->AddItem(item_id, 1); } } } safe_delete_array(npcs); safe_delete_array(counts); safe_delete_array(marked); } void EntityList::CameraEffect(uint32 duration, uint32 intensity) { EQApplicationPacket* outapp = new EQApplicationPacket(OP_CameraEffect, sizeof(Camera_Struct)); memset(outapp->pBuffer, 0, sizeof(outapp->pBuffer)); Camera_Struct* cs = (Camera_Struct*) outapp->pBuffer; cs->duration = duration; // Duration in milliseconds cs->intensity = ((intensity * 6710886) + 1023410176); // Intensity ranges from 1023410176 to 1090519040, so simplify it from 0 to 10. entity_list.QueueClients(0, outapp); safe_delete(outapp); } NPC* EntityList::GetClosestBanker(Mob* sender, uint32 &distance) { if(!sender) return NULL; distance = 4294967295u; NPC* nc = NULL; LinkedListIterator iterator(npc_list); iterator.Reset(); while(iterator.MoreElements()) { if(iterator.GetData()->GetClass() == BANKER) { uint32 nd = ((iterator.GetData()->GetY() - sender->GetY()) * (iterator.GetData()->GetY() - sender->GetY())) + ((iterator.GetData()->GetX() - sender->GetX()) * (iterator.GetData()->GetX() - sender->GetX())); if(nd < distance){ distance = nd; nc = iterator.GetData(); } } iterator.Advance(); } return nc; } void EntityList::ExpeditionWarning(uint32 minutes_left) { EQApplicationPacket* outapp = new EQApplicationPacket(OP_DzExpeditionEndsWarning, sizeof(ExpeditionExpireWarning)); ExpeditionExpireWarning *ew = (ExpeditionExpireWarning*)outapp->pBuffer; ew->minutes_remaining = minutes_left; LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { iterator.GetData()->Message_StringID(15, 3551, itoa((int)minutes_left)); iterator.GetData()->QueuePacket(outapp); iterator.Advance(); } } Mob* EntityList::GetClosestMobByBodyType(Mob* sender, bodyType BodyType) { if(!sender) return NULL; uint32 CurrentDistance, ClosestDistance = 4294967295u; Mob *CurrentMob, *ClosestMob = NULL; LinkedListIterator iterator(mob_list); iterator.Reset(); while(iterator.MoreElements()) { CurrentMob = iterator.GetData(); iterator.Advance(); if(CurrentMob->GetBodyType() != BodyType) continue; CurrentDistance = ((CurrentMob->GetY() - sender->GetY()) * (CurrentMob->GetY() - sender->GetY())) + ((CurrentMob->GetX() - sender->GetX()) * (CurrentMob->GetX() - sender->GetX())); if(CurrentDistance < ClosestDistance) { ClosestDistance = CurrentDistance; ClosestMob = CurrentMob; } } return ClosestMob; } void EntityList::GetTargetsForConeArea(Mob *start, uint32 radius, uint32 height, list &m_list) { LinkedListIterator iterator(mob_list); iterator.Reset(); while(iterator.MoreElements()) { Mob *ptr = iterator.GetData(); if(ptr == start) { iterator.Advance(); continue; } int32 x_diff = ptr->GetX() - start->GetX(); int32 y_diff = ptr->GetY() - start->GetY(); int32 z_diff = ptr->GetZ() - start->GetZ(); x_diff *= x_diff; y_diff *= y_diff; z_diff *= z_diff; if((x_diff + y_diff) <= (radius * radius)) { if(z_diff <= (height * height)) { m_list.push_back(ptr); } } iterator.Advance(); } } Client* EntityList::FindCorpseDragger(const char *CorpseName) { LinkedListIterator iterator(client_list); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->IsDraggingCorpse(CorpseName)) { return iterator.GetData(); } iterator.Advance(); } return 0; } Mob* EntityList::GetTargetForVirus(Mob* spreader) { int max_spread_range = RuleI(Spells, VirusSpreadDistance); vector TargetsInRange; LinkedListIterator iterator(mob_list); iterator.Reset(); while(iterator.MoreElements()) { // Make sure the target is in range, has los and is not the mob doing the spreading if ((iterator.GetData()->GetID() != spreader->GetID()) && (iterator.GetData()->CalculateDistance(spreader->GetX(), spreader->GetY(), spreader->GetZ()) <= max_spread_range) && (spreader->CheckLosFN(iterator.GetData()))) { // If the spreader is an npc it can only spread to other npc controlled mobs if (spreader->IsNPC() && !spreader->IsPet() && iterator.GetData()->IsNPC()) { TargetsInRange.push_back(iterator.GetData()); } // If the spreader is an npc controlled pet it can spread to any other npc or an npc controlled pet else if (spreader->IsNPC() && spreader->IsPet() && spreader->GetOwner()->IsNPC()) { if(iterator.GetData()->IsNPC() && !iterator.GetData()->IsPet()) { TargetsInRange.push_back(iterator.GetData()); } else if(iterator.GetData()->IsNPC() && iterator.GetData()->IsPet() && iterator.GetData()->GetOwner()->IsNPC()) { TargetsInRange.push_back(iterator.GetData()); } } // if the spreader is anything else(bot, pet, etc) then it should spread to everything but non client controlled npcs else if(!spreader->IsNPC() && !iterator.GetData()->IsNPC()) { TargetsInRange.push_back(iterator.GetData()); } // if its a pet we need to determine appropriate targets(pet to client, pet to pet, pet to bot, etc) else if (spreader->IsNPC() && spreader->IsPet() && !spreader->GetOwner()->IsNPC()) { if(!iterator.GetData()->IsNPC()) { TargetsInRange.push_back(iterator.GetData()); } else if (iterator.GetData()->IsNPC() && iterator.GetData()->IsPet() && !iterator.GetData()->GetOwner()->IsNPC()) { TargetsInRange.push_back(iterator.GetData()); } } } iterator.Advance(); } if(TargetsInRange.size() == 0) return NULL; return TargetsInRange[MakeRandomInt(0, TargetsInRange.size() - 1)]; }