diff --git a/EQ2/source/WorldServer/LuaFunctions.cpp b/EQ2/source/WorldServer/LuaFunctions.cpp index be5965cb4..163d4b101 100644 --- a/EQ2/source/WorldServer/LuaFunctions.cpp +++ b/EQ2/source/WorldServer/LuaFunctions.cpp @@ -3609,13 +3609,22 @@ int EQ2Emu_lua_AddPrimaryEntityCommand(lua_State* state) { string error_text = lua_interface->GetStringValue(state, 6); int16 cast_time = lua_interface->GetInt16Value(state, 7); int32 spell_visual = lua_interface->GetInt32Value(state, 8); - if (spawn && player && player->IsPlayer() && name.length() > 0) { + bool denyListDefault = (lua_interface->GetInt8Value(state, 9) == 1); + if (spawn) { if (distance == 0) distance = 10.0f; if (command.length() == 0) command = name; - spawn->AddPrimaryEntityCommand(name.c_str(), distance, command.c_str(), error_text.c_str(), cast_time, spell_visual); - player->GetZone()->SendUpdateDefaultCommand(spawn, command.c_str(), distance); + if (command.length() < 1 && name.length() < 1) + { + // have to run this first to send a 'blank' default command, then remove all commands from the list + spawn->GetZone()->SendUpdateDefaultCommand(spawn, command.c_str(), distance); + spawn->RemovePrimaryCommands(); + } + else + { + spawn->AddPrimaryEntityCommand(name.c_str(), distance, command.c_str(), error_text.c_str(), cast_time, spell_visual, denyListDefault, (player && player->IsPlayer()) ? (Player*)player : NULL); + } } return 0; } @@ -9385,5 +9394,57 @@ int EQ2Emu_lua_SetSeeHide(lua_State* state) { } } + return 0; +} + + +int EQ2Emu_lua_SetAccessToEntityCommand(lua_State* state) +{ + if (!lua_interface) + return 0; + + Spawn* player = lua_interface->GetSpawn(state); + Spawn* spawn = lua_interface->GetSpawn(state, 2); + string command = lua_interface->GetStringValue(state, 3); + bool val = (lua_interface->GetInt8Value(state, 4) == 1); + + if (spawn && player && player->IsPlayer()) + { + EntityCommand* cmd = spawn->FindEntityCommand(string(command), true); + bool res = false; + if (cmd) + res = spawn->SetPermissionToEntityCommand(cmd, (Player*)player, val); + + lua_interface->SetBooleanValue(state, res); + return 1; + } + + return 0; +} + +int EQ2Emu_lua_RemovePrimaryEntityCommand(lua_State* state) +{ + if (!lua_interface) + return 0; + + Spawn* spawn = lua_interface->GetSpawn(state); + string command = lua_interface->GetStringValue(state, 2); + + if (spawn && command.length() > 0) + spawn->RemovePrimaryEntityCommand(command.c_str()); + + return 0; +} + + +int EQ2Emu_lua_SendUpdateDefaultCommand(lua_State* state) { + Spawn* spawn = lua_interface->GetSpawn(state); + float distance = lua_interface->GetFloatValue(state, 2); + string command = lua_interface->GetStringValue(state, 3); + Spawn* player = lua_interface->GetSpawn(state, 4); + + if (spawn) { + spawn->GetZone()->SendUpdateDefaultCommand(spawn, command.c_str(), distance, player); + } return 0; } \ No newline at end of file diff --git a/EQ2/source/WorldServer/LuaFunctions.h b/EQ2/source/WorldServer/LuaFunctions.h index f9be3ec1e..3911d27c4 100644 --- a/EQ2/source/WorldServer/LuaFunctions.h +++ b/EQ2/source/WorldServer/LuaFunctions.h @@ -425,4 +425,8 @@ int EQ2Emu_lua_AddSpawnProximity(lua_State* state); int EQ2Emu_lua_CanSeeInvis(lua_State* state); int EQ2Emu_lua_SetSeeInvis(lua_State* state); int EQ2Emu_lua_SetSeeHide(lua_State* state); + +int EQ2Emu_lua_SetAccessToEntityCommand(lua_State* state); +int EQ2Emu_lua_RemovePrimaryEntityCommand(lua_State* state); +int EQ2Emu_lua_SendUpdateDefaultCommand(lua_State* state); #endif \ No newline at end of file diff --git a/EQ2/source/WorldServer/LuaInterface.cpp b/EQ2/source/WorldServer/LuaInterface.cpp index d6d0de407..39481a3b5 100644 --- a/EQ2/source/WorldServer/LuaInterface.cpp +++ b/EQ2/source/WorldServer/LuaInterface.cpp @@ -1028,6 +1028,10 @@ void LuaInterface::RegisterFunctions(lua_State* state) { lua_register(state, "CanSeeInvis", EQ2Emu_lua_CanSeeInvis); lua_register(state, "SetSeeInvis", EQ2Emu_lua_SetSeeInvis); lua_register(state, "SetSeeHide", EQ2Emu_lua_SetSeeHide); + + lua_register(state, "SetAccessToEntityCommand", EQ2Emu_lua_SetAccessToEntityCommand); + lua_register(state, "RemovePrimaryEntityCommand", EQ2Emu_lua_RemovePrimaryEntityCommand); + lua_register(state, "SendUpdateDefaultCommand", EQ2Emu_lua_SendUpdateDefaultCommand); } void LuaInterface::LogError(const char* error, ...) { @@ -1591,6 +1595,7 @@ bool LuaInterface::RunItemScript(string script_name, const char* function_name, bool LuaInterface::RunSpawnScript(string script_name, const char* function_name, Spawn* npc, Spawn* spawn, const char* message) { if(!npc || spawn_scripts_reloading) return false; + lua_State* state = GetSpawnScript(script_name.c_str(), true, true); if(state){ Mutex* mutex = GetSpawnScriptMutex(script_name.c_str()); diff --git a/EQ2/source/WorldServer/Spawn.cpp b/EQ2/source/WorldServer/Spawn.cpp index 8f5bd0b27..2c2a6b486 100644 --- a/EQ2/source/WorldServer/Spawn.cpp +++ b/EQ2/source/WorldServer/Spawn.cpp @@ -107,9 +107,8 @@ Spawn::Spawn(){ } Spawn::~Spawn(){ - for(int32 i=0;isetDataByName("index", index); @@ -1537,17 +1544,21 @@ void Spawn::SetPrimaryCommands(vector* commands){ } } -EntityCommand* Spawn::FindEntityCommand(string command) { +EntityCommand* Spawn::FindEntityCommand(string command, bool primaryOnly) { EntityCommand* entity_command = 0; if (primary_command_list.size() > 0) { vector::iterator itr; for (itr = primary_command_list.begin(); itr != primary_command_list.end(); itr++) { - if ((*itr)->command == command) { + if ((*itr)->command.compare(command) == 0) { entity_command = *itr; break; } } } + + if (primaryOnly) + return entity_command; + if (!entity_command && secondary_command_list.size() > 0) { vector::iterator itr; for (itr = secondary_command_list.begin(); itr != secondary_command_list.end(); itr++) { @@ -3246,4 +3257,60 @@ void Spawn::RemoveSpawnFromProximity(int32 spawnValue, SpawnProximityType type) prox->spawns_in_proximity.erase(spawnValue); } } +} + +void Spawn::AddPrimaryEntityCommand(const char* name, float distance, const char* command, const char* error_text, int16 cast_time, int32 spell_visual, bool defaultDenyList, Player* player) { + + EntityCommand* cmd = FindEntityCommand(string(command), true); + + bool newCommand = false; + if (!cmd) + { + newCommand = true; + cmd = CreateEntityCommand(name, distance, command, error_text, cast_time, spell_visual, !defaultDenyList); + } + + if (defaultDenyList) + SetPermissionToEntityCommand(cmd, player, true); + + if (newCommand) + primary_command_list.push_back(cmd); +} + +void Spawn::RemovePrimaryEntityCommand(const char* command) { + vector::iterator itr; + string tmpStr(command); + for (itr = primary_command_list.begin(); itr != primary_command_list.end();) { + EntityCommand* cmd = *itr; + if (cmd->command.compare(tmpStr) == 0) + { + safe_delete(cmd); + + vector::iterator tmpItr = itr++; + primary_command_list.erase(itr); + + if (tmpItr == primary_command_list.end()) + break; + + itr = tmpItr; + } + else + itr++; + } +} + +bool Spawn::SetPermissionToEntityCommand(EntityCommand* command, Player* player, bool permissionValue) +{ + if (player != NULL) + { + map::iterator itr = command->allow_or_deny.find(player->GetCharacterID()); + if (itr == command->allow_or_deny.end()) + command->allow_or_deny.insert(make_pair(player->GetCharacterID(), permissionValue)); + else if (itr->second != permissionValue) + itr->second = permissionValue; + + return true; + } + + return false; } \ No newline at end of file diff --git a/EQ2/source/WorldServer/Spawn.h b/EQ2/source/WorldServer/Spawn.h index d9810a812..09c51cd94 100644 --- a/EQ2/source/WorldServer/Spawn.h +++ b/EQ2/source/WorldServer/Spawn.h @@ -279,9 +279,10 @@ public: entity_command->error_text = old_command->error_text; entity_command->cast_time = old_command->cast_time; entity_command->spell_visual = old_command->spell_visual; + entity_command->default_allow_list = old_command->default_allow_list; return entity_command; } - EntityCommand* CreateEntityCommand(const char* name, float distance, const char* command, const char* error_text, int16 cast_time, int32 spell_visual){ + EntityCommand* CreateEntityCommand(const char* name, float distance, const char* command, const char* error_text, int16 cast_time, int32 spell_visual, bool default_allow_list=true){ EntityCommand* entity_command = new EntityCommand; entity_command->name = name; entity_command->distance = distance; @@ -289,12 +290,14 @@ public: entity_command->error_text = error_text; entity_command->cast_time = cast_time; entity_command->spell_visual = spell_visual; + entity_command->default_allow_list = default_allow_list; return entity_command; } void AddChangedZoneSpawn(); - void AddPrimaryEntityCommand(const char* name, float distance, const char* command, const char* error_text, int16 cast_time, int32 spell_visual){ - primary_command_list.push_back(CreateEntityCommand(name, distance, command, error_text, cast_time, spell_visual)); - } + void AddPrimaryEntityCommand(const char* name, float distance, const char* command, const char* error_text, int16 cast_time, int32 spell_visual, bool defaultDenyList = false, Player* player = NULL); + void RemovePrimaryEntityCommand(const char* command); + bool SetPermissionToEntityCommand(EntityCommand* command, Player* player, bool permissionValue); + void AddSecondaryEntityCommand(const char* name, float distance, const char* command, const char* error_text, int16 cast_time, int32 spell_visual){ secondary_command_list.push_back(CreateEntityCommand(name, distance, command, error_text, cast_time, spell_visual)); } @@ -760,7 +763,7 @@ public: void SetSecondaryCommands(vector* commands); vector* GetPrimaryCommands() {return &primary_command_list;} vector* GetSecondaryCommands() {return &secondary_command_list;} - EntityCommand* FindEntityCommand(string command); + EntityCommand* FindEntityCommand(string command, bool primaryOnly=false); virtual EQ2Packet* serialize(Player* player, int16 version); EQ2Packet* spawn_serialize(Player* player, int16 version); EQ2Packet* spawn_update_packet(Player* player, int16 version, bool override_changes = false, bool override_vis_changes = false); @@ -879,6 +882,8 @@ public: int32 GetTransporterID(); bool MeetsSpawnAccessRequirements(Player* player); + void RemovePrimaryCommands(); + void InitializePosPacketData(Player* player, PacketStruct* packet, bool bSpawnUpdate = false); void InitializeInfoPacketData(Player* player, PacketStruct* packet); void InitializeVisPacketData(Player* player, PacketStruct* packet); diff --git a/EQ2/source/WorldServer/SpawnLists.h b/EQ2/source/WorldServer/SpawnLists.h index e88b015d6..6f4359146 100644 --- a/EQ2/source/WorldServer/SpawnLists.h +++ b/EQ2/source/WorldServer/SpawnLists.h @@ -21,6 +21,7 @@ #define EQ2_SPAWN_LISTS #include "../common/types.h" #include +#include #define SPAWN_ENTRY_TYPE_NPC 0 #define SPAWN_ENTRY_TYPE_OBJECT 1 @@ -35,6 +36,8 @@ struct EntityCommand{ string command; int16 cast_time; int32 spell_visual; + map allow_or_deny; // this is a map of player IDs and whether they are allowed on the command or denied + bool default_allow_list; // if set to false then its a defaultDenyList }; struct SpawnEntry{ int32 spawn_entry_id; diff --git a/EQ2/source/WorldServer/WorldDatabase.cpp b/EQ2/source/WorldServer/WorldDatabase.cpp index ab4189ed2..292d2568f 100644 --- a/EQ2/source/WorldServer/WorldDatabase.cpp +++ b/EQ2/source/WorldServer/WorldDatabase.cpp @@ -3662,6 +3662,7 @@ void WorldDatabase::LoadEntityCommands(ZoneServer* zone) { command->error_text = result.GetString(4); command->cast_time = result.GetInt16(5); command->spell_visual = result.GetInt32(6); + command->default_allow_list = true; zone->SetEntityCommandList(id, command); LogWrite(COMMAND__DEBUG, 5, "Command", "---Loading Command: '%s' (%s)", command->name.c_str(), command->command.c_str()); diff --git a/EQ2/source/WorldServer/client.cpp b/EQ2/source/WorldServer/client.cpp index eb4d67364..031023250 100644 --- a/EQ2/source/WorldServer/client.cpp +++ b/EQ2/source/WorldServer/client.cpp @@ -3432,7 +3432,23 @@ void Client::HandleVerbRequest(EQApplicationPacket* app) { vector delete_commands; if (out && spawn) { for (int32 i = 0; i < spawn->primary_command_list.size(); i++) + { + // default is a deny list not allow, only allow if on the iterator list and itr second is not false (deny) + if (!spawn->primary_command_list[i]->default_allow_list) + { + map::iterator itr = spawn->primary_command_list[i]->allow_or_deny.find(GetPlayer()->GetCharacterID()); + if (itr == spawn->primary_command_list[i]->allow_or_deny.end() || !itr->second) + continue; + } + else + { + // default is allow list, only deny if added to the list as deny (false itr second) + map::iterator itr = spawn->primary_command_list[i]->allow_or_deny.find(GetPlayer()->GetCharacterID()); + if (itr != spawn->primary_command_list[i]->allow_or_deny.end() && !itr->second) + continue; + } commands.push_back(spawn->primary_command_list[i]); + } for (int32 i = 0; i < spawn->secondary_command_list.size(); i++) commands.push_back(spawn->secondary_command_list[i]); if (spawn->IsPlayer()) { @@ -8470,4 +8486,18 @@ void Client::SendHailCommand(Spawn* spawn) break; } } +} + +void Client::SendDefaultCommand(Spawn* spawn, const char* command, float distance) +{ + if (GetPlayer()->WasSentSpawn(spawn->GetID()) && GetPlayer()->WasSpawnRemoved(spawn) == false) { + PacketStruct* packet = configReader.getStruct("WS_SetDefaultCommand", GetVersion()); + if (packet) { + packet->setDataByName("spawn_id", GetPlayer()->GetIDWithPlayerSpawn(spawn)); + packet->setMediumStringByName("command_name", command); + packet->setDataByName("distance", distance); + QueuePacket(packet->serialize()); + safe_delete(packet); + } + } } \ No newline at end of file diff --git a/EQ2/source/WorldServer/client.h b/EQ2/source/WorldServer/client.h index 429c77dd7..0d01ffe0a 100644 --- a/EQ2/source/WorldServer/client.h +++ b/EQ2/source/WorldServer/client.h @@ -403,6 +403,7 @@ public: bool IsZonedIn() { return connected_to_zone; } void SendHailCommand(Spawn* target); + void SendDefaultCommand(Spawn* spawn, const char* command, float distance); private: void SavePlayerImages(); void SkillChanged(Skill* skill, int16 previous_value, int16 new_value); diff --git a/EQ2/source/WorldServer/zoneserver.cpp b/EQ2/source/WorldServer/zoneserver.cpp index 7992a392a..104a92d76 100644 --- a/EQ2/source/WorldServer/zoneserver.cpp +++ b/EQ2/source/WorldServer/zoneserver.cpp @@ -5172,7 +5172,24 @@ EQ2Packet* ZoneServer::GetZoneInfoPacket(Client* client){ return outapp; } -void ZoneServer::SendUpdateDefaultCommand(Spawn* spawn, const char* command, float distance){ +void ZoneServer::SendUpdateDefaultCommand(Spawn* spawn, const char* command, float distance, Spawn* toPlayer){ + if (spawn == nullptr || command == nullptr) + return; + + if (toPlayer) + { + if (!toPlayer->IsPlayer()) + return; + + Client* client = GetClientBySpawn(toPlayer); + if (client) + { + client->SendDefaultCommand(spawn, command, distance); + } + // we don't override the primary command cause that would change ALL clients + return; + } + Client* client = 0; PacketStruct* packet = 0; vector::iterator client_itr; @@ -5180,18 +5197,11 @@ void ZoneServer::SendUpdateDefaultCommand(Spawn* spawn, const char* command, flo MClientList.readlock(__FUNCTION__, __LINE__); for (client_itr = clients.begin(); client_itr != clients.end(); client_itr++) { client = *client_itr; - if(client && client->GetPlayer()->WasSentSpawn(spawn->GetID()) && client->GetPlayer()->WasSpawnRemoved(spawn) == false){ - packet = configReader.getStruct("WS_SetDefaultCommand", client->GetVersion()); - if(packet){ - packet->setDataByName("spawn_id", client->GetPlayer()->GetIDWithPlayerSpawn(spawn)); - packet->setMediumStringByName("command_name", command); - packet->setDataByName("distance", distance); - client->QueuePacket(packet->serialize()); - safe_delete(packet); - } - } - spawn->SetPrimaryCommand(command, command, distance); + client->SendDefaultCommand(spawn, command, distance); } + + if (strlen(command)>0) + spawn->SetPrimaryCommand(command, command, distance); MClientList.releasereadlock(__FUNCTION__, __LINE__); } diff --git a/EQ2/source/WorldServer/zoneserver.h b/EQ2/source/WorldServer/zoneserver.h index ac5ad8286..65f81dddb 100644 --- a/EQ2/source/WorldServer/zoneserver.h +++ b/EQ2/source/WorldServer/zoneserver.h @@ -404,7 +404,7 @@ public: void SendDispellPacket(Entity* caster, Spawn* target, string dispell_name, string spell_name, int8 dispell_type); void SetupInstance(int32 createdInstanceID=0); - void SendUpdateDefaultCommand(Spawn* spawn, const char* command, float distance); + void SendUpdateDefaultCommand(Spawn* spawn, const char* command, float distance, Spawn* toplayer = NULL); map* GetSpawnLocationsByGroup(int32 group_id);