mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-13 02:11:30 +00:00
Merge branch 'master' of https://github.com/EQEmu/Server into lsid
# Conflicts: # common/ruletypes.h # world/net.cpp # zone/bot_command.cpp # zone/command.cpp # zone/zonedb.cpp
This commit is contained in:
commit
cf80e594bc
@ -21,6 +21,7 @@
|
||||
#include "string_util.h"
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fmt/format.h>
|
||||
|
||||
/*
|
||||
Commands:
|
||||
@ -45,14 +46,14 @@ const char *RuleManager::s_categoryNames[_CatCount+1] = {
|
||||
|
||||
const RuleManager::RuleInfo RuleManager::s_RuleInfo[_IntRuleCount+_RealRuleCount+_BoolRuleCount+1] = {
|
||||
/* this is done in three steps so we can reliably get to them by index*/
|
||||
#define RULE_INT(cat, rule, default_value) \
|
||||
{ #cat ":" #rule, Category__##cat, IntRule, Int__##rule },
|
||||
#define RULE_INT(cat, rule, default_value, notes) \
|
||||
{ #cat ":" #rule, Category__##cat, IntRule, Int__##rule, notes },
|
||||
#include "ruletypes.h"
|
||||
#define RULE_REAL(cat, rule, default_value) \
|
||||
{ #cat ":" #rule, Category__##cat, RealRule, Real__##rule },
|
||||
#define RULE_REAL(cat, rule, default_value, notes) \
|
||||
{ #cat ":" #rule, Category__##cat, RealRule, Real__##rule, notes },
|
||||
#include "ruletypes.h"
|
||||
#define RULE_BOOL(cat, rule, default_value) \
|
||||
{ #cat ":" #rule, Category__##cat, BoolRule, Bool__##rule },
|
||||
#define RULE_BOOL(cat, rule, default_value, notes) \
|
||||
{ #cat ":" #rule, Category__##cat, BoolRule, Bool__##rule, notes },
|
||||
#include "ruletypes.h"
|
||||
{ "Invalid Rule", _CatCount, IntRule }
|
||||
};
|
||||
@ -178,11 +179,11 @@ void RuleManager::ResetRules(bool reload) {
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Rules, "Resetting running rules to default values");
|
||||
#define RULE_INT(cat, rule, default_value) \
|
||||
#define RULE_INT(cat, rule, default_value, notes) \
|
||||
m_RuleIntValues[ Int__##rule ] = default_value;
|
||||
#define RULE_REAL(cat, rule, default_value) \
|
||||
#define RULE_REAL(cat, rule, default_value, notes) \
|
||||
m_RuleRealValues[ Real__##rule ] = default_value;
|
||||
#define RULE_BOOL(cat, rule, default_value) \
|
||||
#define RULE_BOOL(cat, rule, default_value, notes) \
|
||||
m_RuleBoolValues[ Bool__##rule ] = default_value;
|
||||
#include "ruletypes.h"
|
||||
|
||||
@ -214,19 +215,101 @@ bool RuleManager::_FindRule(const char *rule_name, RuleType &type_into, uint16 &
|
||||
//assumes index is valid!
|
||||
const char *RuleManager::_GetRuleName(RuleType type, uint16 index) {
|
||||
switch (type) {
|
||||
case IntRule:
|
||||
return(s_RuleInfo[index].name);
|
||||
case RealRule:
|
||||
return(s_RuleInfo[index + _IntRuleCount].name);
|
||||
case BoolRule:
|
||||
return(s_RuleInfo[index + _IntRuleCount + _RealRuleCount].name);
|
||||
case IntRule:
|
||||
return(s_RuleInfo[index].name);
|
||||
case RealRule:
|
||||
return(s_RuleInfo[index+_IntRuleCount].name);
|
||||
case BoolRule:
|
||||
return(s_RuleInfo[index+_IntRuleCount+_RealRuleCount].name);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
//should never happen
|
||||
return("InvalidRule??");
|
||||
return(s_RuleInfo[_IntRuleCount+_RealRuleCount+_BoolRuleCount].name); // no need to create a string when one already exists...
|
||||
}
|
||||
|
||||
//assumes index is valid!
|
||||
const std::string &RuleManager::_GetRuleNotes(RuleType type, uint16 index) {
|
||||
switch (type) {
|
||||
case IntRule:
|
||||
return(s_RuleInfo[index].notes);
|
||||
case RealRule:
|
||||
return(s_RuleInfo[index+_IntRuleCount].notes);
|
||||
case BoolRule:
|
||||
return(s_RuleInfo[index+_IntRuleCount+_RealRuleCount].notes);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
//should never happen
|
||||
return(s_RuleInfo[_IntRuleCount+_RealRuleCount+_BoolRuleCount].notes);
|
||||
}
|
||||
|
||||
bool RuleManager::LoadRules(Database *database, const char *ruleset_name, bool reload) {
|
||||
|
||||
int ruleset_id = this->GetRulesetID(database, ruleset_name);
|
||||
if (ruleset_id < 0) {
|
||||
Log(Logs::Detail, Logs::Rules, "Failed to find ruleset '%s' for load operation. Canceling.", ruleset_name);
|
||||
return (false);
|
||||
}
|
||||
|
||||
m_activeRuleset = ruleset_id;
|
||||
m_activeName = ruleset_name;
|
||||
|
||||
/* Load default ruleset values first if we're loading something other than default */
|
||||
if (strcasecmp(ruleset_name, "default") != 0) {
|
||||
|
||||
std::string default_ruleset_name = "default";
|
||||
int default_ruleset_id = GetRulesetID(database, default_ruleset_name.c_str());
|
||||
|
||||
if (default_ruleset_id < 0) {
|
||||
Log(Logs::Detail,
|
||||
Logs::Rules,
|
||||
"Failed to find default ruleset '%s' for load operation. Canceling.",
|
||||
default_ruleset_name.c_str()
|
||||
);
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Rules, "Processing rule set '%s' (%d) load...", default_ruleset_name.c_str(), default_ruleset_id);
|
||||
|
||||
std::string query = StringFormat(
|
||||
"SELECT `rule_name`, `rule_value` FROM `rule_values` WHERE `ruleset_id` = '%d'",
|
||||
default_ruleset_id
|
||||
);
|
||||
|
||||
auto results = database->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
if (!SetRule(row[0], row[1], nullptr, false, reload)) {
|
||||
Log(Logs::Detail, Logs::Rules, "Unable to interpret rule record for '%s'", row[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Rules, "Processing rule set '%s' (%d) load...", ruleset_name, ruleset_id);
|
||||
|
||||
std::string query = StringFormat("SELECT `rule_name`, `rule_value` FROM `rule_values` WHERE `ruleset_id` = '%d'", ruleset_id);
|
||||
|
||||
auto results = database->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
if (!SetRule(row[0], row[1], nullptr, false, reload)) {
|
||||
Log(Logs::Detail, Logs::Rules, "Unable to interpret rule record for '%s'", row[0]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RuleManager::SaveRules(Database *database, const char *ruleset_name) {
|
||||
|
||||
|
||||
if (ruleset_name != nullptr) {
|
||||
//saving to a specific name
|
||||
if (m_activeName != ruleset_name) {
|
||||
@ -257,56 +340,6 @@ void RuleManager::SaveRules(Database *database, const char *ruleset_name) {
|
||||
}
|
||||
}
|
||||
|
||||
bool RuleManager::LoadRules(Database *database, const char *ruleset_name, bool reload) {
|
||||
|
||||
int ruleset_id = this->GetRulesetID(database, ruleset_name);
|
||||
if (ruleset_id < 0) {
|
||||
Log(Logs::Detail, Logs::Rules, "Failed to find ruleset '%s' for load operation. Canceling.", ruleset_name);
|
||||
return (false);
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Rules, "Loading rule set '%s' (%d)", ruleset_name, ruleset_id);
|
||||
|
||||
m_activeRuleset = ruleset_id;
|
||||
m_activeName = ruleset_name;
|
||||
|
||||
/* Load default ruleset values first if we're loading something other than default */
|
||||
if (strcasecmp(ruleset_name, "default") != 0) {
|
||||
std::string default_ruleset_name = "default";
|
||||
int default_ruleset_id = GetRulesetID(database, default_ruleset_name.c_str());
|
||||
if (default_ruleset_id < 0) {
|
||||
Log(Logs::Detail, Logs::Rules, "Failed to find default ruleset '%s' for load operation. Canceling.",
|
||||
default_ruleset_name.c_str());
|
||||
return (false);
|
||||
}
|
||||
Log(Logs::Detail, Logs::Rules, "Loading rule set '%s' (%d)", default_ruleset_name.c_str(), default_ruleset_id);
|
||||
|
||||
std::string query = StringFormat(
|
||||
"SELECT rule_name, rule_value FROM rule_values WHERE ruleset_id = %d",
|
||||
default_ruleset_id
|
||||
);
|
||||
|
||||
auto results = database->QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return false;
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
if (!SetRule(row[0], row[1], nullptr, false, reload))
|
||||
Log(Logs::Detail, Logs::Rules, "Unable to interpret rule record for %s", row[0]);
|
||||
}
|
||||
|
||||
std::string query = StringFormat("SELECT rule_name, rule_value FROM rule_values WHERE ruleset_id=%d", ruleset_id);
|
||||
auto results = database->QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return false;
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
if (!SetRule(row[0], row[1], nullptr, false, reload))
|
||||
Log(Logs::Detail, Logs::Rules, "Unable to interpret rule record for %s", row[0]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RuleManager::_SaveRule(Database *database, RuleType type, uint16 index) {
|
||||
char value_string[100];
|
||||
|
||||
@ -328,17 +361,244 @@ void RuleManager::_SaveRule(Database *database, RuleType type, uint16 index) {
|
||||
}
|
||||
|
||||
std::string query = StringFormat(
|
||||
"REPLACE INTO rule_values "
|
||||
"(ruleset_id, rule_name, rule_value) "
|
||||
" VALUES(%d, '%s', '%s')",
|
||||
"REPLACE INTO `rule_values`"
|
||||
"(`ruleset_id`, `rule_name`, `rule_value`, `notes`)"
|
||||
" VALUES('%d', '%s', '%s', '%s')",
|
||||
m_activeRuleset,
|
||||
_GetRuleName(type, index),
|
||||
value_string
|
||||
value_string,
|
||||
EscapeString(_GetRuleNotes(type, index)).c_str()
|
||||
);
|
||||
|
||||
database->QueryDatabase(query);
|
||||
}
|
||||
|
||||
bool RuleManager::UpdateInjectedRules(Database *db, const char *ruleset_name, bool quiet_update)
|
||||
{
|
||||
std::vector<std::string> database_data;
|
||||
std::map<std::string, std::pair<std::string, const std::string *>> rule_data;
|
||||
std::vector<std::tuple<int, std::string, std::string, std::string>> injected_rule_entries;
|
||||
|
||||
if (ruleset_name == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int ruleset_id = GetRulesetID(db, ruleset_name);
|
||||
if (ruleset_id < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// load database rule names
|
||||
std::string query(StringFormat("SELECT `rule_name` FROM `rule_values` WHERE `ruleset_id` = '%i'", ruleset_id));
|
||||
|
||||
auto results = db->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// build database data entries
|
||||
for (auto row : results) {
|
||||
database_data.push_back(std::string(row[0]));
|
||||
}
|
||||
|
||||
// build rule data entries
|
||||
for (const auto &ri_iter : s_RuleInfo) {
|
||||
if (strcasecmp(ri_iter.name, "Invalid Rule") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char buffer[100];
|
||||
|
||||
switch (ri_iter.type) {
|
||||
case IntRule:
|
||||
sprintf(buffer, "%d", m_RuleIntValues[ri_iter.rule_index]);
|
||||
rule_data[ri_iter.name].first = buffer;
|
||||
rule_data[ri_iter.name].second = &ri_iter.notes;
|
||||
break;
|
||||
case RealRule:
|
||||
sprintf(buffer, "%.13f", m_RuleRealValues[ri_iter.rule_index]);
|
||||
rule_data[ri_iter.name].first = buffer;
|
||||
rule_data[ri_iter.name].second = &ri_iter.notes;
|
||||
break;
|
||||
case BoolRule:
|
||||
sprintf(buffer, "%s", (m_RuleBoolValues[ri_iter.rule_index] ? "true" : "false"));
|
||||
rule_data[ri_iter.name].first = buffer;
|
||||
rule_data[ri_iter.name].second = &ri_iter.notes;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// build injected entries
|
||||
for (const auto &rd_iter : rule_data) {
|
||||
|
||||
const auto &dd_iter = std::find(database_data.begin(), database_data.end(), rd_iter.first);
|
||||
if (dd_iter == database_data.end()) {
|
||||
|
||||
injected_rule_entries.push_back(
|
||||
std::tuple<int, std::string, std::string, std::string>(
|
||||
ruleset_id, // `ruleset_id`
|
||||
rd_iter.first, // `rule_name`
|
||||
rd_iter.second.first, // `rule_value`
|
||||
EscapeString(*rd_iter.second.second) // `notes`
|
||||
)
|
||||
);
|
||||
|
||||
if (!quiet_update) {
|
||||
LogInfo(
|
||||
"New Rule '%s' found... Adding to `rule_values` table with ruleset '%s' (%i) and rule value '%s'...",
|
||||
rd_iter.first.c_str(),
|
||||
ruleset_name,
|
||||
ruleset_id,
|
||||
rd_iter.second.first.c_str()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (injected_rule_entries.size()) {
|
||||
|
||||
std::string query(
|
||||
fmt::format(
|
||||
"REPLACE INTO `rule_values`(`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES {}",
|
||||
implode(
|
||||
",",
|
||||
std::pair<char, char>('(', ')'),
|
||||
join_tuple(",", std::pair<char, char>('\'', '\''), injected_rule_entries)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if (!db->QueryDatabase(query).Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LogInfo(
|
||||
"%u New Rule%s Added to ruleset '%s' (%i)",
|
||||
injected_rule_entries.size(),
|
||||
(injected_rule_entries.size() == 1 ? "" : "s"),
|
||||
ruleset_name,
|
||||
ruleset_id
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RuleManager::UpdateOrphanedRules(Database *db, bool quiet_update)
|
||||
{
|
||||
std::vector<std::string> rule_data;
|
||||
std::vector<std::string> orphaned_rule_entries;
|
||||
|
||||
// load database rule names
|
||||
std::string query("SELECT `rule_name` FROM `rule_values` GROUP BY `rule_name`");
|
||||
|
||||
auto results = db->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// build rule data entries
|
||||
for (const auto &ri_iter : s_RuleInfo) {
|
||||
if (strcasecmp(ri_iter.name, "Invalid Rule") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
rule_data.push_back(ri_iter.name);
|
||||
}
|
||||
|
||||
// build orphaned entries
|
||||
for (auto row : results) {
|
||||
|
||||
const auto &rd_iter = std::find(rule_data.begin(), rule_data.end(), row[0]);
|
||||
if (rd_iter == rule_data.end()) {
|
||||
|
||||
orphaned_rule_entries.push_back(std::string(row[0]));
|
||||
|
||||
if (!quiet_update) {
|
||||
LogInfo(
|
||||
"Rule '%s' no longer exists... Deleting orphaned entry from `rule_values` table...",
|
||||
row[0]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (orphaned_rule_entries.size()) {
|
||||
|
||||
std::string query (
|
||||
fmt::format(
|
||||
"DELETE FROM `rule_values` WHERE `rule_name` IN ({})",
|
||||
implode(",", std::pair<char, char>('\'', '\''), orphaned_rule_entries)
|
||||
)
|
||||
);
|
||||
|
||||
if (!db->QueryDatabase(query).Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LogInfo(
|
||||
"%u Orphaned Rule%s Deleted from 'All Rulesets' (-1)",
|
||||
orphaned_rule_entries.size(),
|
||||
(orphaned_rule_entries.size() == 1 ? "" : "s")
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RuleManager::RestoreRuleNotes(Database *db)
|
||||
{
|
||||
std::string query("SELECT `ruleset_id`, `rule_name`, IFNULL(`notes`, '\\0')`notes` FROM `rule_values`");
|
||||
|
||||
auto results = db->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int update_count = 0;
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
|
||||
const auto &rule = [&row]() {
|
||||
|
||||
for (const auto &rule_iter : s_RuleInfo) {
|
||||
if (strcasecmp(rule_iter.name, row[1]) == 0) {
|
||||
return rule_iter;
|
||||
}
|
||||
}
|
||||
|
||||
return s_RuleInfo[_IntRuleCount+_RealRuleCount+_BoolRuleCount];
|
||||
}();
|
||||
|
||||
if (strcasecmp(rule.name, row[1]) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rule.notes.compare(row[2]) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string query(
|
||||
fmt::format(
|
||||
"UPDATE `rule_values` SET `notes` = '{}' WHERE `ruleset_id` = '{}' AND `rule_name` = '{}'",
|
||||
EscapeString(rule.notes),
|
||||
row[0],
|
||||
row[1]
|
||||
)
|
||||
);
|
||||
|
||||
if (!db->QueryDatabase(query).Success()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
++update_count;
|
||||
}
|
||||
|
||||
if (update_count > 0) {
|
||||
LogInfo("%u Rule Note%s Restored", update_count, (update_count == 1 ? "" : "s"));
|
||||
}
|
||||
}
|
||||
|
||||
int RuleManager::GetRulesetID(Database *database, const char *ruleset_name) {
|
||||
|
||||
|
||||
@ -49,21 +49,21 @@ class RuleManager {
|
||||
public:
|
||||
//generate our rule enums:
|
||||
typedef enum {
|
||||
#define RULE_INT(cat, rule, default_value) \
|
||||
#define RULE_INT(cat, rule, default_value, notes) \
|
||||
Int__##rule,
|
||||
#include "ruletypes.h"
|
||||
_IntRuleCount
|
||||
} IntType;
|
||||
|
||||
typedef enum {
|
||||
#define RULE_REAL(cat, rule, default_value) \
|
||||
#define RULE_REAL(cat, rule, default_value, notes) \
|
||||
Real__##rule,
|
||||
#include "ruletypes.h"
|
||||
_RealRuleCount
|
||||
} RealType;
|
||||
|
||||
typedef enum {
|
||||
#define RULE_BOOL(cat, rule, default_value) \
|
||||
#define RULE_BOOL(cat, rule, default_value, notes) \
|
||||
Bool__##rule,
|
||||
#include "ruletypes.h"
|
||||
_BoolRuleCount
|
||||
@ -97,6 +97,9 @@ public:
|
||||
static const char *GetRuleName(IntType t) { return(s_RuleInfo[t].name); }
|
||||
static const char *GetRuleName(RealType t) { return(s_RuleInfo[t+_IntRuleCount].name); }
|
||||
static const char *GetRuleName(BoolType t) { return(s_RuleInfo[t+_IntRuleCount+_RealRuleCount].name); }
|
||||
static const std::string &GetRuleNotes(IntType t) { return(s_RuleInfo[t].notes); }
|
||||
static const std::string &GetRuleNotes(RealType t) { return(s_RuleInfo[t+_IntRuleCount].notes); }
|
||||
static const std::string &GetRuleNotes(BoolType t) { return(s_RuleInfo[t+_IntRuleCount+_RealRuleCount].notes); }
|
||||
static uint32 CountRules() { return(_RulesCount); }
|
||||
static CategoryType FindCategory(const char *catname);
|
||||
bool ListRules(const char *catname, std::vector<const char *> &into);
|
||||
@ -113,6 +116,9 @@ public:
|
||||
void ResetRules(bool reload = false);
|
||||
bool LoadRules(Database *db, const char *ruleset = nullptr, bool reload = false);
|
||||
void SaveRules(Database *db, const char *ruleset = nullptr);
|
||||
bool UpdateInjectedRules(Database *db, const char *ruleset_name, bool quiet_update = false);
|
||||
bool UpdateOrphanedRules(Database *db, bool quiet_update = false);
|
||||
bool RestoreRuleNotes(Database *db);
|
||||
|
||||
private:
|
||||
RuleManager();
|
||||
@ -137,15 +143,17 @@ private:
|
||||
|
||||
static bool _FindRule(const char *rule_name, RuleType &type_into, uint16 &index_into);
|
||||
static const char *_GetRuleName(RuleType type, uint16 index);
|
||||
static const std::string &_GetRuleNotes(RuleType type, uint16 index);
|
||||
static int _FindOrCreateRuleset(Database *db, const char *ruleset);
|
||||
void _SaveRule(Database *db, RuleType type, uint16 index);
|
||||
|
||||
|
||||
static const char *s_categoryNames[];
|
||||
typedef struct {
|
||||
const char *name;
|
||||
CategoryType category;
|
||||
RuleType type;
|
||||
uint16 rule_index; //index into its 'type' array
|
||||
const std::string notes;
|
||||
} RuleInfo;
|
||||
static const RuleInfo s_RuleInfo[];
|
||||
|
||||
|
||||
1228
common/ruletypes.h
1228
common/ruletypes.h
File diff suppressed because it is too large
Load Diff
@ -18,6 +18,7 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <fmt/format.h>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1800
|
||||
#include <algorithm>
|
||||
@ -1460,6 +1461,56 @@ bool SharedDatabase::GetCommandSettings(std::map<std::string, std::pair<uint8, s
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SharedDatabase::UpdateInjectedCommandSettings(const std::vector<std::pair<std::string, uint8>> &injected)
|
||||
{
|
||||
if (injected.size()) {
|
||||
|
||||
std::string query = fmt::format(
|
||||
"REPLACE INTO `command_settings`(`command`, `access`) VALUES {}",
|
||||
implode(
|
||||
",",
|
||||
std::pair<char, char>('(', ')'),
|
||||
join_pair(",", std::pair<char, char>('\'', '\''), injected)
|
||||
)
|
||||
);
|
||||
|
||||
if (!QueryDatabase(query).Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LogInfo(
|
||||
"%u New Command%s Added",
|
||||
injected.size(),
|
||||
(injected.size() == 1 ? "" : "s")
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SharedDatabase::UpdateOrphanedCommandSettings(const std::vector<std::string> &orphaned)
|
||||
{
|
||||
if (orphaned.size()) {
|
||||
|
||||
std::string query = fmt::format(
|
||||
"DELETE FROM `command_settings` WHERE `command` IN ({})",
|
||||
implode(",", std::pair<char, char>('\'', '\''), orphaned)
|
||||
);
|
||||
|
||||
if (!QueryDatabase(query).Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LogInfo(
|
||||
"%u Orphaned Command%s Deleted",
|
||||
orphaned.size(),
|
||||
(orphaned.size() == 1 ? "" : "s")
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SharedDatabase::LoadSkillCaps(const std::string &prefix) {
|
||||
skill_caps_mmf.reset(nullptr);
|
||||
|
||||
|
||||
@ -71,6 +71,8 @@ class SharedDatabase : public Database
|
||||
void LoadCharacterInspectMessage(uint32 character_id, InspectMessage_Struct* message);
|
||||
void SaveCharacterInspectMessage(uint32 character_id, const InspectMessage_Struct* message);
|
||||
bool GetCommandSettings(std::map<std::string, std::pair<uint8, std::vector<std::string>>> &command_settings);
|
||||
bool UpdateInjectedCommandSettings(const std::vector<std::pair<std::string, uint8>> &injected);
|
||||
bool UpdateOrphanedCommandSettings(const std::vector<std::string> &orphaned);
|
||||
uint32 GetTotalTimeEntitledOnAccount(uint32 AccountID);
|
||||
void SetMailKey(int CharID, int IPAddress, int MailKey);
|
||||
std::string GetMailKey(int CharID, bool key_only = false);
|
||||
|
||||
@ -526,4 +526,4 @@ bool isAlphaNumeric(const char *text)
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,6 +20,12 @@
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
#include <cstdarg>
|
||||
#include <tuple>
|
||||
|
||||
#ifndef _WIN32
|
||||
// this doesn't appear to affect linux-based systems..need feedback for _WIN64
|
||||
#include <fmt/format.h>
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
|
||||
@ -31,6 +37,93 @@ std::vector<std::string> split(std::string str_to_split, char delimiter);
|
||||
const std::string StringFormat(const char* format, ...);
|
||||
const std::string vStringFormat(const char* format, va_list args);
|
||||
std::string implode(std::string glue, std::vector<std::string> src);
|
||||
|
||||
template <typename T>
|
||||
std::string implode(const std::string &glue, const std::pair<char, char> &encapsulation, const std::vector<T> &src)
|
||||
{
|
||||
if (src.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::ostringstream oss;
|
||||
|
||||
for (const T &src_iter : src) {
|
||||
oss << encapsulation.first << src_iter << encapsulation.second << glue;
|
||||
}
|
||||
|
||||
std::string output(oss.str());
|
||||
output.resize(output.size() - glue.size());
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
// _WIN32 builds require that #include<fmt/format.h> be included in whatever code file the invocation is made from (no header files)
|
||||
template <typename T1, typename T2>
|
||||
std::vector<std::string> join_pair(const std::string &glue, const std::pair<char, char> &encapsulation, const std::vector<std::pair<T1, T2>> &src)
|
||||
{
|
||||
if (src.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<std::string> output;
|
||||
|
||||
for (const std::pair<T1, T2> &src_iter : src) {
|
||||
output.push_back(
|
||||
|
||||
fmt::format(
|
||||
"{}{}{}{}{}{}{}",
|
||||
encapsulation.first,
|
||||
src_iter.first,
|
||||
encapsulation.second,
|
||||
glue,
|
||||
encapsulation.first,
|
||||
src_iter.second,
|
||||
encapsulation.second
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
// _WIN32 builds require that #include<fmt/format.h> be included in whatever code file the invocation is made from (no header files)
|
||||
template <typename T1, typename T2, typename T3, typename T4>
|
||||
std::vector<std::string> join_tuple(const std::string &glue, const std::pair<char, char> &encapsulation, const std::vector<std::tuple<T1, T2, T3, T4>> &src)
|
||||
{
|
||||
if (src.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<std::string> output;
|
||||
|
||||
for (const std::tuple<T1, T2, T3, T4> &src_iter : src) {
|
||||
|
||||
output.push_back(
|
||||
|
||||
fmt::format(
|
||||
"{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}",
|
||||
encapsulation.first,
|
||||
std::get<0>(src_iter),
|
||||
encapsulation.second,
|
||||
glue,
|
||||
encapsulation.first,
|
||||
std::get<1>(src_iter),
|
||||
encapsulation.second,
|
||||
glue,
|
||||
encapsulation.first,
|
||||
std::get<2>(src_iter),
|
||||
encapsulation.second,
|
||||
glue,
|
||||
encapsulation.first,
|
||||
std::get<3>(src_iter),
|
||||
encapsulation.second
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
std::vector<std::string> SplitString(const std::string &s, char delim);
|
||||
std::string EscapeString(const char *src, size_t sz);
|
||||
std::string EscapeString(const std::string &s);
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9142
|
||||
|
||||
#ifdef BOTS
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9025
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9026
|
||||
#else
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 0 // must be 0
|
||||
#endif
|
||||
|
||||
@ -399,11 +399,13 @@ sub build_linux_source {
|
||||
print `git clone https://github.com/EQEmu/Server.git`;
|
||||
|
||||
mkdir($source_dir . "/Server/build") if (!-e $source_dir . "/Server/build");
|
||||
chdir($source_dir . "/Server/build");
|
||||
chdir($source_dir . "/Server");
|
||||
|
||||
print `git submodule init`;
|
||||
print `git submodule update`;
|
||||
|
||||
chdir($source_dir . "/Server/build");
|
||||
|
||||
print "Generating CMake build files...\n";
|
||||
if ($os_flavor eq "fedora_core") {
|
||||
print `cmake $cmake_options -DEQEMU_BUILD_LOGIN=ON -DEQEMU_BUILD_LUA=ON -DLUA_INCLUDE_DIR=/usr/include/lua-5.1/ -G "Unix Makefiles" ..`;
|
||||
|
||||
@ -153,7 +153,7 @@ elif [[ "$OS" == "red_hat" ]]; then
|
||||
yum -y install \
|
||||
open-vm-tools \
|
||||
vim \
|
||||
cmake \
|
||||
cmake3 \
|
||||
boost-* \
|
||||
zlib-devel \
|
||||
mariadb \
|
||||
@ -178,6 +178,12 @@ elif [[ "$OS" == "red_hat" ]]; then
|
||||
"Development Tools" \
|
||||
"Basic Web Server" \
|
||||
"Compatibility Libraries"
|
||||
# Deal with the cmake 3 prerequisite on RHEL/CentOS 6/7 Note: Might break with RHEL/CentOS 8
|
||||
alternatives --install /usr/local/bin/cmake cmake /usr/bin/cmake3 20 \
|
||||
--slave /usr/local/bin/ctest ctest /usr/bin/ctest3 \
|
||||
--slave /usr/local/bin/cpack cpack /usr/bin/cpack3 \
|
||||
--slave /usr/local/bin/ccmake ccmake /usr/bin/ccmake3 \
|
||||
--family cmake
|
||||
|
||||
elif [[ "$OS" == "fedora_core" ]]; then
|
||||
# Do Fedora stuff
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
9023|2019_06_22_bots_owner_option_stats_update.sql|SHOW COLUMNS FROM `bot_owner_options` LIKE 'stats_update'|empty|
|
||||
9024|2019_06_27_bots_pet_get_lost.sql|SELECT `bot_command` FROM `bot_command_settings` WHERE `bot_command` LIKE 'petgetlost'|empty|
|
||||
9025|2019_08_26_bots_owner_option_spawn_message.sql|SHOW COLUMNS FROM `bot_owner_options` LIKE 'spawn_message_enabled'|empty|
|
||||
9026|2019_09_09_bots_owner_options_rework.sql|SHOW COLUMNS FROM `bot_owner_options` LIKE 'option_type'|empty|
|
||||
|
||||
# Upgrade conditions:
|
||||
# This won't be needed after this system is implemented, but it is used database that are not
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
DROP TABLE IF EXISTS `bot_owner_options`;
|
||||
|
||||
CREATE TABLE `bot_owner_options` (
|
||||
`owner_id` INT(11) UNSIGNED NOT NULL,
|
||||
`option_type` SMALLINT(3) UNSIGNED NOT NULL,
|
||||
`option_value` SMALLINT(3) UNSIGNED NULL DEFAULT '0',
|
||||
PRIMARY KEY (`owner_id`, `option_type`)
|
||||
)
|
||||
COLLATE='latin1_swedish_ci'
|
||||
ENGINE=InnoDB;
|
||||
@ -354,16 +354,27 @@ int main(int argc, char** argv) {
|
||||
|
||||
LogInfo("Loading guilds");
|
||||
guild_mgr.LoadGuilds();
|
||||
|
||||
//rules:
|
||||
{
|
||||
if (!RuleManager::Instance()->UpdateOrphanedRules(&database)) {
|
||||
LogInfo("Failed to process 'Orphaned Rules' update operation.");
|
||||
}
|
||||
|
||||
if (!RuleManager::Instance()->UpdateInjectedRules(&database, "default")) {
|
||||
LogInfo("Failed to process 'Injected Rules' for ruleset 'default' update operation.");
|
||||
}
|
||||
|
||||
std::string tmp;
|
||||
if (database.GetVariable("RuleSet", tmp)) {
|
||||
LogInfo("Loading rule set [{}]", tmp.c_str());
|
||||
|
||||
if (!RuleManager::Instance()->LoadRules(&database, tmp.c_str(), false)) {
|
||||
LogInfo("Failed to load ruleset [{}], falling back to defaults", tmp.c_str());
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
if (!RuleManager::Instance()->LoadRules(&database, "default", false)) {
|
||||
LogInfo("No rule set configured, using default rules");
|
||||
}
|
||||
@ -372,17 +383,19 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
EQEmu::InitializeDynamicLookups();
|
||||
LogInfo("Initialized dynamic dictionary entries");
|
||||
if (!RuleManager::Instance()->RestoreRuleNotes(&database)) {
|
||||
LogInfo("Failed to process 'Restore Rule Notes' update operation.");
|
||||
}
|
||||
}
|
||||
|
||||
EQEmu::InitializeDynamicLookups();
|
||||
LogInfo("Initialized dynamic dictionary entries");
|
||||
|
||||
if (RuleB(World, ClearTempMerchantlist)) {
|
||||
LogInfo("Clearing temporary merchant lists");
|
||||
database.ClearMerchantTemp();
|
||||
}
|
||||
|
||||
RuleManager::Instance()->SaveRules(&database);
|
||||
|
||||
LogInfo("Loading EQ time of day");
|
||||
TimeOfDay_Struct eqTime;
|
||||
time_t realtime;
|
||||
|
||||
23
zone/bot.cpp
23
zone/bot.cpp
@ -255,6 +255,18 @@ void Bot::SetBotSpellID(uint32 newSpellID) {
|
||||
this->npc_spells_id = newSpellID;
|
||||
}
|
||||
|
||||
void Bot::SetSurname(std::string bot_surname) {
|
||||
_surname = bot_surname.substr(0, 31);
|
||||
}
|
||||
|
||||
void Bot::SetTitle(std::string bot_title) {
|
||||
_title = bot_title.substr(0, 31);
|
||||
}
|
||||
|
||||
void Bot::SetSuffix(std::string bot_suffix) {
|
||||
_suffix = bot_suffix.substr(0, 31);
|
||||
}
|
||||
|
||||
uint32 Bot::GetBotArcheryRange() {
|
||||
const EQEmu::ItemInstance *range_inst = GetBotItem(EQEmu::invslot::slotRange);
|
||||
const EQEmu::ItemInstance *ammo_inst = GetBotItem(EQEmu::invslot::slotAmmo);
|
||||
@ -3260,7 +3272,7 @@ bool Bot::Spawn(Client* botCharacterOwner) {
|
||||
else
|
||||
this->GetBotOwner()->CastToClient()->Message(Chat::Red, "%s save failed!", this->GetCleanName());
|
||||
|
||||
// Spawn the bot at the bow owner's loc
|
||||
// Spawn the bot at the bot owner's loc
|
||||
this->m_Position.x = botCharacterOwner->GetX();
|
||||
this->m_Position.y = botCharacterOwner->GetY();
|
||||
this->m_Position.z = botCharacterOwner->GetZ();
|
||||
@ -3365,6 +3377,9 @@ void Bot::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) {
|
||||
ns->spawn.helm = helmtexture; //(GetShowHelm() ? helmtexture : 0); //0xFF;
|
||||
ns->spawn.equip_chest2 = texture; //0xFF;
|
||||
ns->spawn.show_name = true;
|
||||
strcpy(ns->spawn.lastName, GetSurname().c_str());
|
||||
strcpy(ns->spawn.title, GetTitle().c_str());
|
||||
strcpy(ns->spawn.suffix, GetSuffix().c_str());
|
||||
const EQEmu::ItemData* item = nullptr;
|
||||
const EQEmu::ItemInstance* inst = nullptr;
|
||||
uint32 spawnedbotid = 0;
|
||||
@ -3499,7 +3514,7 @@ void Bot::LevelBotWithClient(Client* client, uint8 level, bool sendlvlapp) {
|
||||
Bot* bot = *biter;
|
||||
if(bot && (bot->GetLevel() != client->GetLevel())) {
|
||||
bot->SetPetChooser(false); // not sure what this does, but was in bot 'update' code
|
||||
bot->CalcBotStats(client->GetBotOptionStatsUpdate());
|
||||
bot->CalcBotStats(client->GetBotOption(Client::booStatsUpdate));
|
||||
if(sendlvlapp)
|
||||
bot->SendLevelAppearance();
|
||||
// modified from Client::SetLevel()
|
||||
@ -4178,7 +4193,7 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli
|
||||
client->Message(Chat::Lime, "Trade with '%s' resulted in %i accepted item%s, %i returned item%s.", GetCleanName(), accepted_count, ((accepted_count == 1) ? "" : "s"), returned_count, ((returned_count == 1) ? "" : "s"));
|
||||
|
||||
if (accepted_count)
|
||||
CalcBotStats(client->GetBotOptionStatsUpdate());
|
||||
CalcBotStats(client->GetBotOption(Client::booStatsUpdate));
|
||||
}
|
||||
|
||||
bool Bot::Death(Mob *killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill) {
|
||||
@ -4188,7 +4203,7 @@ bool Bot::Death(Mob *killerMob, int32 damage, uint16 spell_id, EQEmu::skills::Sk
|
||||
Save();
|
||||
|
||||
Mob *my_owner = GetBotOwner();
|
||||
if (my_owner && my_owner->IsClient() && my_owner->CastToClient()->GetBotOptionDeathMarquee()) {
|
||||
if (my_owner && my_owner->IsClient() && my_owner->CastToClient()->GetBotOption(Client::booDeathMarquee)) {
|
||||
if (killerMob)
|
||||
my_owner->CastToClient()->SendMarqueeMessage(Chat::Yellow, 510, 0, 1000, 3000, StringFormat("%s has been slain by %s", GetCleanName(), killerMob->GetCleanName()));
|
||||
else
|
||||
|
||||
10
zone/bot.h
10
zone/bot.h
@ -270,7 +270,12 @@ public:
|
||||
bool GetNeedsHateRedux(Mob *tar);
|
||||
bool HasOrMayGetAggro();
|
||||
void SetDefaultBotStance();
|
||||
|
||||
void SetSurname(std::string bot_surname);
|
||||
void SetTitle(std::string bot_title);
|
||||
void SetSuffix(std::string bot_suffix);
|
||||
std::string GetSurname() { return _surname; }
|
||||
std::string GetTitle() { return _title; }
|
||||
std::string GetSuffix() { return _suffix; }
|
||||
inline virtual int32 GetMaxStat();
|
||||
inline virtual int32 GetMaxResist();
|
||||
inline virtual int32 GetMaxSTR();
|
||||
@ -650,6 +655,9 @@ private:
|
||||
uint32 _guildId;
|
||||
uint8 _guildRank;
|
||||
std::string _guildName;
|
||||
std::string _surname;
|
||||
std::string _title;
|
||||
std::string _suffix;
|
||||
uint32 _lastZoneId;
|
||||
bool _rangerAutoWeaponSelect;
|
||||
BotRoleType _botRole;
|
||||
|
||||
@ -1351,10 +1351,13 @@ int bot_command_init(void)
|
||||
bot_command_add("botspawn", "Spawns a created bot", 0, bot_subcommand_bot_spawn) ||
|
||||
bot_command_add("botstance", "Changes the stance of a bot", 0, bot_subcommand_bot_stance) ||
|
||||
bot_command_add("botstopmeleelevel", "Sets the level a caster or spell-casting fighter bot will stop melee combat", 0, bot_subcommand_bot_stop_melee_level) ||
|
||||
bot_command_add("botsuffix", "Sets a bots suffix", 0, bot_subcommand_bot_suffix) ||
|
||||
bot_command_add("botsummon", "Summons bot(s) to your location", 0, bot_subcommand_bot_summon) ||
|
||||
bot_command_add("botsurname", "Sets a bots surname (last name)", 0, bot_subcommand_bot_surname) ||
|
||||
bot_command_add("bottattoo", "Changes the Drakkin tattoo of a bot", 0, bot_subcommand_bot_tattoo) ||
|
||||
bot_command_add("bottogglearcher", "Toggles a archer bot between melee and ranged weapon use", 0, bot_subcommand_bot_toggle_archer) ||
|
||||
bot_command_add("bottogglehelm", "Toggles the helm visibility of a bot between shown and hidden", 0, bot_subcommand_bot_toggle_helm) ||
|
||||
bot_command_add("bottitle", "Sets a bots title", 0, bot_subcommand_bot_title) ||
|
||||
bot_command_add("botupdate", "Updates a bot to reflect any level changes that you have experienced", 0, bot_subcommand_bot_update) ||
|
||||
bot_command_add("botwoad", "Changes the Barbarian woad of a bot", 0, bot_subcommand_bot_woad) ||
|
||||
bot_command_add("charm", "Attempts to have a bot charm your target", 0, bot_command_charm) ||
|
||||
@ -1426,35 +1429,93 @@ int bot_command_init(void)
|
||||
std::map<std::string, std::pair<uint8, std::vector<std::string>>> bot_command_settings;
|
||||
database.botdb.LoadBotCommandSettings(bot_command_settings);
|
||||
|
||||
std::vector<std::pair<std::string, uint8>> injected_bot_command_settings;
|
||||
std::vector<std::string> orphaned_bot_command_settings;
|
||||
|
||||
for (auto bcs_iter : bot_command_settings) {
|
||||
|
||||
auto bcl_iter = bot_command_list.find(bcs_iter.first);
|
||||
if (bcl_iter == bot_command_list.end()) {
|
||||
|
||||
orphaned_bot_command_settings.push_back(bcs_iter.first);
|
||||
LogInfo(
|
||||
"Bot Command '%s' no longer exists... Deleting orphaned entry from `bot_command_settings` table...",
|
||||
bcs_iter.first.c_str()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (orphaned_bot_command_settings.size()) {
|
||||
if (!database.botdb.UpdateOrphanedBotCommandSettings(orphaned_bot_command_settings)) {
|
||||
LogInfo("Failed to process 'Orphaned Bot Commands' update operation.");
|
||||
}
|
||||
}
|
||||
|
||||
auto working_bcl = bot_command_list;
|
||||
for (auto working_bcl_iter : working_bcl) {
|
||||
auto bot_command_settings_iter = bot_command_settings.find(working_bcl_iter.first);
|
||||
if (bot_command_settings_iter == bot_command_settings.end()) {
|
||||
if (working_bcl_iter.second->access == 0)
|
||||
LogCommands("bot_command_init(): Warning: Bot Command [{}] defaulting to access level 0!", working_bcl_iter.first.c_str());
|
||||
|
||||
auto bcs_iter = bot_command_settings.find(working_bcl_iter.first);
|
||||
if (bcs_iter == bot_command_settings.end()) {
|
||||
|
||||
injected_bot_command_settings.push_back(std::pair<std::string, uint8>(working_bcl_iter.first, working_bcl_iter.second->access));
|
||||
LogInfo(
|
||||
"New Bot Command '%s' found... Adding to `bot_command_settings` table with access '%u'...",
|
||||
working_bcl_iter.first.c_str(),
|
||||
working_bcl_iter.second->access
|
||||
);
|
||||
|
||||
if (working_bcl_iter.second->access == 0) {
|
||||
LogCommands(
|
||||
"bot_command_init(): Warning: Bot Command '%s' defaulting to access level 0!",
|
||||
working_bcl_iter.first.c_str()
|
||||
);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
working_bcl_iter.second->access = bot_command_settings_iter->second.first;
|
||||
LogCommands("bot_command_init(): - Bot Command [{}] set to access level [{}]", working_bcl_iter.first.c_str(), bot_command_settings_iter->second.first);
|
||||
if (bot_command_settings_iter->second.second.empty())
|
||||
working_bcl_iter.second->access = bcs_iter->second.first;
|
||||
LogCommands(
|
||||
"bot_command_init(): - Bot Command '%s' set to access level %d.",
|
||||
working_bcl_iter.first.c_str(),
|
||||
bcs_iter->second.first
|
||||
);
|
||||
|
||||
if (bcs_iter->second.second.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto alias_iter : bot_command_settings_iter->second.second) {
|
||||
if (alias_iter.empty())
|
||||
for (auto alias_iter : bcs_iter->second.second) {
|
||||
if (alias_iter.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bot_command_list.find(alias_iter) != bot_command_list.end()) {
|
||||
LogCommands("bot_command_init(): Warning: Alias [{}] already exists as a bot command - skipping!", alias_iter.c_str());
|
||||
LogCommands(
|
||||
"bot_command_init(): Warning: Alias '%s' already exists as a bot command - skipping!",
|
||||
alias_iter.c_str()
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
bot_command_list[alias_iter] = working_bcl_iter.second;
|
||||
bot_command_aliases[alias_iter] = working_bcl_iter.first;
|
||||
|
||||
LogCommands("bot_command_init(): - Alias [{}] added to bot command [{}]", alias_iter.c_str(), bot_command_aliases[alias_iter].c_str());
|
||||
LogCommands(
|
||||
"bot_command_init(): - Alias '%s' added to bot command '%s'.",
|
||||
alias_iter.c_str(),
|
||||
bot_command_aliases[alias_iter].c_str()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (injected_bot_command_settings.size()) {
|
||||
if (!database.botdb.UpdateInjectedBotCommandSettings(injected_bot_command_settings)) {
|
||||
LogInfo("Failed to process 'Injected Bot Commands' update operation.");
|
||||
}
|
||||
}
|
||||
|
||||
bot_command_dispatch = bot_command_real_dispatch;
|
||||
|
||||
BCSpells::Load();
|
||||
@ -3443,63 +3504,180 @@ void bot_command_movement_speed(Client *c, const Seperator *sep)
|
||||
void bot_command_owner_option(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (helper_is_help_or_usage(sep->arg[1])) {
|
||||
c->Message(m_usage, "usage: %s [deathmarquee | statsupdate] (argument: enable | disable | null (toggles))", sep->arg[0]);
|
||||
c->Message(m_usage, "usage: %s [spawnmessage] [argument: say | tell | silent | class | default]", sep->arg[0]);
|
||||
|
||||
c->Message(m_usage, "usage: %s [option] [argument | null]", sep->arg[0]);
|
||||
|
||||
std::string window_title = "Bot Owner Options";
|
||||
std::string window_text =
|
||||
"<table>"
|
||||
"<tr>"
|
||||
"<td><c \"#FFFFFF\">Option</td>"
|
||||
"<td>Argument</td>"
|
||||
"<td>Notes</td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td><c \"#FFFFFF\">deathmarquee</td>"
|
||||
"<td><c \"#00FF00\">enable</td>"
|
||||
"<td></td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td></td>"
|
||||
"<td><c \"#00FF00\">disable</td>"
|
||||
"<td></td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td></td>"
|
||||
"<td><c \"#00FFFF\">null</td>"
|
||||
"<td><c \"#AAAAAA\">(toggles)</td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td><c \"#FFFFFF\">statsupdate</td>"
|
||||
"<td><c \"#00FF00\">enable</td>"
|
||||
"<td></td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td></td>"
|
||||
"<td><c \"#00FF00\">disable</td>"
|
||||
"<td></td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td></td>"
|
||||
"<td><c \"#00FFFF\">null</td>"
|
||||
"<td><c \"#AAAAAA\">(toggles)</td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td><c \"#FFFFFF\">spawnmessage</td>"
|
||||
"<td><c \"#00FF00\">say</td>"
|
||||
"<td></td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td></td>"
|
||||
"<td><c \"#00FF00\">tell</td>"
|
||||
"<td></td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td></td>"
|
||||
"<td><c \"#00FF00\">silent</td>"
|
||||
"<td></td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td></td>"
|
||||
"<td><c \"#00FF00\">class</td>"
|
||||
"<td></td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td></td>"
|
||||
"<td><c \"#00FF00\">default</td>"
|
||||
"<td></td>"
|
||||
"</tr>"
|
||||
"</table>";
|
||||
|
||||
c->SendPopupToClient(window_title.c_str(), window_text.c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
std::string owner_option = sep->arg[1];
|
||||
std::string argument = sep->arg[2];
|
||||
std::string owner_option(sep->arg[1]);
|
||||
std::string argument(sep->arg[2]);
|
||||
|
||||
if (!owner_option.compare("deathmarquee")) {
|
||||
if (!argument.compare("enable"))
|
||||
c->SetBotOptionDeathMarquee(true);
|
||||
else if (!argument.compare("disable"))
|
||||
c->SetBotOptionDeathMarquee(false);
|
||||
else
|
||||
c->SetBotOptionDeathMarquee(!c->GetBotOptionDeathMarquee());
|
||||
|
||||
database.botdb.SaveOwnerOptionDeathMarquee(c->CharacterID(), c->GetBotOptionDeathMarquee());
|
||||
c->Message(m_action, "Bot 'death marquee' is now %s.", (c->GetBotOptionDeathMarquee() == true ? "enabled" : "disabled"));
|
||||
}
|
||||
else if (!owner_option.compare("statsupdate")) {
|
||||
if (!argument.compare("enable"))
|
||||
c->SetBotOptionStatsUpdate(true);
|
||||
else if (!argument.compare("disable"))
|
||||
c->SetBotOptionStatsUpdate(false);
|
||||
else
|
||||
c->SetBotOptionStatsUpdate(!c->GetBotOptionStatsUpdate());
|
||||
|
||||
database.botdb.SaveOwnerOptionStatsUpdate(c->CharacterID(), c->GetBotOptionStatsUpdate());
|
||||
c->Message(m_action, "Bot 'stats update' is now %s.", (c->GetBotOptionStatsUpdate() == true ? "enabled" : "disabled"));
|
||||
}
|
||||
else if (!owner_option.compare("spawnmessage")) {
|
||||
if (!argument.compare("say")) {
|
||||
c->SetBotOptionSpawnMessageSay();
|
||||
if (!argument.compare("enable")) {
|
||||
c->SetBotOption(Client::booDeathMarquee, true);
|
||||
}
|
||||
else if (!argument.compare("tell")) {
|
||||
c->SetBotOptionSpawnMessageTell();
|
||||
}
|
||||
else if (!argument.compare("silent")) {
|
||||
c->SetBotOptionSpawnMessageSilent();
|
||||
}
|
||||
else if (!argument.compare("class")) {
|
||||
c->SetBotOptionSpawnMessageClassSpecific(true);
|
||||
}
|
||||
else if (!argument.compare("default")) {
|
||||
c->SetBotOptionSpawnMessageClassSpecific(false);
|
||||
else if (!argument.compare("disable")) {
|
||||
c->SetBotOption(Client::booDeathMarquee, false);
|
||||
}
|
||||
else {
|
||||
c->SetBotOption(Client::booDeathMarquee, !c->GetBotOption(Client::booDeathMarquee));
|
||||
}
|
||||
|
||||
database.botdb.SaveOwnerOption(c->CharacterID(), Client::booDeathMarquee, c->GetBotOption(Client::booDeathMarquee));
|
||||
|
||||
c->Message(m_action, "Bot 'death marquee' is now %s.", (c->GetBotOption(Client::booDeathMarquee) == true ? "enabled" : "disabled"));
|
||||
}
|
||||
else if (!owner_option.compare("statsupdate")) {
|
||||
|
||||
if (!argument.compare("enable")) {
|
||||
c->SetBotOption(Client::booStatsUpdate, true);
|
||||
}
|
||||
else if (!argument.compare("disable")) {
|
||||
c->SetBotOption(Client::booStatsUpdate, false);
|
||||
}
|
||||
else {
|
||||
c->SetBotOption(Client::booStatsUpdate, !c->GetBotOption(Client::booStatsUpdate));
|
||||
}
|
||||
|
||||
database.botdb.SaveOwnerOption(c->CharacterID(), Client::booStatsUpdate, c->GetBotOption(Client::booStatsUpdate));
|
||||
|
||||
c->Message(m_action, "Bot 'stats update' is now %s.", (c->GetBotOption(Client::booStatsUpdate) == true ? "enabled" : "disabled"));
|
||||
}
|
||||
else if (!owner_option.compare("spawnmessage")) {
|
||||
|
||||
Client::BotOwnerOption boo = Client::_booCount;
|
||||
|
||||
if (!argument.compare("say")) {
|
||||
|
||||
boo = Client::booSpawnMessageSay;
|
||||
c->SetBotOption(Client::booSpawnMessageSay, true);
|
||||
c->SetBotOption(Client::booSpawnMessageTell, false);
|
||||
}
|
||||
else if (!argument.compare("tell")) {
|
||||
|
||||
boo = Client::booSpawnMessageSay;
|
||||
c->SetBotOption(Client::booSpawnMessageSay, false);
|
||||
c->SetBotOption(Client::booSpawnMessageTell, true);
|
||||
}
|
||||
else if (!argument.compare("silent")) {
|
||||
|
||||
boo = Client::booSpawnMessageSay;
|
||||
c->SetBotOption(Client::booSpawnMessageSay, false);
|
||||
c->SetBotOption(Client::booSpawnMessageTell, false);
|
||||
}
|
||||
else if (!argument.compare("class")) {
|
||||
|
||||
boo = Client::booSpawnMessageClassSpecific;
|
||||
c->SetBotOption(Client::booSpawnMessageClassSpecific, true);
|
||||
}
|
||||
else if (!argument.compare("default")) {
|
||||
|
||||
boo = Client::booSpawnMessageClassSpecific;
|
||||
c->SetBotOption(Client::booSpawnMessageClassSpecific, false);
|
||||
}
|
||||
else {
|
||||
|
||||
c->Message(m_fail, "Owner option '%s' argument '%s' is not recognized.", owner_option.c_str(), argument.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
database.botdb.SaveOwnerOptionSpawnMessage(
|
||||
c->CharacterID(),
|
||||
c->GetBotOptionSpawnMessageSay(),
|
||||
c->GetBotOptionSpawnMessageTell(),
|
||||
c->GetBotOptionSpawnMessageClassSpecific()
|
||||
);
|
||||
if (boo == Client::booSpawnMessageSay) {
|
||||
|
||||
database.botdb.SaveOwnerOption(
|
||||
c->CharacterID(),
|
||||
std::pair<size_t, size_t>(
|
||||
Client::booSpawnMessageSay,
|
||||
Client::booSpawnMessageTell
|
||||
),
|
||||
std::pair<bool, bool>(
|
||||
c->GetBotOption(Client::booSpawnMessageSay),
|
||||
c->GetBotOption(Client::booSpawnMessageTell)
|
||||
)
|
||||
);
|
||||
}
|
||||
else if (boo == Client::booSpawnMessageClassSpecific) {
|
||||
|
||||
database.botdb.SaveOwnerOption(
|
||||
c->CharacterID(),
|
||||
Client::booSpawnMessageClassSpecific,
|
||||
c->GetBotOption(Client::booSpawnMessageClassSpecific)
|
||||
);
|
||||
}
|
||||
else {
|
||||
|
||||
c->Message(m_action, "Bot 'spawn message' is now ERROR.");
|
||||
return;
|
||||
}
|
||||
|
||||
c->Message(m_action, "Bot 'spawn message' is now %s.", argument.c_str());
|
||||
}
|
||||
else {
|
||||
@ -4408,7 +4586,7 @@ void bot_subcommand_bot_create(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
std::string bot_name = sep->arg[1];
|
||||
|
||||
bot_name = ucfirst(bot_name);
|
||||
if (sep->arg[2][0] == '\0' || !sep->IsNumber(2)) {
|
||||
c->Message(m_fail, "Invalid Class!");
|
||||
return;
|
||||
@ -4936,17 +5114,22 @@ void bot_subcommand_bot_list(Client *c, const Seperator *sep)
|
||||
if (helper_command_alias_fail(c, "bot_subcommand_bot_list", sep->arg[0], "botlist"))
|
||||
return;
|
||||
if (helper_is_help_or_usage(sep->arg[1])) {
|
||||
c->Message(m_usage, "usage: %s ([class] [value]) ([race] [value]) ([name] [partial-full])", sep->arg[0]);
|
||||
c->Message(m_usage, "usage: %s (account) ([class] [value]) ([race] [value]) ([name] [partial-full])", sep->arg[0]);
|
||||
c->Message(m_note, "note: filter criteria is orderless and optional");
|
||||
return;
|
||||
}
|
||||
|
||||
bool Account = false;
|
||||
int seps = 1;
|
||||
uint32 filter_value[FilterCount];
|
||||
int name_criteria_arg = 0;
|
||||
memset(&filter_value, 0, sizeof(uint32) * FilterCount);
|
||||
|
||||
int filter_mask = 0;
|
||||
for (int i = 1; i < (FilterCount * 2); i += 2) {
|
||||
if (strcasecmp(sep->arg[1], "account") == 0) {
|
||||
Account = true;
|
||||
seps = 2;
|
||||
}
|
||||
for (int i = seps; i < (FilterCount * 2); i += 2) {
|
||||
if (sep->arg[i][0] == '\0')
|
||||
break;
|
||||
|
||||
@ -4971,7 +5154,7 @@ void bot_subcommand_bot_list(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
std::list<BotsAvailableList> bots_list;
|
||||
if (!database.botdb.LoadBotsList(c->CharacterID(), bots_list)) {
|
||||
if (!database.botdb.LoadBotsList(c->CharacterID(), bots_list, Account)) {
|
||||
c->Message(m_fail, "%s", BotDatabase::fail::LoadBotsList());
|
||||
return;
|
||||
}
|
||||
@ -4981,6 +5164,7 @@ void bot_subcommand_bot_list(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
int bot_count = 0;
|
||||
int bots_owned = 0;
|
||||
for (auto bots_iter : bots_list) {
|
||||
if (filter_mask) {
|
||||
if ((filter_mask & MaskClass) && filter_value[FilterClass] != bots_iter.Class)
|
||||
@ -4996,23 +5180,26 @@ void bot_subcommand_bot_list(Client *c, const Seperator *sep)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
c->Message(m_message, "%s is a level %u %s %s %s",
|
||||
bots_iter.Name,
|
||||
Bot * botCheckNotOnline = entity_list.GetBotByBotName(bots_iter.Name);
|
||||
std::string botspawn_saylink = StringFormat("^botspawn %s", bots_iter.Name);
|
||||
c->Message(Chat::White, "%s is a level %u %s %s %s who is owned by %s",
|
||||
((c->CharacterID() == bots_iter.Owner_ID) && (!botCheckNotOnline) ? (EQEmu::SayLinkEngine::GenerateQuestSaylink(botspawn_saylink, false, bots_iter.Name).c_str()) : (bots_iter.Name)),
|
||||
bots_iter.Level,
|
||||
Bot::RaceIdToString(bots_iter.Race).c_str(),
|
||||
((bots_iter.Gender == FEMALE) ? ("Female") : ((bots_iter.Gender == MALE) ? ("Male") : ("Neuter"))),
|
||||
Bot::ClassIdToString(bots_iter.Class).c_str()
|
||||
Bot::ClassIdToString(bots_iter.Class).c_str(),
|
||||
bots_iter.Owner
|
||||
);
|
||||
|
||||
if (c->CharacterID() == bots_iter.Owner_ID) { ++bots_owned; }
|
||||
++bot_count;
|
||||
}
|
||||
if (!bot_count) {
|
||||
c->Message(m_fail, "You have no bots meeting this criteria");
|
||||
c->Message(Chat::Red, "You have no bots meeting this criteria");
|
||||
}
|
||||
else {
|
||||
c->Message(m_action, "%i of %i bot%s shown", bot_count, bots_list.size(), ((bot_count != 1) ? ("s") : ("")));
|
||||
c->Message(m_message, "Your limit is %i bot%s", RuleI(Bots, CreationLimit), ((RuleI(Bots, CreationLimit) != 1) ? ("s") : ("")));
|
||||
c->Message(Chat::Yellow, "%i of %i bot%s shown.", bot_count, bots_list.size(), ((bot_count != 1) ? ("s") : ("")));
|
||||
c->Message(Chat::Yellow, "%i of %i bot%s are owned by you. (You may spawn any available by clicking name)", bots_owned, bot_count, ((bot_count != 1) ? ("s") : ("")));
|
||||
c->Message(Chat::White, "Your limit is %i bot%s", RuleI(Bots, CreationLimit), ((RuleI(Bots, CreationLimit) != 1) ? ("s") : ("")));
|
||||
}
|
||||
}
|
||||
|
||||
@ -5058,6 +5245,103 @@ void bot_subcommand_bot_out_of_combat(Client *c, const Seperator *sep)
|
||||
}
|
||||
}
|
||||
|
||||
void bot_subcommand_bot_surname(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (sep->arg[1][0] == '\0' || sep->IsNumber(1)) {
|
||||
c->Message(Chat::Red, "You must specify a [surname] to use this command (use _ to define spaces or -remove to clear.)");
|
||||
return;
|
||||
}
|
||||
auto my_bot = ActionableBots::AsTarget_ByBot(c);
|
||||
if (!my_bot) {
|
||||
c->Message(Chat::Red, "You must <target> a bot that you own to use this command");
|
||||
return;
|
||||
}
|
||||
if (strlen(sep->arg[1]) > 31) {
|
||||
c->Message(Chat::Red, "Surname must be 31 characters or less.");
|
||||
return;
|
||||
}
|
||||
std::string bot_surname = sep->arg[1];
|
||||
bot_surname = (bot_surname == "-remove") ? "" : bot_surname;
|
||||
std::replace(bot_surname.begin(), bot_surname.end(), '_', ' ');
|
||||
my_bot->SetSurname(bot_surname);
|
||||
if (!database.botdb.SaveBot(my_bot)) {
|
||||
c->Message(Chat::Red, BotDatabase::fail::SaveBot());
|
||||
return;
|
||||
}
|
||||
else {
|
||||
auto outapp = new EQApplicationPacket(OP_GMLastName, sizeof(GMLastName_Struct));
|
||||
GMLastName_Struct * gmn = (GMLastName_Struct*)outapp->pBuffer;
|
||||
strcpy(gmn->name, my_bot->GetCleanName());
|
||||
strcpy(gmn->gmname, my_bot->GetCleanName());
|
||||
strcpy(gmn->lastname, my_bot->GetSurname().c_str());
|
||||
gmn->unknown[0] = 1;
|
||||
gmn->unknown[1] = 1;
|
||||
gmn->unknown[2] = 1;
|
||||
gmn->unknown[3] = 1;
|
||||
entity_list.QueueClients(my_bot->CastToClient(), outapp);
|
||||
safe_delete(outapp);
|
||||
c->Message(Chat::Yellow, "Bot Surname Saved.");
|
||||
}
|
||||
}
|
||||
|
||||
void bot_subcommand_bot_title(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (sep->arg[1][0] == '\0' || sep->IsNumber(1)) {
|
||||
c->Message(Chat::Red, "You must specify a [title] to use this command. (use _ to define spaces or -remove to clear.)");
|
||||
return;
|
||||
}
|
||||
auto my_bot = ActionableBots::AsTarget_ByBot(c);
|
||||
if (!my_bot) {
|
||||
c->Message(Chat::Red, "You must <target> a bot that you own to use this command");
|
||||
return;
|
||||
}
|
||||
if (strlen(sep->arg[1]) > 31) {
|
||||
c->Message(Chat::Red, "Title must be 31 characters or less.");
|
||||
return;
|
||||
}
|
||||
std::string bot_title = sep->arg[1];
|
||||
bot_title = (bot_title == "-remove") ? "" : bot_title;
|
||||
std::replace(bot_title.begin(), bot_title.end(), '_', ' ');
|
||||
my_bot->SetTitle(bot_title);
|
||||
if (!database.botdb.SaveBot(my_bot)) {
|
||||
c->Message(Chat::Red, BotDatabase::fail::SaveBot());
|
||||
return;
|
||||
}
|
||||
else {
|
||||
my_bot->CastToClient()->SetAATitle(my_bot->GetTitle().c_str());
|
||||
c->Message(Chat::Yellow, "Bot Title Saved.");
|
||||
}
|
||||
}
|
||||
|
||||
void bot_subcommand_bot_suffix(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (sep->arg[1][0] == '\0' || sep->IsNumber(1)) {
|
||||
c->Message(Chat::Red, "You must specify a [suffix] to use this command. (use _ to define spaces or -remove to clear.)");
|
||||
return;
|
||||
}
|
||||
auto my_bot = ActionableBots::AsTarget_ByBot(c);
|
||||
if (!my_bot) {
|
||||
c->Message(Chat::Red, "You must <target> a bot that you own to use this command");
|
||||
return;
|
||||
}
|
||||
if (strlen(sep->arg[1]) > 31) {
|
||||
c->Message(Chat::Red, "Suffix must be 31 characters or less.");
|
||||
return;
|
||||
}
|
||||
std::string bot_suffix = sep->arg[1];
|
||||
bot_suffix = (bot_suffix == "-remove") ? "" : bot_suffix;
|
||||
std::replace(bot_suffix.begin(), bot_suffix.end(), '_', ' ');
|
||||
my_bot->SetSuffix(bot_suffix);
|
||||
if (!database.botdb.SaveBot(my_bot)) {
|
||||
c->Message(Chat::Red, BotDatabase::fail::SaveBot());
|
||||
return;
|
||||
}
|
||||
else {
|
||||
my_bot->CastToClient()->SetTitleSuffix(my_bot->GetSuffix().c_str());
|
||||
c->Message(Chat::Yellow, "Bot Suffix Saved.");
|
||||
}
|
||||
}
|
||||
|
||||
void bot_subcommand_bot_report(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (helper_command_alias_fail(c, "bot_subcommand_bot_report", sep->arg[0], "botreport"))
|
||||
@ -5221,13 +5505,16 @@ void bot_subcommand_bot_spawn(Client *c, const Seperator *sep)
|
||||
};
|
||||
|
||||
uint8 message_index = 0;
|
||||
if (c->GetBotOptionSpawnMessageClassSpecific())
|
||||
if (c->GetBotOption(Client::booSpawnMessageClassSpecific)) {
|
||||
message_index = VALIDATECLASSID(my_bot->GetClass());
|
||||
}
|
||||
|
||||
if (c->GetBotOptionSpawnMessageSay())
|
||||
if (c->GetBotOption(Client::booSpawnMessageSay)) {
|
||||
Bot::BotGroupSay(my_bot, "%s", bot_spawn_message[message_index]);
|
||||
else if (c->GetBotOptionSpawnMessageTell())
|
||||
}
|
||||
else if (c->GetBotOption(Client::booSpawnMessageTell)) {
|
||||
c->Message(Chat::Tell, "%s tells you, \"%s\"", my_bot->GetCleanName(), bot_spawn_message[message_index]);
|
||||
}
|
||||
}
|
||||
|
||||
void bot_subcommand_bot_stance(Client *c, const Seperator *sep)
|
||||
@ -5607,7 +5894,7 @@ void bot_subcommand_bot_update(Client *c, const Seperator *sep)
|
||||
continue;
|
||||
|
||||
bot_iter->SetPetChooser(false);
|
||||
bot_iter->CalcBotStats(c->GetBotOptionStatsUpdate());
|
||||
bot_iter->CalcBotStats(c->GetBotOption(Client::booStatsUpdate));
|
||||
bot_iter->SendAppearancePacket(AT_WhoLevel, bot_iter->GetLevel(), true, true);
|
||||
++bot_count;
|
||||
}
|
||||
@ -7396,7 +7683,7 @@ void bot_subcommand_inventory_remove(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
my_bot->BotRemoveEquipItem(slotId);
|
||||
my_bot->CalcBotStats(c->GetBotOptionStatsUpdate());
|
||||
my_bot->CalcBotStats(c->GetBotOption(Client::booStatsUpdate));
|
||||
}
|
||||
|
||||
switch (slotId) {
|
||||
|
||||
@ -614,8 +614,11 @@ void bot_subcommand_bot_report(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_spawn(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_stance(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_stop_melee_level(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_suffix(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_summon(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_surname(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_tattoo(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_title(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_toggle_archer(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_toggle_helm(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_update(Client *c, const Seperator *sep);
|
||||
|
||||
@ -27,6 +27,8 @@
|
||||
#include "bot.h"
|
||||
#include "client.h"
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
|
||||
bool BotDatabase::LoadBotCommandSettings(std::map<std::string, std::pair<uint8, std::vector<std::string>>> &bot_command_settings)
|
||||
{
|
||||
@ -52,6 +54,58 @@ bool BotDatabase::LoadBotCommandSettings(std::map<std::string, std::pair<uint8,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BotDatabase::UpdateInjectedBotCommandSettings(const std::vector<std::pair<std::string, uint8>> &injected)
|
||||
{
|
||||
if (injected.size()) {
|
||||
|
||||
query = fmt::format(
|
||||
"REPLACE INTO `bot_command_settings`(`bot_command`, `access`) VALUES {}",
|
||||
implode(
|
||||
",",
|
||||
std::pair<char, char>('(', ')'),
|
||||
join_pair(",", std::pair<char, char>('\'', '\''), injected)
|
||||
)
|
||||
);
|
||||
|
||||
if (!database.QueryDatabase(query).Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Log(Logs::General,
|
||||
Logs::Status,
|
||||
"%u New Bot Command%s Added",
|
||||
injected.size(),
|
||||
(injected.size() == 1 ? "" : "s")
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BotDatabase::UpdateOrphanedBotCommandSettings(const std::vector<std::string> &orphaned)
|
||||
{
|
||||
if (orphaned.size()) {
|
||||
|
||||
query = fmt::format(
|
||||
"DELETE FROM `bot_command_settings` WHERE `bot_command` IN ({})",
|
||||
implode(",", std::pair<char, char>('\'', '\''), orphaned)
|
||||
);
|
||||
|
||||
if (!database.QueryDatabase(query).Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Log(Logs::General,
|
||||
Logs::Status,
|
||||
"%u Orphaned Bot Command%s Deleted",
|
||||
orphaned.size(),
|
||||
(orphaned.size() == 1 ? "" : "s")
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BotDatabase::LoadBotSpellCastingChances()
|
||||
{
|
||||
query =
|
||||
@ -163,12 +217,19 @@ bool BotDatabase::LoadQuestableSpawnCount(const uint32 owner_id, int& spawn_coun
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BotDatabase::LoadBotsList(const uint32 owner_id, std::list<BotsAvailableList>& bots_list)
|
||||
bool BotDatabase::LoadBotsList(const uint32 owner_id, std::list<BotsAvailableList>& bots_list, bool ByAccount)
|
||||
{
|
||||
if (!owner_id)
|
||||
return false;
|
||||
|
||||
query = StringFormat("SELECT `bot_id`, `name`, `class`, `level`, `race`, `gender` FROM `bot_data` WHERE `owner_id` = '%u'", owner_id);
|
||||
if (ByAccount == true)
|
||||
query = StringFormat("SELECT bot_id, bd.`name`, bd.class, bd.`level`, bd.race, bd.gender, cd.`name` as owner, bd.owner_id, cd.account_id, cd.id"
|
||||
" FROM bot_data as bd inner join character_data as cd on bd.owner_id = cd.id"
|
||||
" WHERE cd.account_id = (select account_id from bot_data bd inner join character_data as cd on bd.owner_id = cd.id where bd.owner_id = '%u' LIMIT 1)"
|
||||
" ORDER BY bd.owner_id", owner_id);
|
||||
else
|
||||
query = StringFormat("SELECT `bot_id`, `name`, `class`, `level`, `race`, `gender`, 'You' as owner, owner_id FROM `bot_data` WHERE `owner_id` = '%u'", owner_id);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return false;
|
||||
@ -186,12 +247,17 @@ bool BotDatabase::LoadBotsList(const uint32 owner_id, std::list<BotsAvailableLis
|
||||
bot_name = bot_name.substr(0, 63);
|
||||
if (!bot_name.empty())
|
||||
strcpy(bot_entry.Name, bot_name.c_str());
|
||||
|
||||
memset(&bot_entry.Owner, 0, sizeof(bot_entry.Owner));
|
||||
std::string bot_owner = row[6];
|
||||
if (bot_owner.size() > 63)
|
||||
bot_owner = bot_owner.substr(0, 63);
|
||||
if (!bot_owner.empty())
|
||||
strcpy(bot_entry.Owner, bot_owner.c_str());
|
||||
bot_entry.Class = atoi(row[2]);
|
||||
bot_entry.Level = atoi(row[3]);
|
||||
bot_entry.Race = atoi(row[4]);
|
||||
bot_entry.Gender = atoi(row[5]);
|
||||
|
||||
bot_entry.Owner_ID = atoi(row[7]);
|
||||
bots_list.push_back(bot_entry);
|
||||
}
|
||||
|
||||
@ -266,8 +332,8 @@ bool BotDatabase::LoadBot(const uint32 bot_id, Bot*& loaded_bot)
|
||||
" `spells_id`,"
|
||||
" `name`,"
|
||||
" `last_name`,"
|
||||
" `title`," /* planned use[4] */
|
||||
" `suffix`," /* planned use[5] */
|
||||
" `title`,"
|
||||
" `suffix`,"
|
||||
" `zone_id`,"
|
||||
" `gender`,"
|
||||
" `race`,"
|
||||
@ -364,7 +430,9 @@ bool BotDatabase::LoadBot(const uint32 bot_id, Bot*& loaded_bot)
|
||||
loaded_bot = new Bot(bot_id, atoi(row[0]), atoi(row[1]), atof(row[14]), atoi(row[6]), tempNPCStruct);
|
||||
if (loaded_bot) {
|
||||
loaded_bot->SetShowHelm((atoi(row[43]) > 0 ? true : false));
|
||||
|
||||
loaded_bot->SetSurname(row[3]);//maintaining outside mob::lastname to cater to spaces
|
||||
loaded_bot->SetTitle(row[4]);
|
||||
loaded_bot->SetSuffix(row[5]);
|
||||
uint32 bfd = atoi(row[44]);
|
||||
if (bfd < 1)
|
||||
bfd = 1;
|
||||
@ -573,12 +641,14 @@ bool BotDatabase::SaveBot(Bot* bot_inst)
|
||||
" `corruption` = '%i',"
|
||||
" `show_helm` = '%i',"
|
||||
" `follow_distance` = '%i',"
|
||||
" `stop_melee_level` = '%u'"
|
||||
" `stop_melee_level` = '%u',"
|
||||
" `title` = '%s',"
|
||||
" `suffix` = '%s'"
|
||||
" WHERE `bot_id` = '%u'",
|
||||
bot_inst->GetBotOwnerCharacterID(),
|
||||
bot_inst->GetBotSpellID(),
|
||||
bot_inst->GetCleanName(),
|
||||
bot_inst->GetLastName(),
|
||||
bot_inst->GetSurname().c_str(),
|
||||
bot_inst->GetLastZoneID(),
|
||||
bot_inst->GetBaseGender(),
|
||||
bot_inst->GetBaseRace(),
|
||||
@ -616,6 +686,8 @@ bool BotDatabase::SaveBot(Bot* bot_inst)
|
||||
((bot_inst->GetShowHelm()) ? (1) : (0)),
|
||||
bot_inst->GetFollowDistance(),
|
||||
bot_inst->GetStopMeleeLevel(),
|
||||
bot_inst->GetTitle().c_str(),
|
||||
bot_inst->GetSuffix().c_str(),
|
||||
bot_inst->GetBotID()
|
||||
);
|
||||
auto results = database.QueryDatabase(query);
|
||||
@ -2153,111 +2225,92 @@ bool BotDatabase::SaveStopMeleeLevel(const uint32 owner_id, const uint32 bot_id,
|
||||
|
||||
bool BotDatabase::LoadOwnerOptions(Client *owner)
|
||||
{
|
||||
if (!owner || !owner->CharacterID())
|
||||
return false;
|
||||
|
||||
query = StringFormat(
|
||||
"SELECT `death_marquee`, `stats_update`, `spawn_message_enabled`, `spawn_message_type` FROM `bot_owner_options`"
|
||||
" WHERE `owner_id` = '%u'",
|
||||
owner->CharacterID()
|
||||
);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return false;
|
||||
if (!results.RowCount()) {
|
||||
query = StringFormat("REPLACE INTO `bot_owner_options` (`owner_id`) VALUES ('%u')", owner->CharacterID());
|
||||
results = database.QueryDatabase(query);
|
||||
|
||||
if (!owner || !owner->CharacterID()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
owner->SetBotOptionDeathMarquee((atoi(row[0]) != 0));
|
||||
owner->SetBotOptionStatsUpdate((atoi(row[1]) != 0));
|
||||
switch (atoi(row[2])) {
|
||||
case 2:
|
||||
owner->SetBotOptionSpawnMessageSay();
|
||||
break;
|
||||
case 1:
|
||||
owner->SetBotOptionSpawnMessageTell();
|
||||
break;
|
||||
query = fmt::format("SELECT `option_type`, `option_value` FROM `bot_owner_options` WHERE `owner_id` = '{}'", owner->CharacterID());
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto row : results) {
|
||||
|
||||
owner->SetBotOption(static_cast<Client::BotOwnerOption>(atoul(row[0])), (atoul(row[1]) != 0));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BotDatabase::SaveOwnerOption(const uint32 owner_id, size_t type, const bool flag)
|
||||
{
|
||||
if (!owner_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (static_cast<Client::BotOwnerOption>(type)) {
|
||||
case Client::booDeathMarquee:
|
||||
case Client::booStatsUpdate:
|
||||
case Client::booSpawnMessageClassSpecific: {
|
||||
|
||||
query = fmt::format(
|
||||
"REPLACE INTO `bot_owner_options`(`owner_id`, `option_type`, `option_value`) VALUES ('{}', '{}', '{}')",
|
||||
owner_id,
|
||||
type,
|
||||
(flag == true ? 1 : 0)
|
||||
);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
owner->SetBotOptionSpawnMessageSilent();
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
owner->SetBotOptionSpawnMessageClassSpecific((atoi(row[3]) != 0));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BotDatabase::SaveOwnerOptionDeathMarquee(const uint32 owner_id, const bool flag)
|
||||
bool BotDatabase::SaveOwnerOption(const uint32 owner_id, const std::pair<size_t, size_t> type, const std::pair<bool, bool> flag)
|
||||
{
|
||||
if (!owner_id)
|
||||
if (!owner_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
query = StringFormat(
|
||||
"UPDATE `bot_owner_options`"
|
||||
" SET `death_marquee` = '%u'"
|
||||
" WHERE `owner_id` = '%u'",
|
||||
(flag == true ? 1 : 0),
|
||||
owner_id
|
||||
);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
switch (static_cast<Client::BotOwnerOption>(type.first)) {
|
||||
case Client::booSpawnMessageSay:
|
||||
case Client::booSpawnMessageTell: {
|
||||
switch (static_cast<Client::BotOwnerOption>(type.second)) {
|
||||
case Client::booSpawnMessageSay:
|
||||
case Client::booSpawnMessageTell: {
|
||||
|
||||
query = fmt::format(
|
||||
"REPLACE INTO `bot_owner_options`(`owner_id`, `option_type`, `option_value`) VALUES ('{}', '{}', '{}'), ('{}', '{}', '{}')",
|
||||
owner_id,
|
||||
type.first,
|
||||
(flag.first == true ? 1 : 0),
|
||||
owner_id,
|
||||
type.second,
|
||||
(flag.second == true ? 1 : 0)
|
||||
);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BotDatabase::SaveOwnerOptionStatsUpdate(const uint32 owner_id, const bool flag)
|
||||
{
|
||||
if (!owner_id)
|
||||
return false;
|
||||
|
||||
query = StringFormat(
|
||||
"UPDATE `bot_owner_options`"
|
||||
" SET `stats_update` = '%u'"
|
||||
" WHERE `owner_id` = '%u'",
|
||||
(flag == true ? 1 : 0),
|
||||
owner_id
|
||||
);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BotDatabase::SaveOwnerOptionSpawnMessage(const uint32 owner_id, const bool say, const bool tell, const bool class_specific)
|
||||
{
|
||||
if (!owner_id)
|
||||
return false;
|
||||
|
||||
uint8 enabled_value = 0;
|
||||
if (say)
|
||||
enabled_value = 2;
|
||||
else if (tell)
|
||||
enabled_value = 1;
|
||||
|
||||
uint8 type_value = 0;
|
||||
if (class_specific)
|
||||
type_value = 1;
|
||||
|
||||
query = StringFormat(
|
||||
"UPDATE `bot_owner_options`"
|
||||
" SET"
|
||||
" `spawn_message_enabled` = '%u',"
|
||||
" `spawn_message_type` = '%u'"
|
||||
" WHERE `owner_id` = '%u'",
|
||||
enabled_value,
|
||||
type_value,
|
||||
owner_id
|
||||
);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -43,6 +43,8 @@ class BotDatabase
|
||||
{
|
||||
public:
|
||||
bool LoadBotCommandSettings(std::map<std::string, std::pair<uint8, std::vector<std::string>>> &bot_command_settings);
|
||||
bool UpdateInjectedBotCommandSettings(const std::vector<std::pair<std::string, uint8>> &injected);
|
||||
bool UpdateOrphanedBotCommandSettings(const std::vector<std::string> &orphaned);
|
||||
bool LoadBotSpellCastingChances();
|
||||
|
||||
|
||||
@ -50,7 +52,7 @@ public:
|
||||
bool QueryNameAvailablity(const std::string& bot_name, bool& available_flag);
|
||||
bool QueryBotCount(const uint32 owner_id, uint32& bot_count);
|
||||
bool LoadQuestableSpawnCount(const uint32 owner_id, int& spawn_count);
|
||||
bool LoadBotsList(const uint32 owner_id, std::list<BotsAvailableList>& bots_list);
|
||||
bool LoadBotsList(const uint32 owner_id, std::list<BotsAvailableList>& bots_list, bool ByAccount = false);
|
||||
|
||||
bool LoadOwnerID(const std::string& bot_name, uint32& owner_id);
|
||||
bool LoadOwnerID(const uint32 bot_id, uint32& owner_id);
|
||||
@ -139,10 +141,9 @@ public:
|
||||
bool SaveStopMeleeLevel(const uint32 owner_id, const uint32 bot_id, const uint8 sml_value);
|
||||
|
||||
bool LoadOwnerOptions(Client *owner);
|
||||
bool SaveOwnerOptionDeathMarquee(const uint32 owner_id, const bool flag);
|
||||
bool SaveOwnerOptionStatsUpdate(const uint32 owner_id, const bool flag);
|
||||
bool SaveOwnerOptionSpawnMessage(const uint32 owner_id, const bool say, const bool tell, const bool class_specific);
|
||||
|
||||
bool SaveOwnerOption(const uint32 owner_id, size_t type, const bool flag);
|
||||
bool SaveOwnerOption(const uint32 owner_id, const std::pair<size_t, size_t> type, const std::pair<bool, bool> flag);
|
||||
|
||||
/* Bot bot-group functions */
|
||||
bool QueryBotGroupExistence(const std::string& botgroup_name, bool& extant_flag);
|
||||
|
||||
|
||||
@ -32,6 +32,8 @@ struct BotsAvailableList {
|
||||
uint8 Level;
|
||||
uint16 Race;
|
||||
uint8 Gender;
|
||||
char Owner[64];
|
||||
uint32 Owner_ID;
|
||||
};
|
||||
|
||||
struct BotGroup {
|
||||
|
||||
@ -347,7 +347,11 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
dev_tools_window_enabled = true;
|
||||
|
||||
#ifdef BOTS
|
||||
bot_owner_options = DefaultBotOwnerOptions;
|
||||
bot_owner_options[booDeathMarquee] = false;
|
||||
bot_owner_options[booStatsUpdate] = false;
|
||||
bot_owner_options[booSpawnMessageSay] = false;
|
||||
bot_owner_options[booSpawnMessageTell] = true;
|
||||
bot_owner_options[booSpawnMessageClassSpecific] = true;
|
||||
#endif
|
||||
|
||||
AI_Init();
|
||||
@ -9132,4 +9136,24 @@ glm::vec4 &Client::GetLastPositionBeforeBulkUpdate()
|
||||
void Client::SetLastPositionBeforeBulkUpdate(glm::vec4 in_last_position_before_bulk_update)
|
||||
{
|
||||
Client::last_position_before_bulk_update = in_last_position_before_bulk_update;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BOTS
|
||||
|
||||
bool Client::GetBotOption(BotOwnerOption boo) const {
|
||||
|
||||
if (boo < _booCount) {
|
||||
return bot_owner_options[boo];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Client::SetBotOption(BotOwnerOption boo, bool flag) {
|
||||
|
||||
if (boo < _booCount) {
|
||||
bot_owner_options[boo] = flag;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -1627,39 +1627,26 @@ private:
|
||||
int client_max_level;
|
||||
|
||||
#ifdef BOTS
|
||||
struct BotOwnerOptions {
|
||||
bool death_marquee;
|
||||
bool stats_update;
|
||||
bool spawn_message_say;
|
||||
bool spawn_message_tell;
|
||||
bool spawn_message_class_specific;
|
||||
};
|
||||
|
||||
|
||||
BotOwnerOptions bot_owner_options;
|
||||
|
||||
const BotOwnerOptions DefaultBotOwnerOptions = {
|
||||
false, // death_marquee
|
||||
false, // stats_update
|
||||
false, // spawn_message_say
|
||||
true, // spawn_message_tell
|
||||
true // spawn_message_class_specific
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
void SetBotOptionDeathMarquee(bool flag) { bot_owner_options.death_marquee = flag; }
|
||||
void SetBotOptionStatsUpdate(bool flag) { bot_owner_options.stats_update = flag; }
|
||||
void SetBotOptionSpawnMessageSay() { bot_owner_options.spawn_message_say = true; bot_owner_options.spawn_message_tell = false; }
|
||||
void SetBotOptionSpawnMessageTell() { bot_owner_options.spawn_message_say = false; bot_owner_options.spawn_message_tell = true; }
|
||||
void SetBotOptionSpawnMessageSilent() { bot_owner_options.spawn_message_say = false; bot_owner_options.spawn_message_tell = false; }
|
||||
void SetBotOptionSpawnMessageClassSpecific(bool flag) { bot_owner_options.spawn_message_class_specific = flag; }
|
||||
enum BotOwnerOption : size_t {
|
||||
booDeathMarquee,
|
||||
booStatsUpdate,
|
||||
booSpawnMessageSay,
|
||||
booSpawnMessageTell,
|
||||
booSpawnMessageClassSpecific,
|
||||
_booCount
|
||||
};
|
||||
|
||||
bool GetBotOptionDeathMarquee() const { return bot_owner_options.death_marquee; }
|
||||
bool GetBotOptionStatsUpdate() const { return bot_owner_options.stats_update; }
|
||||
bool GetBotOptionSpawnMessageSay() const { return bot_owner_options.spawn_message_say; }
|
||||
bool GetBotOptionSpawnMessageTell() const { return bot_owner_options.spawn_message_tell; }
|
||||
bool GetBotOptionSpawnMessageClassSpecific() const { return bot_owner_options.spawn_message_class_specific; }
|
||||
bool GetBotOption(BotOwnerOption boo) const;
|
||||
void SetBotOption(BotOwnerOption boo, bool flag = true);
|
||||
|
||||
private:
|
||||
bool bot_owner_options[_booCount];
|
||||
|
||||
private:
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@ -3945,9 +3945,11 @@ void Client::Handle_OP_Camp(const EQApplicationPacket *app)
|
||||
#ifdef BOTS
|
||||
// This block is necessary to clean up any bot objects owned by a Client
|
||||
Bot::BotOrderCampAll(this);
|
||||
auto group = GetGroup();
|
||||
if (group && group->GroupCount() < 2)
|
||||
group->DisbandGroup();
|
||||
// Evidently, this is bad under certain conditions and causes crashes...
|
||||
// Group and Raid code really needs to be overhauled to account for non-client types (mercs and bots)
|
||||
//auto group = GetGroup();
|
||||
//if (group && group->GroupCount() < 2)
|
||||
// group->DisbandGroup();
|
||||
#endif
|
||||
if (IsLFP())
|
||||
worldserver.StopLFP(CharacterID());
|
||||
|
||||
173
zone/command.cpp
173
zone/command.cpp
@ -182,6 +182,7 @@ int command_init(void)
|
||||
command_add("crashtest", "- Crash the zoneserver", 255, command_crashtest) ||
|
||||
command_add("cvs", "- Summary of client versions currently online.", 200, command_cvs) ||
|
||||
command_add("damage", "[amount] - Damage your target", 100, command_damage) ||
|
||||
command_add("databuckets", "View|Delete [key] [limit]- View data buckets, limit 50 default or Delete databucket by key", 80, command_databuckets) ||
|
||||
command_add("date", "[yyyy] [mm] [dd] [HH] [MM] - Set EQ time", 90, command_date) ||
|
||||
command_add("dbspawn2", "[spawngroup] [respawn] [variance] - Spawn an NPC from a predefined row in the spawn2 table", 100, command_dbspawn2) ||
|
||||
command_add("delacct", "[accountname] - Delete an account", 150, command_delacct) ||
|
||||
@ -453,33 +454,90 @@ int command_init(void)
|
||||
std::map<std::string, std::pair<uint8, std::vector<std::string>>> command_settings;
|
||||
database.GetCommandSettings(command_settings);
|
||||
|
||||
std::map<std::string, CommandRecord *> working_cl = commandlist;
|
||||
for (auto iter_cl = working_cl.begin(); iter_cl != working_cl.end(); ++iter_cl) {
|
||||
auto iter_cs = command_settings.find(iter_cl->first);
|
||||
if (iter_cs == command_settings.end()) {
|
||||
if (iter_cl->second->access == 0)
|
||||
LogCommands("command_init(): Warning: Command [{}] defaulting to access level 0!", iter_cl->first.c_str());
|
||||
std::vector<std::pair<std::string, uint8>> injected_command_settings;
|
||||
std::vector<std::string> orphaned_command_settings;
|
||||
|
||||
for (auto cs_iter : command_settings) {
|
||||
|
||||
auto cl_iter = commandlist.find(cs_iter.first);
|
||||
if (cl_iter == commandlist.end()) {
|
||||
|
||||
orphaned_command_settings.push_back(cs_iter.first);
|
||||
LogInfo(
|
||||
"Command '%s' no longer exists... Deleting orphaned entry from `command_settings` table...",
|
||||
cs_iter.first.c_str()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (orphaned_command_settings.size()) {
|
||||
if (!database.UpdateOrphanedCommandSettings(orphaned_command_settings)) {
|
||||
LogInfo("Failed to process 'Orphaned Commands' update operation.");
|
||||
}
|
||||
}
|
||||
|
||||
auto working_cl = commandlist;
|
||||
for (auto working_cl_iter : working_cl) {
|
||||
|
||||
auto cs_iter = command_settings.find(working_cl_iter.first);
|
||||
if (cs_iter == command_settings.end()) {
|
||||
|
||||
injected_command_settings.push_back(std::pair<std::string, uint8>(working_cl_iter.first, working_cl_iter.second->access));
|
||||
LogInfo(
|
||||
"New Command '%s' found... Adding to `command_settings` table with access '%u'...",
|
||||
working_cl_iter.first.c_str(),
|
||||
working_cl_iter.second->access
|
||||
);
|
||||
|
||||
if (working_cl_iter.second->access == 0) {
|
||||
LogCommands(
|
||||
"command_init(): Warning: Command '%s' defaulting to access level 0!",
|
||||
working_cl_iter.first.c_str()
|
||||
);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
iter_cl->second->access = iter_cs->second.first;
|
||||
LogCommands("command_init(): - Command [{}] set to access level [{}]", iter_cl->first.c_str(), iter_cs->second.first);
|
||||
if (iter_cs->second.second.empty())
|
||||
working_cl_iter.second->access = cs_iter->second.first;
|
||||
LogCommands(
|
||||
"command_init(): - Command '%s' set to access level %d.",
|
||||
working_cl_iter.first.c_str(),
|
||||
cs_iter->second.first
|
||||
);
|
||||
|
||||
if (cs_iter->second.second.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto iter_aka = iter_cs->second.second.begin(); iter_aka != iter_cs->second.second.end();
|
||||
++iter_aka) {
|
||||
if (iter_aka->empty())
|
||||
continue;
|
||||
if (commandlist.find(*iter_aka) != commandlist.end()) {
|
||||
LogCommands("command_init(): Warning: Alias [{}] already exists as a command - skipping!", iter_aka->c_str());
|
||||
for (auto alias_iter : cs_iter->second.second) {
|
||||
if (alias_iter.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
commandlist[*iter_aka] = iter_cl->second;
|
||||
commandaliases[*iter_aka] = iter_cl->first;
|
||||
if (commandlist.find(alias_iter) != commandlist.end()) {
|
||||
LogCommands(
|
||||
"command_init(): Warning: Alias '%s' already exists as a command - skipping!",
|
||||
alias_iter.c_str()
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
LogCommands("command_init(): - Alias [{}] added to command [{}]", iter_aka->c_str(), commandaliases[*iter_aka].c_str());
|
||||
commandlist[alias_iter] = working_cl_iter.second;
|
||||
commandaliases[alias_iter] = working_cl_iter.first;
|
||||
|
||||
LogCommands(
|
||||
"command_init(): - Alias '%s' added to command '%s'.",
|
||||
alias_iter.c_str(),
|
||||
commandaliases[alias_iter].c_str()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (injected_command_settings.size()) {
|
||||
if (!database.UpdateInjectedCommandSettings(injected_command_settings)) {
|
||||
LogInfo("Failed to process 'Injected Commands' update operation.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -12583,6 +12641,85 @@ void command_scale(Client *c, const Seperator *sep)
|
||||
}
|
||||
}
|
||||
|
||||
void command_databuckets(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (sep->arg[1][0] == 0) {
|
||||
c->Message(Chat::Yellow, "Usage: #databuckets view (partial key)|(limit) OR #databuckets delete (key)");
|
||||
return;
|
||||
}
|
||||
if (strcasecmp(sep->arg[1], "view") == 0) {
|
||||
|
||||
std::string key_filter;
|
||||
uint8 limit = 50;
|
||||
for (int i = 2; i < 4; i++) {
|
||||
if (sep->arg[i][0] == '\0')
|
||||
break;
|
||||
if (strcasecmp(sep->arg[i], "limit") == 0) {
|
||||
limit = (uint8)atoi(sep->arg[i + 1]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (sep->arg[2]) {
|
||||
key_filter = str_tolower(sep->arg[2]);
|
||||
}
|
||||
std::string query = "SELECT `id`, `key`, `value`, `expires` FROM data_buckets";
|
||||
if (!key_filter.empty()) query += StringFormat(" WHERE `key` LIKE '%%%s%%'", key_filter.c_str());
|
||||
query += StringFormat(" LIMIT %u", limit);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return;
|
||||
if (results.RowCount() == 0) {
|
||||
c->Message(Chat::Yellow, "No data_buckets found");
|
||||
return;
|
||||
}
|
||||
int _ctr = 0;
|
||||
// put in window for easier readability in case want command line for something else
|
||||
std::string window_title = "Data Buckets";
|
||||
std::string window_text =
|
||||
"<table>"
|
||||
"<tr>"
|
||||
"<td>ID</td>"
|
||||
"<td>Expires</td>"
|
||||
"<td>Key</td>"
|
||||
"<td>Value</td>"
|
||||
"</tr>";
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
auto id = static_cast<uint32>(atoi(row[0]));
|
||||
std::string key = row[1];
|
||||
std::string value = row[2];
|
||||
std::string expires = row[3];
|
||||
window_text.append(StringFormat(
|
||||
"<tr>"
|
||||
"<td>%u</td>"
|
||||
"<td>%s</td>"
|
||||
"<td>%s</td>"
|
||||
"<td>%s</td>"
|
||||
"</tr>",
|
||||
id,
|
||||
expires.c_str(),
|
||||
key.c_str(),
|
||||
value.c_str()
|
||||
));
|
||||
_ctr++;
|
||||
std::string del_saylink = StringFormat("#databuckets delete %s", key.c_str());
|
||||
c->Message(Chat::White, "%s : %s",
|
||||
EQEmu::SayLinkEngine::GenerateQuestSaylink(del_saylink, false, "Delete").c_str(), key.c_str(), " Value: ", value.c_str());
|
||||
}
|
||||
window_text.append("</table>");
|
||||
c->SendPopupToClient(window_title.c_str(), window_text.c_str());
|
||||
std::string response = _ctr > 0 ? StringFormat("Found %i matching data buckets", _ctr).c_str() : "No Databuckets found.";
|
||||
c->Message(Chat::Yellow, response.c_str());
|
||||
}
|
||||
else if (strcasecmp(sep->arg[1], "delete") == 0)
|
||||
{
|
||||
if (DataBucket::DeleteData(sep->argplus[2]))
|
||||
c->Message(Chat::Yellow, "data bucket %s deleted.", sep->argplus[2]);
|
||||
else
|
||||
c->Message(Chat::Red, "An error occurred deleting data bucket %s", sep->argplus[2]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void command_who(Client *c, const Seperator *sep)
|
||||
{
|
||||
std::string query =
|
||||
|
||||
@ -77,6 +77,7 @@ void command_crashtest(Client *c, const Seperator *sep);
|
||||
void command_cvs(Client *c, const Seperator *sep);
|
||||
void command_d1(Client *c, const Seperator *sep);
|
||||
void command_damage(Client *c, const Seperator *sep);
|
||||
void command_databuckets(Client *c, const Seperator *sep);
|
||||
void command_date(Client *c, const Seperator *sep);
|
||||
void command_dbspawn2(Client *c, const Seperator *sep);
|
||||
void command_delacct(Client *c, const Seperator *sep);
|
||||
|
||||
@ -226,8 +226,7 @@ XS(XS__spawn);
|
||||
XS(XS__spawn) {
|
||||
dXSARGS;
|
||||
if (items != 6)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: quest::spawn(int npc_type_id, int grid_id, int int_unused, float x, float y, float z)");
|
||||
Perl_croak(aTHX_ "Usage: quest::spawn(int npc_type_id, int grid_id, int int_unused, float x, float y, float z)");
|
||||
|
||||
uint16 RETVAL;
|
||||
dXSTARG;
|
||||
@ -249,8 +248,7 @@ XS(XS__spawn2);
|
||||
XS(XS__spawn2) {
|
||||
dXSARGS;
|
||||
if (items != 7)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: quest::spawn2(int npc_type_id, int grid_id, int int_unused, float x, float y, float z, float heading)");
|
||||
Perl_croak(aTHX_ "Usage: quest::spawn2(int npc_type_id, int grid_id, int int_unused, float x, float y, float z, float heading)");
|
||||
|
||||
uint16 RETVAL;
|
||||
dXSTARG;
|
||||
@ -272,8 +270,7 @@ XS(XS__unique_spawn);
|
||||
XS(XS__unique_spawn) {
|
||||
dXSARGS;
|
||||
if (items != 6 && items != 7)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: quest::unique_spawn(int npc_type_id, int grid_id, int int_unused, float x, float y, float z, [float heading])");
|
||||
Perl_croak(aTHX_ "Usage: quest::unique_spawn(int npc_type_id, int grid_id, int int_unused, float x, float y, float z, [float heading])");
|
||||
|
||||
uint16 RETVAL;
|
||||
dXSTARG;
|
||||
@ -1315,8 +1312,7 @@ XS(XS__targlobal);
|
||||
XS(XS__targlobal) {
|
||||
dXSARGS;
|
||||
if (items != 6)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: quest::targlobal(stirng key, string value, string duration, int npc_id, int chararacter_id, int zone_id)");
|
||||
Perl_croak(aTHX_ "Usage: quest::targlobal(stirng key, string value, string duration, int npc_id, int chararacter_id, int zone_id)");
|
||||
|
||||
char *key = (char *) SvPV_nolen(ST(0));
|
||||
char *str_value = (char *) SvPV_nolen(ST(1));
|
||||
@ -1411,8 +1407,7 @@ XS(XS__moveto);
|
||||
XS(XS__moveto) {
|
||||
dXSARGS;
|
||||
if (items != 3 && items != 4 && items != 5)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: quest::moveto(float x, float y, float z, [float heading], [bool save_guard_location])");
|
||||
Perl_croak(aTHX_ "Usage: quest::moveto(float x, float y, float z, [float heading], [bool save_guard_location])");
|
||||
|
||||
float x = (float) SvNV(ST(0));
|
||||
float y = (float) SvNV(ST(1));
|
||||
@ -1561,8 +1556,7 @@ XS(XS__set_proximity);
|
||||
XS(XS__set_proximity) {
|
||||
dXSARGS;
|
||||
if (items != 4 && items != 6 && items != 7)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: quest::set_proximity(float min_x, float max_x, float min_y, float max_y, [float min_z], [float max_z], [say])");
|
||||
Perl_croak(aTHX_ "Usage: quest::set_proximity(float min_x, float max_x, float min_y, float max_y, [float min_z], [float max_z], [say])");
|
||||
|
||||
float min_x = (float) SvNV(ST(0));
|
||||
float max_x = (float) SvNV(ST(1));
|
||||
@ -1643,8 +1637,7 @@ XS(XS__spawn_condition);
|
||||
XS(XS__spawn_condition) {
|
||||
dXSARGS;
|
||||
if (items < 3 || items > 4)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: quest::spawn_condition(string zone_short, [int instance_id], uint16 condition_id, int16 value)");
|
||||
Perl_croak(aTHX_ "Usage: quest::spawn_condition(string zone_short, [int instance_id], uint16 condition_id, int16 value)");
|
||||
|
||||
if (items == 3) {
|
||||
char *zone_short = (char *) SvPV_nolen(ST(0));
|
||||
@ -1701,8 +1694,7 @@ XS(XS__toggle_spawn_event);
|
||||
XS(XS__toggle_spawn_event) {
|
||||
dXSARGS;
|
||||
if (items != 4)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: quest::toggle_spawn_event(uint32 event_id, [bool is_enabled = false], [bool is_strict = false], [bool reset_base = false])");
|
||||
Perl_croak(aTHX_ "Usage: quest::toggle_spawn_event(uint32 event_id, [bool is_enabled = false], [bool is_strict = false], [bool reset_base = false])");
|
||||
|
||||
uint32 event_id = (int) SvIV(ST(0));
|
||||
bool is_enabled = ((int) SvIV(ST(1))) == 0 ? false : true;
|
||||
@ -1763,8 +1755,7 @@ XS(XS__summonburiedplayercorpse);
|
||||
XS(XS__summonburiedplayercorpse) {
|
||||
dXSARGS;
|
||||
if (items != 5)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: quest::summonburiedplayercorpse(uint32 char_id, float dest_x, float dest_y, float dest_z, float dest_heading)");
|
||||
Perl_croak(aTHX_ "Usage: quest::summonburiedplayercorpse(uint32 char_id, float dest_x, float dest_y, float dest_z, float dest_heading)");
|
||||
|
||||
bool RETVAL;
|
||||
uint32 char_id = (int) SvIV(ST(0));
|
||||
@ -1781,8 +1772,7 @@ XS(XS__summonallplayercorpses);
|
||||
XS(XS__summonallplayercorpses) {
|
||||
dXSARGS;
|
||||
if (items != 5)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: quest::summonallplayercorpses(int char_id, float dest_x, float dest_y, float dest_z, float dest_heading)");
|
||||
Perl_croak(aTHX_ "Usage: quest::summonallplayercorpses(int char_id, float dest_x, float dest_y, float dest_z, float dest_heading)");
|
||||
|
||||
bool RETVAL;
|
||||
uint32 char_id = (int) SvIV(ST(0));
|
||||
@ -2038,8 +2028,7 @@ XS(XS__playerfeature);
|
||||
XS(XS__playerfeature) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: quest::playerfeature(string feature [race|gender|texture|helm|haircolor|beardcolor|eyecolor1|eyecolor2|hair|face|beard|heritage|tatoo|details|size], int setting)");
|
||||
Perl_croak(aTHX_ "Usage: quest::playerfeature(string feature [race|gender|texture|helm|haircolor|beardcolor|eyecolor1|eyecolor2|hair|face|beard|heritage|tatoo|details|size], int setting)");
|
||||
|
||||
char *str_value = (char *) SvPV_nolen(ST(0));
|
||||
int int_value = (int) SvIV(ST(1));
|
||||
@ -2053,8 +2042,7 @@ XS(XS__npcfeature);
|
||||
XS(XS__npcfeature) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: quest::npcfeature(string feature [race|gender|texture|helm|haircolor|beardcolor|eyecolor1|eyecolor2|hair|face|beard|heritage|tatoo|details|size], int value)");
|
||||
Perl_croak(aTHX_ "Usage: quest::npcfeature(string feature [race|gender|texture|helm|haircolor|beardcolor|eyecolor1|eyecolor2|hair|face|beard|heritage|tatoo|details|size], int value)");
|
||||
|
||||
char *str_value = (char *) SvPV_nolen(ST(0));
|
||||
int int_value = (int) SvIV(ST(1));
|
||||
@ -2281,8 +2269,7 @@ XS(XS__updatetaskactivity) {
|
||||
}
|
||||
quest_manager.updatetaskactivity(task_id, activity_id, count, ignore_quest_update);
|
||||
} else {
|
||||
Perl_croak(aTHX_
|
||||
"Usage: quest::updatetaskactivity(int task_id, int activity_id, [int count], [bool ignore_quest_update = false])");
|
||||
Perl_croak(aTHX_ "Usage: quest::updatetaskactivity(int task_id, int activity_id, [int count], [bool ignore_quest_update = false])");
|
||||
}
|
||||
|
||||
XSRETURN_EMPTY;
|
||||
@ -2570,8 +2557,7 @@ XS(XS__popup) {
|
||||
int duration = 0;
|
||||
|
||||
if ((items < 2) || (items > 5))
|
||||
Perl_croak(aTHX_
|
||||
"Usage: quest::popup(string window_title, string message, int popup_id, int buttons, int duration)");
|
||||
Perl_croak(aTHX_ "Usage: quest::popup(string window_title, string message, int popup_id, int buttons, int duration)");
|
||||
|
||||
if (items >= 3)
|
||||
popup_id = (int) SvIV(ST(2));
|
||||
@ -2652,8 +2638,7 @@ XS(XS__CreateGroundObject);
|
||||
XS(XS__CreateGroundObject) {
|
||||
dXSARGS;
|
||||
if (items != 5 && items != 6)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: quest::creategroundobject(int item_id, float x, float y, float z, float heading, [uint32 decay_time-ms = 300000])");
|
||||
Perl_croak(aTHX_ "Usage: quest::creategroundobject(int item_id, float x, float y, float z, float heading, [uint32 decay_time-ms = 300000])");
|
||||
|
||||
int item_id = (int) SvIV(ST(0));
|
||||
float x = (float) SvNV(ST(1));
|
||||
@ -2676,8 +2661,7 @@ XS(XS__CreateGroundObjectFromModel);
|
||||
XS(XS__CreateGroundObjectFromModel) {
|
||||
dXSARGS;
|
||||
if (items < 5 || items > 7)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: quest::creategroundobjectfrommodel(string model_name, float x, float y, float z, float heading, [int object_type], [uint32 decay_time-ms = 300000])");
|
||||
Perl_croak(aTHX_ "Usage: quest::creategroundobjectfrommodel(string model_name, float x, float y, float z, float heading, [int object_type], [uint32 decay_time-ms = 300000])");
|
||||
|
||||
char *modelname = (char *) SvPV_nolen(ST(0));
|
||||
float x = (float) SvNV(ST(1));
|
||||
@ -2702,8 +2686,7 @@ XS(XS__CreateDoor);
|
||||
XS(XS__CreateDoor) {
|
||||
dXSARGS;
|
||||
if (items < 5 || items > 7)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: quest::createdoor(string model_name, float x, float y, float z, float heading, [int object_type = 58], [int size = 100])");
|
||||
Perl_croak(aTHX_ "Usage: quest::createdoor(string model_name, float x, float y, float z, float heading, [int object_type = 58], [int size = 100])");
|
||||
|
||||
char *modelname = (char *) SvPV_nolen(ST(0));
|
||||
float x = (float) SvNV(ST(1));
|
||||
@ -3032,8 +3015,7 @@ XS(XS__MovePCInstance);
|
||||
XS(XS__MovePCInstance) {
|
||||
dXSARGS;
|
||||
if (items != 5 && items != 6)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: quest::MovePCInstance(int zone_id, int instance_id, float x, float y, float z, [float heading])");
|
||||
Perl_croak(aTHX_ "Usage: quest::MovePCInstance(int zone_id, int instance_id, float x, float y, float z, [float heading])");
|
||||
|
||||
int zone_id = (int) SvIV(ST(0));
|
||||
int instanceid = (int) SvIV(ST(1));
|
||||
@ -3286,8 +3268,7 @@ XS(XS__wearchange);
|
||||
XS(XS__wearchange) {
|
||||
dXSARGS;
|
||||
if (items < 2)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: quest::wearchange(uint8 slot, uint16 texture_id, [uint32 hero_forge_model_id = 0], [uint32 elite_material_id = 0])");
|
||||
Perl_croak(aTHX_ "Usage: quest::wearchange(uint8 slot, uint16 texture_id, [uint32 hero_forge_model_id = 0], [uint32 elite_material_id = 0])");
|
||||
|
||||
uint8 slot = (int) SvUV(ST(0));
|
||||
uint16 texture_id = (int) SvUV(ST(1));
|
||||
@ -3535,8 +3516,7 @@ XS(XS__crosszonesetentityvariablebynpctypeid) {
|
||||
dXSARGS;
|
||||
|
||||
if (items != 3)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: quest::crosszonesetentityvariablebynpctypeid(int npc_type_id, string key, string value)");
|
||||
Perl_croak(aTHX_ "Usage: quest::crosszonesetentityvariablebynpctypeid(int npc_type_id, string key, string value)");
|
||||
|
||||
if (items == 3) {
|
||||
uint32 npc_type_id = (uint32) SvIV(ST(0));
|
||||
@ -3553,8 +3533,7 @@ XS(XS__crosszonesetentityvariablebyclientname) {
|
||||
dXSARGS;
|
||||
|
||||
if (items != 3)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: quest::crosszonesetentityvariablebyclientname(string client_name, string key, string value)");
|
||||
Perl_croak(aTHX_ "Usage: quest::crosszonesetentityvariablebyclientname(string client_name, string key, string value)");
|
||||
|
||||
if (items == 3) {
|
||||
const char *client_name = (const char *) SvPV_nolen(ST(0));
|
||||
@ -3586,8 +3565,7 @@ XS(XS__worldwidemarquee);
|
||||
XS(XS__worldwidemarquee) {
|
||||
dXSARGS;
|
||||
if (items != 6)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: quest::worldwidemarquee(uint32 color_id, uint32 priority, uint32 fade_in, uint32 fade_out, uint32 duration, string message)");
|
||||
Perl_croak(aTHX_ "Usage: quest::worldwidemarquee(uint32 color_id, uint32 priority, uint32 fade_in, uint32 fade_out, uint32 duration, string message)");
|
||||
|
||||
if (items == 6) {
|
||||
uint32 color_id = (uint32) SvIV(ST(0));
|
||||
|
||||
@ -2327,17 +2327,17 @@ luabind::scope lua_register_rules_const() {
|
||||
return luabind::class_<Rule>("Rule")
|
||||
.enum_("constants")
|
||||
[
|
||||
#define RULE_INT(cat, rule, default_value) \
|
||||
#define RULE_INT(cat, rule, default_value, notes) \
|
||||
luabind::value(#rule, RuleManager::Int__##rule),
|
||||
#include "../common/ruletypes.h"
|
||||
luabind::value("_IntRuleCount", RuleManager::_IntRuleCount),
|
||||
#undef RULE_INT
|
||||
#define RULE_REAL(cat, rule, default_value) \
|
||||
#define RULE_REAL(cat, rule, default_value, notes) \
|
||||
luabind::value(#rule, RuleManager::Real__##rule),
|
||||
#include "../common/ruletypes.h"
|
||||
luabind::value("_RealRuleCount", RuleManager::_RealRuleCount),
|
||||
#undef RULE_REAL
|
||||
#define RULE_BOOL(cat, rule, default_value) \
|
||||
#define RULE_BOOL(cat, rule, default_value, notes) \
|
||||
luabind::value(#rule, RuleManager::Bool__##rule),
|
||||
#include "../common/ruletypes.h"
|
||||
luabind::value("_BoolRuleCount", RuleManager::_BoolRuleCount)
|
||||
|
||||
@ -961,8 +961,7 @@ XS(XS_Client_SetEXP); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Client_SetEXP) {
|
||||
dXSARGS;
|
||||
if (items < 3 || items > 4)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Client::SetEXP(THIS, uint32 experience_points, uint32 aa_experience_points, [bool resexp=false])");
|
||||
Perl_croak(aTHX_ "Usage: Client::SetEXP(THIS, uint32 experience_points, uint32 aa_experience_points, [bool resexp=false])");
|
||||
{
|
||||
Client *THIS;
|
||||
uint32 set_exp = (uint32) SvUV(ST(1));
|
||||
@ -992,8 +991,7 @@ XS(XS_Client_SetBindPoint); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Client_SetBindPoint) {
|
||||
dXSARGS;
|
||||
if (items < 1 || items > 6)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Client::SetBindPoint(THIS, int to_zone = -1, int to_instance = 0, float new_x = 0.0f, float new_y = 0.0f, float new_z = 0.0f)");
|
||||
Perl_croak(aTHX_ "Usage: Client::SetBindPoint(THIS, int to_zone = -1, int to_instance = 0, float new_x = 0.0f, float new_y = 0.0f, float new_z = 0.0f)");
|
||||
{
|
||||
Client *THIS;
|
||||
int to_zone;
|
||||
@ -1256,8 +1254,7 @@ XS(XS_Client_MovePCInstance); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Client_MovePCInstance) {
|
||||
dXSARGS;
|
||||
if (items != 7)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Client::MovePCInstance(THIS, uint32 zone_id, uint32 instance_id, float x, float y, float z, float heading)");
|
||||
Perl_croak(aTHX_ "Usage: Client::MovePCInstance(THIS, uint32 zone_id, uint32 instance_id, float x, float y, float z, float heading)");
|
||||
{
|
||||
Client *THIS;
|
||||
uint32 zoneID = (uint32) SvUV(ST(1));
|
||||
@ -1327,8 +1324,7 @@ XS(XS_Client_GetFactionLevel); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Client_GetFactionLevel) {
|
||||
dXSARGS;
|
||||
if (items != 8)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Client::GetFactionLevel(THIS, uint32 character_id, uint32 npc_id, uint32 player_race_id, uint32 player_class_id, uint32 player_deity_id, uint32 player_faction_id, Mob*)");
|
||||
Perl_croak(aTHX_ "Usage: Client::GetFactionLevel(THIS, uint32 character_id, uint32 npc_id, uint32 player_race_id, uint32 player_class_id, uint32 player_deity_id, uint32 player_faction_id, Mob*)");
|
||||
{
|
||||
Client *THIS;
|
||||
FACTION_VALUE RETVAL;
|
||||
@ -1368,8 +1364,7 @@ XS(XS_Client_SetFactionLevel); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Client_SetFactionLevel) {
|
||||
dXSARGS;
|
||||
if (items != 6)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Client::SetFactionLevel(THIS, uint32 character_id, uint32 npc_id, uint8 character_class, uint8 character_race, uint8 character_deity)");
|
||||
Perl_croak(aTHX_ "Usage: Client::SetFactionLevel(THIS, uint32 character_id, uint32 npc_id, uint8 character_class, uint8 character_race, uint8 character_deity)");
|
||||
{
|
||||
Client *THIS;
|
||||
uint32 char_id = (uint32) SvUV(ST(1));
|
||||
@ -1395,8 +1390,7 @@ XS(XS_Client_SetFactionLevel2); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Client_SetFactionLevel2) {
|
||||
dXSARGS;
|
||||
if (items < 7 || items > 8)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Client::SetFactionLevel2(THIS, uint32 character_id, int32 faction_id, uint8 character_class, uint8 character_race, uint8 character_deity, int32 value, uint8 temp)");
|
||||
Perl_croak(aTHX_ "Usage: Client::SetFactionLevel2(THIS, uint32 character_id, int32 faction_id, uint8 character_class, uint8 character_race, uint8 character_deity, int32 value, uint8 temp)");
|
||||
{
|
||||
Client *THIS;
|
||||
uint32 char_id = (uint32) SvUV(ST(1));
|
||||
@ -1716,8 +1710,7 @@ XS(XS_Client_AddMoneyToPP); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Client_AddMoneyToPP) {
|
||||
dXSARGS;
|
||||
if (items != 6)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Client::AddMoneyToPP(THIS, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, bool update_client)");
|
||||
Perl_croak(aTHX_ "Usage: Client::AddMoneyToPP(THIS, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, bool update_client)");
|
||||
{
|
||||
Client *THIS;
|
||||
uint32 copper = (uint32) SvUV(ST(1));
|
||||
@ -3087,8 +3080,7 @@ XS(XS_Client_DeleteItemInInventory); /* prototype to pass -Wmissing-prototypes *
|
||||
XS(XS_Client_DeleteItemInInventory) {
|
||||
dXSARGS;
|
||||
if (items < 2 || items > 4)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Client::DeleteItemInInventory(THIS, int16 slot_id, [int8 quantity = 0], [bool client_update = false])");
|
||||
Perl_croak(aTHX_ "Usage: Client::DeleteItemInInventory(THIS, int16 slot_id, [int8 quantity = 0], [bool client_update = false])");
|
||||
{
|
||||
Client *THIS;
|
||||
int16 slot_id = (int16) SvIV(ST(1));
|
||||
@ -3124,8 +3116,7 @@ XS(XS_Client_SummonItem); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Client_SummonItem) {
|
||||
dXSARGS;
|
||||
if (items < 2 || items > 10)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Client::SummonItem(THIS, uint32 item_id, [int16 charges = -1], [bool attune = false], [uint32 aug1 = 0], [uint32 aug2 = 0], [uint32 aug3 = 0], [uint32 aug4 = 0], [uint32 aug5 = 0], [uint16 slot_id = cursor])");
|
||||
Perl_croak(aTHX_ "Usage: Client::SummonItem(THIS, uint32 item_id, [int16 charges = -1], [bool attune = false], [uint32 aug1 = 0], [uint32 aug2 = 0], [uint32 aug3 = 0], [uint32 aug4 = 0], [uint32 aug5 = 0], [uint16 slot_id = cursor])");
|
||||
{
|
||||
Client *THIS;
|
||||
uint32 item_id = (uint32) SvUV(ST(1));
|
||||
@ -4826,8 +4817,7 @@ XS(XS_Client_GrantAlternateAdvancementAbility); /* prototype to pass -Wmissing-p
|
||||
XS(XS_Client_GrantAlternateAdvancementAbility) {
|
||||
dXSARGS;
|
||||
if (items < 3 || items > 4)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Client::GrantAlternateAdvancementAbility(THIS, int aa_id, int points, [bool ignore_cost = false])");
|
||||
Perl_croak(aTHX_ "Usage: Client::GrantAlternateAdvancementAbility(THIS, int aa_id, int points, [bool ignore_cost = false])");
|
||||
{
|
||||
Client *THIS;
|
||||
bool RETVAL;
|
||||
@ -4984,8 +4974,7 @@ XS(XS_Client_UpdateTaskActivity); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Client_UpdateTaskActivity) {
|
||||
dXSARGS;
|
||||
if (items < 4)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Client::UpdateTaskActivity(THIS, int task_id, int activity_id, int count, [bool ignore_quest_update = false])");
|
||||
Perl_croak(aTHX_ "Usage: Client::UpdateTaskActivity(THIS, int task_id, int activity_id, int count, [bool ignore_quest_update = false])");
|
||||
{
|
||||
bool ignore_quest_update = false;
|
||||
|
||||
@ -5044,8 +5033,7 @@ XS(XS_Client_AssignTask); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Client_AssignTask) {
|
||||
dXSARGS;
|
||||
if (items != 3 && items != 4)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Client::AssignTask(THIS, int task_id, int npc_id, [bool enforce_level_requirement = false])");
|
||||
Perl_croak(aTHX_ "Usage: Client::AssignTask(THIS, int task_id, int npc_id, [bool enforce_level_requirement = false])");
|
||||
{
|
||||
Client *THIS;
|
||||
int TaskID = (int) SvIV(ST(1));
|
||||
@ -5956,8 +5944,7 @@ XS(XS_Client_SendMarqueeMessage); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Client_SendMarqueeMessage) {
|
||||
dXSARGS;
|
||||
if (items != 7)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Client::SendMarqueeMessage(THIS, uint32 type, uint32 priority, uint32 fade_in, uint32 fade_out, uint32 duration, string msg)");
|
||||
Perl_croak(aTHX_ "Usage: Client::SendMarqueeMessage(THIS, uint32 type, uint32 priority, uint32 fade_in, uint32 fade_out, uint32 duration, string msg)");
|
||||
{
|
||||
Client *THIS;
|
||||
uint32 type = (uint32) SvUV(ST(1));
|
||||
@ -6136,8 +6123,7 @@ XS(XS_Client_QuestReward); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Client_QuestReward) {
|
||||
dXSARGS;
|
||||
if (items < 1 || items > 9)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Client::QuestReward(THIS, int32 mob, int32 copper, int32 silver, int32 gold, int32 platinum, int32 item_id, int32 exp, [bool faction = false])");
|
||||
Perl_croak(aTHX_ "Usage: Client::QuestReward(THIS, int32 mob, int32 copper, int32 silver, int32 gold, int32 platinum, int32 item_id, int32 exp, [bool faction = false])");
|
||||
{
|
||||
Client *THIS;
|
||||
Mob *mob = nullptr;
|
||||
@ -6237,8 +6223,7 @@ XS(XS_Client_Popup2); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Client_Popup2) {
|
||||
dXSARGS;
|
||||
if (items < 3 || items > 10)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Client::SendFullPopup(THIS, string title, string text, uint32 popup_id, uint32 negative_id, uint32 buttons, uint32 duration, string button_name_0, string button_name_1, uint32 sound_controls)");
|
||||
Perl_croak(aTHX_ "Usage: Client::SendFullPopup(THIS, string title, string text, uint32 popup_id, uint32 negative_id, uint32 buttons, uint32 duration, string button_name_0, string button_name_1, uint32 sound_controls)");
|
||||
{
|
||||
Client *THIS;
|
||||
char *Title = (char *) SvPV_nolen(ST(1));
|
||||
|
||||
@ -1222,8 +1222,7 @@ XS(XS_EntityList_MessageStatus); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_EntityList_MessageStatus) {
|
||||
dXSARGS;
|
||||
if (items < 5)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: EntityList::MessageStatus(THIS, uint32 guild_id, uint32 emote_color_type, string message)");
|
||||
Perl_croak(aTHX_ "Usage: EntityList::MessageStatus(THIS, uint32 guild_id, uint32 emote_color_type, string message)");
|
||||
{
|
||||
EntityList *THIS;
|
||||
uint32 to_guilddbid = (uint32) SvUV(ST(1));
|
||||
@ -1248,8 +1247,7 @@ XS(XS_EntityList_MessageClose); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_EntityList_MessageClose) {
|
||||
dXSARGS;
|
||||
if (items < 6)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: EntityList::MessageClose(THIS, Mob* sender, bool skip_sender, float distance, uint32 emote_color_type, string message)");
|
||||
Perl_croak(aTHX_ "Usage: EntityList::MessageClose(THIS, Mob* sender, bool skip_sender, float distance, uint32 emote_color_type, string message)");
|
||||
{
|
||||
EntityList *THIS;
|
||||
Mob *sender;
|
||||
@ -1682,8 +1680,7 @@ XS(XS_EntityList_MessageGroup); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_EntityList_MessageGroup) {
|
||||
dXSARGS;
|
||||
if (items < 5)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: EntityList::MessageGroup(THIS, Mob* sender, bool skip_close, uint32 emote_color_type, string message)");
|
||||
Perl_croak(aTHX_ "Usage: EntityList::MessageGroup(THIS, Mob* sender, bool skip_close, uint32 emote_color_type, string message)");
|
||||
{
|
||||
EntityList *THIS;
|
||||
Mob *sender;
|
||||
@ -1716,8 +1713,7 @@ XS(XS_EntityList_GetRandomClient); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_EntityList_GetRandomClient) {
|
||||
dXSARGS;
|
||||
if ((items < 5) || (items > 6))
|
||||
Perl_croak(aTHX_
|
||||
"Usage: EntityList::GetRandomClient(THIS, float x, float y, float z, float distance, [Client* exclude_client = nullptr])");
|
||||
Perl_croak(aTHX_ "Usage: EntityList::GetRandomClient(THIS, float x, float y, float z, float distance, [Client* exclude_client = nullptr])");
|
||||
{
|
||||
EntityList *THIS;
|
||||
Client *RETVAL, *c = nullptr;
|
||||
|
||||
@ -486,8 +486,7 @@ XS(XS_Group_TeleportGroup); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Group_TeleportGroup) {
|
||||
dXSARGS;
|
||||
if (items != 7)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Group::TeleportGroup(THIS, Mob* sender, uint32 zone_id, float x, float y, float z, float heading)");
|
||||
Perl_croak(aTHX_ "Usage: Group::TeleportGroup(THIS, Mob* sender, uint32 zone_id, float x, float y, float z, float heading)");
|
||||
{
|
||||
Group *THIS;
|
||||
Mob *sender;
|
||||
|
||||
@ -794,8 +794,7 @@ XS(XS_Mob_Attack); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_Attack) {
|
||||
dXSARGS;
|
||||
if (items < 2 || items > 4)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Mob::Attack(THIS, Mob* other, [int hand = 13 [prim|sec]], [bool from_riposte = false])");
|
||||
Perl_croak(aTHX_ "Usage: Mob::Attack(THIS, Mob* other, [int hand = 13 [prim|sec]], [bool from_riposte = false])");
|
||||
{
|
||||
Mob *THIS;
|
||||
bool RETVAL;
|
||||
@ -842,8 +841,7 @@ XS(XS_Mob_Damage); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_Damage) {
|
||||
dXSARGS;
|
||||
if (items < 5 || items > 8)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Mob::Damage(THIS, Mob* from, int32 damage, uint16 spell_id, int attack_skill, [bool avoidable = true], [int8 buffslot = -1], [bool buff_tic = false])");
|
||||
Perl_croak(aTHX_ "Usage: Mob::Damage(THIS, Mob* from, int32 damage, uint16 spell_id, int attack_skill, [bool avoidable = true], [int8 buffslot = -1], [bool buff_tic = false])");
|
||||
{
|
||||
Mob *THIS;
|
||||
Mob *from;
|
||||
@ -1447,8 +1445,7 @@ XS(XS_Mob_MakeTempPet); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_MakeTempPet) {
|
||||
dXSARGS;
|
||||
if (items < 2 || items > 6)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Mob::MakeTempPet(THIS, uint16 spell_id, [string name = nullptr], [uint32 duration = 0], [Mob* target = nullptr], [bool sticktarg = 0])");
|
||||
Perl_croak(aTHX_ "Usage: Mob::MakeTempPet(THIS, uint16 spell_id, [string name = nullptr], [uint32 duration = 0], [Mob* target = nullptr], [bool sticktarg = 0])");
|
||||
{
|
||||
Mob *THIS;
|
||||
uint16 spell_id = (uint16) SvUV(ST(1));
|
||||
@ -1498,8 +1495,7 @@ XS(XS_Mob_TypesTempPet); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_TypesTempPet) {
|
||||
dXSARGS;
|
||||
if (items < 2 || items > 7)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Mob::TypesTempPet(THIS, uint32 type_id, [string name = nullptr], [uint32 duration = 0], [bool follow = 0], [Mob* target = nullptr], [bool stick_targ = 0])");
|
||||
Perl_croak(aTHX_ "Usage: Mob::TypesTempPet(THIS, uint32 type_id, [string name = nullptr], [uint32 duration = 0], [bool follow = 0], [Mob* target = nullptr], [bool stick_targ = 0])");
|
||||
{
|
||||
Mob *THIS;
|
||||
uint32 typesid = (uint32) SvUV(ST(1));
|
||||
@ -3680,8 +3676,7 @@ XS(XS_Mob_Message_StringID); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_Message_StringID) {
|
||||
dXSARGS;
|
||||
if (items < 3 || items > 4)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Mob::Message_StringID(THIS, uint32 emote_color_type, uint32 string_id, [uint32 distance = 0])");
|
||||
Perl_croak(aTHX_ "Usage: Mob::Message_StringID(THIS, uint32 emote_color_type, uint32 string_id, [uint32 distance = 0])");
|
||||
{
|
||||
Mob *THIS;
|
||||
uint32 type = (uint32) SvUV(ST(1));
|
||||
@ -3805,8 +3800,7 @@ XS(XS_Mob_CastSpell); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_CastSpell) {
|
||||
dXSARGS;
|
||||
if (items < 3 || items > 7)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Mob::CastSpell(THIS, uint16 spell_id, uint16 target_id, [int slot = 22], [int32 cast_time = -1], [int32 mana_cost = -1], [int16 resist_adjust = 0])");
|
||||
Perl_croak(aTHX_ "Usage: Mob::CastSpell(THIS, uint16 spell_id, uint16 target_id, [int slot = 22], [int32 cast_time = -1], [int32 mana_cost = -1], [int16 resist_adjust = 0])");
|
||||
{
|
||||
Mob *THIS;
|
||||
uint16 spell_id = (uint16) SvUV(ST(1));
|
||||
@ -3862,8 +3856,7 @@ XS(XS_Mob_SpellFinished); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_SpellFinished) {
|
||||
dXSARGS;
|
||||
if (items < 2 || items > 5)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Mob::SpellFinished(uint16 spell_id, [Mob* spell_target = this], [uint16 mana_cost = 0], [uint16 resist_diff = 0])");
|
||||
Perl_croak(aTHX_ "Usage: Mob::SpellFinished(uint16 spell_id, [Mob* spell_target = this], [uint16 mana_cost = 0], [uint16 resist_diff = 0])");
|
||||
{
|
||||
Mob *THIS;
|
||||
uint16 spell_id = (uint16) SvUV(ST(1));
|
||||
@ -4045,8 +4038,7 @@ XS(XS_Mob_CanBuffStack); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_CanBuffStack) {
|
||||
dXSARGS;
|
||||
if (items < 3 || items > 4)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Mob::CanBuffStack(THIS, uint16 spell_id, uint8 caster_level, [bool fail_if_overwritten = false])");
|
||||
Perl_croak(aTHX_ "Usage: Mob::CanBuffStack(THIS, uint16 spell_id, uint8 caster_level, [bool fail_if_overwritten = false])");
|
||||
{
|
||||
Mob *THIS;
|
||||
int RETVAL;
|
||||
@ -5044,8 +5036,7 @@ XS(XS_Mob_AddToHateList); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_AddToHateList) {
|
||||
dXSARGS;
|
||||
if (items < 2 || items > 7)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Mob::AddToHateList(THIS, Mob* other, [int32 hate = 0], [int32 damage = 0], [bool yell_for_help = true], [bool frenzy = false], [bool buff_tic = false])");
|
||||
Perl_croak(aTHX_ "Usage: Mob::AddToHateList(THIS, Mob* other, [int32 hate = 0], [int32 damage = 0], [bool yell_for_help = true], [bool frenzy = false], [bool buff_tic = false])");
|
||||
{
|
||||
Mob *THIS;
|
||||
Mob *other;
|
||||
@ -5609,8 +5600,7 @@ XS(XS_Mob_NavigateTo); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_NavigateTo) {
|
||||
dXSARGS;
|
||||
if (items < 4 || items > 5)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Mob::NavigateTo(THIS, float x, float y, float z)");
|
||||
Perl_croak(aTHX_ "Usage: Mob::NavigateTo(THIS, float x, float y, float z)");
|
||||
{
|
||||
Mob *THIS;
|
||||
float x = (float) SvNV(ST(1));
|
||||
@ -5735,8 +5725,7 @@ XS(XS_Mob_NPCSpecialAttacks); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_NPCSpecialAttacks) {
|
||||
dXSARGS;
|
||||
if (items < 3 || items > 5)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Mob::NPCSpecialAttacks(THIS, string abilities_string, int perm_tag, [bool reset = true], [bool remove = true])");
|
||||
Perl_croak(aTHX_ "Usage: Mob::NPCSpecialAttacks(THIS, string abilities_string, int perm_tag, [bool reset = true], [bool remove = true])");
|
||||
{
|
||||
Mob *THIS;
|
||||
char *parse = (char *) SvPV_nolen(ST(1));
|
||||
@ -6476,8 +6465,7 @@ XS(XS_Mob_DoSpecialAttackDamage); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_DoSpecialAttackDamage) {
|
||||
dXSARGS;
|
||||
if (items < 4 || items > 6)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Mob::DoSpecialAttackDamage(THIS, Mob* target, int skill, int32 max_damage, [int32 min_damage = 1], [int32 hate_override = -11])");
|
||||
Perl_croak(aTHX_ "Usage: Mob::DoSpecialAttackDamage(THIS, Mob* target, int skill, int32 max_damage, [int32 min_damage = 1], [int32 hate_override = -11])");
|
||||
{
|
||||
Mob *THIS;
|
||||
Mob *target;
|
||||
@ -6620,8 +6608,7 @@ XS(XS_Mob_ProjectileAnim); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_ProjectileAnim) {
|
||||
dXSARGS;
|
||||
if (items < 3 || items > 9)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Mob::ProjectileAnim(THIS, Mob* mob, int item_id, [bool is_arrow = false], [float speed = 0], [float angle = 0], [float tilt = 0], [float arc = 0])");
|
||||
Perl_croak(aTHX_ "Usage: Mob::ProjectileAnim(THIS, Mob* mob, int item_id, [bool is_arrow = false], [float speed = 0], [float angle = 0], [float tilt = 0], [float arc = 0])");
|
||||
|
||||
{
|
||||
Mob *THIS;
|
||||
@ -6703,8 +6690,7 @@ XS(XS_Mob_SendAppearanceEffect); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_SendAppearanceEffect) {
|
||||
dXSARGS;
|
||||
if (items < 2 || items > 7)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Mob::SendAppearanceEffect(THIS, int32 param_1, [int32 param_2 = 0], [int32 param_3 = 0], [int32 param_4 = 0], [int32 param_5 = 0], [Client* single_client_to_send_to = null])");
|
||||
Perl_croak(aTHX_ "Usage: Mob::SendAppearanceEffect(THIS, int32 param_1, [int32 param_2 = 0], [int32 param_3 = 0], [int32 param_4 = 0], [int32 param_5 = 0], [Client* single_client_to_send_to = null])");
|
||||
{
|
||||
Mob *THIS;
|
||||
int32 parm1 = (int32) SvIV(ST(1));
|
||||
@ -6833,8 +6819,7 @@ XS(XS_Mob_SendIllusion); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_SendIllusion) {
|
||||
dXSARGS;
|
||||
if (items < 2 || items > 14)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Mob::SendIllusion(THIS, uint16 race, [uint8 gender = 0xFF], [uint8 texture face = 0xFF], [uint8 hairstyle = 0xFF], [uint8 hair_color = 0xFF], [uint8 beard = 0xFF], [uint8 beard_color =FF], [uint32 drakkin_tattoo = 0xFFFFFFFF], [uint32 drakkin_details = 0xFFFFFFFF], [float size = -1])");
|
||||
Perl_croak(aTHX_ "Usage: Mob::SendIllusion(THIS, uint16 race, [uint8 gender = 0xFF], [uint8 texture face = 0xFF], [uint8 hairstyle = 0xFF], [uint8 hair_color = 0xFF], [uint8 beard = 0xFF], [uint8 beard_color =FF], [uint32 drakkin_tattoo = 0xFFFFFFFF], [uint32 drakkin_details = 0xFFFFFFFF], [float size = -1])");
|
||||
{
|
||||
Mob *THIS;
|
||||
uint16 race = (uint16) SvIV(ST(1));
|
||||
@ -6882,8 +6867,7 @@ XS(XS_Mob_CameraEffect); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_CameraEffect) {
|
||||
dXSARGS;
|
||||
if (items < 2 || items > 5)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Mob::CameraEffect(THIS, uint32 duration, [uint32 intensity = 0], [Client* single_client = nullptr], [bool is_world_wide = false])");
|
||||
Perl_croak(aTHX_ "Usage: Mob::CameraEffect(THIS, uint32 duration, [uint32 intensity = 0], [Client* single_client = nullptr], [bool is_world_wide = false])");
|
||||
{
|
||||
Mob *THIS;
|
||||
uint32 duration = (uint32) SvUV(ST(1));
|
||||
@ -6925,8 +6909,7 @@ XS(XS_Mob_SpellEffect); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_SpellEffect) {
|
||||
dXSARGS;
|
||||
if (items < 2 || items > 8)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Mob::SpellEffect(THIS, uint32 effect, [uint32 duration = 5000], [uint32 finish_delay = 0], [bool zone_wide = false], [uint32 unk20 = 3000], [bool perm_effect = false], [Client* single_client])");
|
||||
Perl_croak(aTHX_ "Usage: Mob::SpellEffect(THIS, uint32 effect, [uint32 duration = 5000], [uint32 finish_delay = 0], [bool zone_wide = false], [uint32 unk20 = 3000], [bool perm_effect = false], [Client* single_client])");
|
||||
{
|
||||
Mob *THIS;
|
||||
uint32 effect = (uint32) SvUV(ST(1));
|
||||
@ -7054,8 +7037,7 @@ XS(XS_Mob_SetGlobal);
|
||||
XS(XS_Mob_SetGlobal) {
|
||||
dXSARGS;
|
||||
if (items < 5 || items > 6)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: SetGlobal(THIS, string var_name, string new_value, int options, string duration, [Mob* other = nullptr])");
|
||||
Perl_croak(aTHX_ "Usage: SetGlobal(THIS, string var_name, string new_value, int options, string duration, [Mob* other = nullptr])");
|
||||
{
|
||||
Mob *THIS;
|
||||
char *varname = (char *) SvPV_nolen(ST(1));
|
||||
@ -7091,8 +7073,7 @@ XS(XS_Mob_TarGlobal);
|
||||
XS(XS_Mob_TarGlobal) {
|
||||
dXSARGS;
|
||||
if (items != 7)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: TarGlobal(THIS, string var_name, string value, string duration, int npc_id, int character_id, int zone_id)");
|
||||
Perl_croak(aTHX_ "Usage: TarGlobal(THIS, string var_name, string value, string duration, int npc_id, int character_id, int zone_id)");
|
||||
{
|
||||
Mob *THIS;
|
||||
char *varname = (char *) SvPV_nolen(ST(1));
|
||||
@ -7141,8 +7122,7 @@ XS(XS_Mob_SetSlotTint); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_SetSlotTint) {
|
||||
dXSARGS;
|
||||
if (items != 5)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Mob::SetSlotTint(THIS, uint8 material_slot, uint8 red_tint, uint8 green_tint, uint8 blue_tint)");
|
||||
Perl_croak(aTHX_ "Usage: Mob::SetSlotTint(THIS, uint8 material_slot, uint8 red_tint, uint8 green_tint, uint8 blue_tint)");
|
||||
{
|
||||
Mob *THIS;
|
||||
uint8 material_slot = (uint8) SvIV(ST(1));
|
||||
@ -7167,8 +7147,7 @@ XS(XS_Mob_WearChange); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_WearChange) {
|
||||
dXSARGS;
|
||||
if (items < 3 || items > 4)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Mob::WearChange(THIS, uint8 material_slot, uint16 texture, [uint32 color = 0, uint32 hero_forge_model = 0])");
|
||||
Perl_croak(aTHX_ "Usage: Mob::WearChange(THIS, uint8 material_slot, uint16 texture, [uint32 color = 0, uint32 hero_forge_model = 0])");
|
||||
{
|
||||
Mob *THIS;
|
||||
uint8 material_slot = (uint8) SvIV(ST(1));
|
||||
@ -7598,8 +7577,7 @@ XS(XS_Mob_DoMeleeSkillAttackDmg); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_DoMeleeSkillAttackDmg) {
|
||||
dXSARGS;
|
||||
if (items != 7)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Mob::DoMeleeSkillAttackDmg(THIS, Mob* target, uint16 weapon_damage, int skill, int16 chance_mod, int16 focus, uint8 can_riposte)");
|
||||
Perl_croak(aTHX_ "Usage: Mob::DoMeleeSkillAttackDmg(THIS, Mob* target, uint16 weapon_damage, int skill, int16 chance_mod, int16 focus, uint8 can_riposte)");
|
||||
{
|
||||
Mob *THIS;
|
||||
Mob *target;
|
||||
@ -7634,8 +7612,7 @@ XS(XS_Mob_DoArcheryAttackDmg); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_DoArcheryAttackDmg) {
|
||||
dXSARGS;
|
||||
if (items != 7)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Mob::DoArcheryAttackDmg(THIS, Mob* target, [range_weapon_item_instance = nullptr], [ammo_item_instance = nullptr], uint16 weapon_damage, int16 chance_mod, int16 focus)");
|
||||
Perl_croak(aTHX_ "Usage: Mob::DoArcheryAttackDmg(THIS, Mob* target, [range_weapon_item_instance = nullptr], [ammo_item_instance = nullptr], uint16 weapon_damage, int16 chance_mod, int16 focus)");
|
||||
{
|
||||
Mob *THIS;
|
||||
Mob *target;
|
||||
@ -7670,8 +7647,7 @@ XS(XS_Mob_DoThrowingAttackDmg); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_DoThrowingAttackDmg) {
|
||||
dXSARGS;
|
||||
if (items != 7)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Mob::DoThrowingAttackDmg(THIS, Mob* target, [range_weapon_item_instance = nullptr], [ammo_item_instance = nullptr], uint16 weapon_damage, int16 chance_mod, int16 focus)");
|
||||
Perl_croak(aTHX_ "Usage: Mob::DoThrowingAttackDmg(THIS, Mob* target, [range_weapon_item_instance = nullptr], [ammo_item_instance = nullptr], uint16 weapon_damage, int16 chance_mod, int16 focus)");
|
||||
{
|
||||
Mob *THIS;
|
||||
Mob *target;
|
||||
|
||||
@ -97,8 +97,7 @@ XS(XS_NPC_AddItem); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_NPC_AddItem) {
|
||||
dXSARGS;
|
||||
if (items < 2 || items > 10)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: NPC::AddItem(THIS, uint32 item_id, [uint16 charges = 0], [bool equip_item = true], [uint32 aug1 = 0], [uint32 aug2 = 0], [uint32 aug3 = 0], [uint32 aug4 = 0], [uint32 aug5 = 0], [uint32 aug6 = 0])");
|
||||
Perl_croak(aTHX_ "Usage: NPC::AddItem(THIS, uint32 item_id, [uint16 charges = 0], [bool equip_item = true], [uint32 aug1 = 0], [uint32 aug2 = 0], [uint32 aug3 = 0], [uint32 aug4 = 0], [uint32 aug5 = 0], [uint32 aug6 = 0])");
|
||||
{
|
||||
NPC *THIS;
|
||||
uint32 itemid = (uint32) SvUV(ST(1));
|
||||
@ -1283,8 +1282,7 @@ XS(XS_NPC_MoveTo); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_NPC_MoveTo) {
|
||||
dXSARGS;
|
||||
if (items != 4 && items != 5 && items != 6)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: NPC::MoveTo(THIS, float x, float y, float z, [float heading], [bool save_guard_location = false])");
|
||||
Perl_croak(aTHX_ "Usage: NPC::MoveTo(THIS, float x, float y, float z, [float heading], [bool save_guard_location = false])");
|
||||
{
|
||||
NPC *THIS;
|
||||
float mtx = (float) SvNV(ST(1));
|
||||
@ -1391,8 +1389,7 @@ XS(XS_NPC_AI_SetRoambox); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_NPC_AI_SetRoambox) {
|
||||
dXSARGS;
|
||||
if (items < 6 || items > 8)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: NPC::AI_SetRoambox(THIS, float distance, float max_x, float min_x, float max_y, float min_y, [uint32 max_delay = 2500], [uint32 min_delay = 2500])");
|
||||
Perl_croak(aTHX_ "Usage: NPC::AI_SetRoambox(THIS, float distance, float max_x, float min_x, float max_y, float min_y, [uint32 max_delay = 2500], [uint32 min_delay = 2500])");
|
||||
{
|
||||
NPC *THIS;
|
||||
float iDist = (float) SvNV(ST(1));
|
||||
@ -1852,8 +1849,7 @@ XS(XS_NPC_AddSpellToNPCList); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_NPC_AddSpellToNPCList) {
|
||||
dXSARGS;
|
||||
if (items != 7)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: NPC::AddAISpell(THIS, int priority, int spell_id, int type, int mana_cost, int recast_delay, int resist_adjust)");
|
||||
Perl_croak(aTHX_ "Usage: NPC::AddAISpell(THIS, int priority, int spell_id, int type, int mana_cost, int recast_delay, int resist_adjust)");
|
||||
{
|
||||
NPC *THIS;
|
||||
int priority = (int) SvIV(ST(1));
|
||||
|
||||
@ -420,8 +420,7 @@ XS(XS_Raid_TeleportGroup); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Raid_TeleportGroup) {
|
||||
dXSARGS;
|
||||
if (items != 8)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Raid::TeleportGroup(THIS, Mob* sender, uint32 zone_id, float x, float y, float z, float heading, uint32 group_id)");
|
||||
Perl_croak(aTHX_ "Usage: Raid::TeleportGroup(THIS, Mob* sender, uint32 zone_id, float x, float y, float z, float heading, uint32 group_id)");
|
||||
{
|
||||
Raid *THIS;
|
||||
Mob *sender;
|
||||
@ -457,8 +456,7 @@ XS(XS_Raid_TeleportRaid); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Raid_TeleportRaid) {
|
||||
dXSARGS;
|
||||
if (items != 7)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Raid::TeleportRaid(THIS, Mob* sender, uint32 zone_id, float x, float y, float z, float heading)");
|
||||
Perl_croak(aTHX_ "Usage: Raid::TeleportRaid(THIS, Mob* sender, uint32 zone_id, float x, float y, float z, float heading)");
|
||||
{
|
||||
Raid *THIS;
|
||||
Mob *sender;
|
||||
|
||||
126
zone/zonedb.cpp
126
zone/zonedb.cpp
@ -15,6 +15,7 @@
|
||||
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <fmt/format.h>
|
||||
|
||||
extern Zone* zone;
|
||||
|
||||
@ -4073,60 +4074,113 @@ bool ZoneDatabase::SetCharacterFactionLevel(uint32 char_id, int32 faction_id, in
|
||||
|
||||
bool ZoneDatabase::LoadFactionData()
|
||||
{
|
||||
std::string query = "SELECT MAX(id) FROM faction_list";
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
std::string query("SELECT MAX(`id`) FROM `faction_list`");
|
||||
|
||||
auto faction_max_results = QueryDatabase(query);
|
||||
if (!faction_max_results.Success() || faction_max_results.RowCount() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
return false;
|
||||
auto fmr_row = faction_max_results.begin();
|
||||
|
||||
auto row = results.begin();
|
||||
max_faction = atoul(fmr_row[0]);
|
||||
faction_array = new Faction *[max_faction + 1];
|
||||
|
||||
max_faction = row[0] ? atoi(row[0]) : 0;
|
||||
faction_array = new Faction*[max_faction+1];
|
||||
for(unsigned int index=0; index<max_faction; index++)
|
||||
faction_array[index] = nullptr;
|
||||
memset(faction_array, 0, (sizeof(Faction*) * (max_faction + 1)));
|
||||
|
||||
std::vector<size_t> faction_ids;
|
||||
|
||||
// load factions
|
||||
query = "SELECT `id`, `name`, `base` FROM `faction_list`";
|
||||
|
||||
query = "SELECT id, name, base FROM faction_list";
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
auto faction_results = QueryDatabase(query);
|
||||
if (!faction_results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (row = results.begin(); row != results.end(); ++row) {
|
||||
uint32 index = atoi(row[0]);
|
||||
for (auto fr_row : faction_results) {
|
||||
|
||||
uint32 index = atoul(fr_row[0]);
|
||||
if (index > max_faction) {
|
||||
Log(Logs::General, Logs::Error, "Faction '%u' is out-of-bounds for faction array size!", index);
|
||||
continue;
|
||||
}
|
||||
|
||||
// this should never hit since `id` is keyed..but, it alleviates any risk of lost pointers
|
||||
if (faction_array[index] != nullptr) {
|
||||
Log(Logs::General, Logs::Error, "Faction '%u' has already been assigned! (Duplicate Entry)", index);
|
||||
continue;
|
||||
}
|
||||
|
||||
faction_array[index] = new Faction;
|
||||
strn0cpy(faction_array[index]->name, row[1], 50);
|
||||
faction_array[index]->base = atoi(row[2]);
|
||||
strn0cpy(faction_array[index]->name, fr_row[1], 50);
|
||||
faction_array[index]->base = atoi(fr_row[2]);
|
||||
faction_array[index]->min = MIN_PERSONAL_FACTION;
|
||||
faction_array[index]->max = MAX_PERSONAL_FACTION;
|
||||
|
||||
faction_ids.push_back(index);
|
||||
}
|
||||
|
||||
// Load in the mimimum and maximum faction that can be earned for this faction
|
||||
query = StringFormat("SELECT `min` , `max` FROM `faction_base_data` WHERE client_faction_id = %u", index);
|
||||
auto baseResults = QueryDatabase(query);
|
||||
if (!baseResults.Success() || baseResults.RowCount() == 0) {
|
||||
Log(Logs::General, Logs::General, "Faction %d has no base data", (int)index);
|
||||
}
|
||||
else {
|
||||
for (auto modRow = baseResults.begin(); modRow != baseResults.end(); ++modRow) {
|
||||
faction_array[index]->min = atoi(modRow[0]);
|
||||
faction_array[index]->max = atoi(modRow[1]);
|
||||
LogDebug("Min([{}]), Max([{}]) for faction ([{}])",faction_array[index]->min, faction_array[index]->max, index);
|
||||
LogInfo("%u Faction%s loaded...", faction_ids.size(), (faction_ids.size() == 1 ? "" : "s"));
|
||||
|
||||
const std::string faction_id_criteria(implode(",", std::pair<char, char>('\'', '\''), faction_ids));
|
||||
|
||||
// load faction mins/maxes
|
||||
query = fmt::format("SELECT `client_faction_id`, `min`, `max` FROM `faction_base_data` WHERE `client_faction_id` IN ({})", faction_id_criteria);
|
||||
|
||||
auto base_results = QueryDatabase(query);
|
||||
if (base_results.Success()) {
|
||||
|
||||
for (auto br_row : base_results) {
|
||||
|
||||
uint32 index = atoul(br_row[0]);
|
||||
if (index > max_faction) {
|
||||
LogError("Faction '%u' is out-of-bounds for faction array size in Base adjustment!", index);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (faction_array[index] == nullptr) {
|
||||
LogError("Faction '%u' does not exist for Base adjustment!", index);
|
||||
continue;
|
||||
}
|
||||
|
||||
faction_array[index]->min = atoi(br_row[1]);
|
||||
faction_array[index]->max = atoi(br_row[2]);
|
||||
}
|
||||
|
||||
// Load in modifiers to the faction based on characters race, class and diety.
|
||||
query = StringFormat("SELECT `mod`, `mod_name` FROM `faction_list_mod` WHERE faction_id = %u", index);
|
||||
auto modResults = QueryDatabase(query);
|
||||
if (!modResults.Success())
|
||||
continue;
|
||||
LogInfo("%u Faction Base%s loaded...", base_results.RowCount(), (base_results.RowCount() == 1 ? "" : "s"));
|
||||
}
|
||||
else {
|
||||
LogInfo("Unable to load Faction Base data...");
|
||||
}
|
||||
|
||||
// load race, class and diety modifiers
|
||||
query = fmt::format("SELECT `faction_id`, `mod`, `mod_name` FROM `faction_list_mod` WHERE `faction_id` IN ({})", faction_id_criteria);
|
||||
|
||||
for (auto modRow = modResults.begin(); modRow != modResults.end(); ++modRow) {
|
||||
faction_array[index]->mods[modRow[1]] = atoi(modRow[0]);
|
||||
auto modifier_results = QueryDatabase(query);
|
||||
if (modifier_results.Success()) {
|
||||
|
||||
for (auto mr_row : modifier_results) {
|
||||
|
||||
uint32 index = atoul(mr_row[0]);
|
||||
if (index > max_faction) {
|
||||
Log(Logs::General, Logs::Error, "Faction '%u' is out-of-bounds for faction array size in Modifier adjustment!", index);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (faction_array[index] == nullptr) {
|
||||
Log(Logs::General, Logs::Error, "Faction '%u' does not exist for Modifier adjustment!", index);
|
||||
continue;
|
||||
}
|
||||
|
||||
faction_array[index]->mods[mr_row[2]] = atoi(mr_row[1]);
|
||||
}
|
||||
}
|
||||
|
||||
Log(Logs::General, Logs::Status, "%u Faction Modifier%s loaded...", modifier_results.RowCount(), (modifier_results.RowCount() == 1 ? "" : "s"));
|
||||
}
|
||||
else {
|
||||
Log(Logs::General, Logs::Status, "Unable to load Faction Modifier data...");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user