LUA Commands Added/Updated for controlling primary commands

Fix #120

Examples:

--AddPrimaryEntityCommand(Spawn,NPC,"",0,"") -- removes all the primary entity commands (including hail)

--AddPrimaryEntityCommand(Spawn,NPC,"hail",10000,"hail") -- adds the hail command back to the npc

--SendUpdateDefaultCommand(NPC,10000,"hail") -- returns the bubble option when you hover over the spawn/npc

--AddPrimaryEntityCommand(Spawn,NPC,"hail2",10000,"hail2","",0,0,1) -- 1 at the end sets this as a default DENY list, if Spawn is supplied and not null/not player then that player gets default allow access.  Any other players must be added (either by calling the AddPrimaryEntityCommand or subsequently SetAccessToEntityCommand)

--SetAccessToEntityCommand(Spawn,NPC,"hail2",0) -- removes access to the just created hail2 for that player

--SetAccessToEntityCommand(Spawn,NPC,"hail2",1) -- adds access to hail2 for that Spawn (player)

--RemovePrimaryEntityCommand(NPC,"hail2") -- removes hail2 command for all players
This commit is contained in:
Image 2020-05-19 13:38:11 -04:00
parent bdbb49c92a
commit 6c7f11fd70
11 changed files with 213 additions and 26 deletions

View file

@ -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;
}

View file

@ -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

View file

@ -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());

View file

@ -107,9 +107,8 @@ Spawn::Spawn(){
}
Spawn::~Spawn(){
for(int32 i=0;i<primary_command_list.size();i++){
safe_delete(primary_command_list[i]);
}
RemovePrimaryCommands();
for(int32 i=0;i<secondary_command_list.size();i++){
safe_delete(secondary_command_list[i]);
}
@ -143,6 +142,14 @@ Spawn::~Spawn(){
RemoveSpawnProximities();
}
void Spawn::RemovePrimaryCommands()
{
for (int32 i = 0; i < primary_command_list.size(); i++) {
safe_delete(primary_command_list[i]);
}
primary_command_list.clear();
}
void Spawn::InitializeHeaderPacketData(Player* player, PacketStruct* header, int16 index) {
header->setDataByName("index", index);
@ -1537,17 +1544,21 @@ void Spawn::SetPrimaryCommands(vector<EntityCommand*>* commands){
}
}
EntityCommand* Spawn::FindEntityCommand(string command) {
EntityCommand* Spawn::FindEntityCommand(string command, bool primaryOnly) {
EntityCommand* entity_command = 0;
if (primary_command_list.size() > 0) {
vector<EntityCommand*>::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<EntityCommand*>::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<EntityCommand*>::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<EntityCommand*>::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<int32, bool>::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;
}

View file

@ -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<EntityCommand*>* commands);
vector<EntityCommand*>* GetPrimaryCommands() {return &primary_command_list;}
vector<EntityCommand*>* 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);

View file

@ -21,6 +21,7 @@
#define EQ2_SPAWN_LISTS
#include "../common/types.h"
#include <vector>
#include <map>
#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<int32, bool> 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;

View file

@ -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());

View file

@ -3432,7 +3432,23 @@ void Client::HandleVerbRequest(EQApplicationPacket* app) {
vector<EntityCommand*> 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<int32, bool>::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<int32, bool>::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);
}
}
}

View file

@ -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);

View file

@ -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<Client*>::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__);
}

View file

@ -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<int32, int32>* GetSpawnLocationsByGroup(int32 group_id);