Merge remote-tracking branch 'origin/master' into build

This commit is contained in:
KimLS 2019-08-29 21:57:54 -07:00
commit 276804604c
13 changed files with 214 additions and 68 deletions

View File

@ -413,7 +413,7 @@ namespace EQEmu
int32 SkillModMax; // Max skill point modification
uint32 SkillModType; // Type of skill for SkillModValue to apply to
uint32 BaneDmgRace; // Bane Damage Race
int8 BaneDmgAmt; // Bane Damage Body Amount
int32 BaneDmgAmt; // Bane Damage Body Amount
uint32 BaneDmgBody; // Bane Damage Body
bool Magic; // True=Magic Item, False=not
int32 CastTime_;

View File

@ -2303,7 +2303,10 @@ namespace Titanium
ob << '|' << itoa(item->SkillModType);
ob << '|' << itoa(item->BaneDmgRace);
ob << '|' << itoa(item->BaneDmgAmt);
if (item->BaneDmgAmt > 255)
ob << '|' << "255";
else
ob << '|' << itoa(item->BaneDmgAmt);
ob << '|' << itoa(item->BaneDmgBody);
ob << '|' << itoa(item->Magic);

View File

@ -998,7 +998,7 @@ void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_
item.SkillModMax = (int32)atoul(row[ItemField::skillmodmax]);
item.SkillModType = (uint32)atoul(row[ItemField::skillmodtype]);
item.BaneDmgRace = (uint32)atoul(row[ItemField::banedmgrace]);
item.BaneDmgAmt = (int8)atoi(row[ItemField::banedmgamt]);
item.BaneDmgAmt = (int32)atoul(row[ItemField::banedmgamt]);
item.BaneDmgBody = (uint32)atoul(row[ItemField::banedmgbody]);
item.Magic = (atoi(row[ItemField::magic]) == 0) ? false : true;
item.CastTime_ = (int32)atoul(row[ItemField::casttime_]);

View File

@ -34,7 +34,7 @@
#define CURRENT_BINARY_DATABASE_VERSION 9141
#ifdef BOTS
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9024
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9025
#else
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 0 // must be 0
#endif

View File

@ -23,6 +23,7 @@
9022|2019_02_07_bots_stance_type_update.sql|SELECT * FROM `bot_spell_casting_chances` WHERE `spell_type_index` = '255' AND `class_id` = '255' AND `stance_index` = '0'|not_empty|
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|
# Upgrade conditions:
# This won't be needed after this system is implemented, but it is used database that are not

View File

@ -0,0 +1,2 @@
ALTER TABLE `bot_owner_options` ADD COLUMN `spawn_message_enabled` SMALLINT(3) UNSIGNED NULL DEFAULT '1' AFTER `stats_update`;
ALTER TABLE `bot_owner_options` ADD COLUMN `spawn_message_type` SMALLINT(3) UNSIGNED NULL DEFAULT '1' AFTER `spawn_message_enabled`;

View File

@ -7465,9 +7465,14 @@ void Bot::DoEnduranceUpkeep() {
void Bot::Camp(bool databaseSave) {
Sit();
if(IsGrouped())
//auto group = GetGroup();
if(GetGroup())
RemoveBotFromGroup(this, GetGroup());
// RemoveBotFromGroup() code is too complicated for this to work as-is (still needs to be addressed to prevent memory leaks)
//if (group->GroupCount() < 2)
// group->DisbandGroup();
LeaveHealRotationMemberPool();
if(databaseSave)

View File

@ -95,6 +95,7 @@ namespace
enum { EffectIDFirst = 1, EffectIDLast = 12 };
#define VALIDATECLASSID(x) ((x >= WARRIOR && x <= BERSERKER) ? (x) : (0))
#define CLASSIDTOINDEX(x) ((x >= WARRIOR && x <= BERSERKER) ? (x - 1) : (0))
#define EFFECTIDTOINDEX(x) ((x >= EffectIDFirst && x <= EffectIDLast) ? (x - 1) : (0))
#define AILMENTIDTOINDEX(x) ((x >= BCEnum::AT_Blindness && x <= BCEnum::AT_Corruption) ? (x - 1) : (0))
@ -3443,16 +3444,17 @@ 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]);
return;
}
std::string owner_option = sep->arg[1];
std::string flag = sep->arg[2];
std::string argument = sep->arg[2];
if (!owner_option.compare("deathmarquee")) {
if (!flag.compare("enable"))
if (!argument.compare("enable"))
c->SetBotOptionDeathMarquee(true);
else if (!flag.compare("disable"))
else if (!argument.compare("disable"))
c->SetBotOptionDeathMarquee(false);
else
c->SetBotOptionDeathMarquee(!c->GetBotOptionDeathMarquee());
@ -3461,9 +3463,9 @@ void bot_command_owner_option(Client *c, const Seperator *sep)
c->Message(m_action, "Bot 'death marquee' is now %s.", (c->GetBotOptionDeathMarquee() == true ? "enabled" : "disabled"));
}
else if (!owner_option.compare("statsupdate")) {
if (!flag.compare("enable"))
if (!argument.compare("enable"))
c->SetBotOptionStatsUpdate(true);
else if (!flag.compare("disable"))
else if (!argument.compare("disable"))
c->SetBotOptionStatsUpdate(false);
else
c->SetBotOptionStatsUpdate(!c->GetBotOptionStatsUpdate());
@ -3471,6 +3473,35 @@ void bot_command_owner_option(Client *c, const Seperator *sep)
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();
}
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 {
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()
);
c->Message(m_action, "Bot 'spawn message' is now %s.", argument.c_str());
}
else {
c->Message(m_fail, "Owner option '%s' is not recognized.", owner_option.c_str());
}
@ -4284,17 +4315,17 @@ void bot_subcommand_bot_clone(Client *c, const Seperator *sep)
void bot_subcommand_bot_create(Client *c, const Seperator *sep)
{
const std::string class_substrs[17] = { "",
"%u(WAR)", "%u(CLR)", "%u(PAL)", "%u(RNG)",
"%u(SHD)", "%u(DRU)", "%u(MNK)", "%u(BRD)",
"%u(ROG)", "%u(SHM)", "%u(NEC)", "%u(WIZ)",
"%u(MAG)", "%u(ENC)", "%u(BST)", "%u(BER)"
"%u (WAR)", "%u (CLR)", "%u (PAL)", "%u (RNG)",
"%u (SHD)", "%u (DRU)", "%u (MNK)", "%u (BRD)",
"%u (ROG)", "%u (SHM)", "%u (NEC)", "%u (WIZ)",
"%u (MAG)", "%u (ENC)", "%u (BST)", "%u (BER)"
};
const std::string race_substrs[17] = { "",
"%u(HUM)", "%u(BAR)", "%u(ERU)", "%u(ELF)",
"%u(HIE)", "%u(DEF)", "%u(HEF)", "%u(DWF)",
"%u(TRL)", "%u(OGR)", "%u(HFL)", "%u(GNM)",
"%u(IKS)", "%u(VAH)", "%u(FRG)", "%u(DRK)"
"%u (HUM)", "%u (BAR)", "%u (ERU)", "%u (ELF)",
"%u (HIE)", "%u (DEF)", "%u (HEF)", "%u (DWF)",
"%u (TRL)", "%u (OGR)", "%u (HFL)", "%u (GNM)",
"%u (IKS)", "%u (VAH)", "%u (FRG)", "%u (DRK)"
};
const uint16 race_values[17] = { 0,
@ -4305,54 +4336,70 @@ void bot_subcommand_bot_create(Client *c, const Seperator *sep)
};
const std::string gender_substrs[2] = {
"%u(M)", "%u(F)",
"%u (M)", "%u (F)",
};
std::string msg_class = "class:";
std::string msg_race = "race:";
std::string msg_gender = "gender:";
std::string msg_separator;
msg_separator = " ";
for (int i = 0; i <= 15; ++i) {
if (((1 << i) & RuleI(Bots, AllowedClasses)) == 0)
continue;
msg_class.append(const_cast<const std::string&>(msg_separator));
msg_class.append(StringFormat(class_substrs[i + 1].c_str(), (i + 1)));
msg_separator = ", ";
}
msg_separator = " ";
for (int i = 0; i <= 15; ++i) {
if (((1 << i) & RuleI(Bots, AllowedRaces)) == 0)
continue;
msg_race.append(const_cast<const std::string&>(msg_separator));
msg_race.append(StringFormat(race_substrs[i + 1].c_str(), race_values[i + 1]));
msg_separator = ", ";
}
msg_separator = " ";
for (int i = 0; i <= 1; ++i) {
if (((1 << i) & RuleI(Bots, AllowedGenders)) == 0)
continue;
msg_gender.append(const_cast<const std::string&>(msg_separator));
msg_gender.append(StringFormat(gender_substrs[i].c_str(), i));
msg_separator = ", ";
}
if (helper_command_alias_fail(c, "bot_subcommand_bot_create", sep->arg[0], "botcreate"))
return;
if (helper_is_help_or_usage(sep->arg[1])) {
c->Message(m_usage, "usage: %s [bot_name] [bot_class] [bot_race] [bot_gender]", sep->arg[0]);
c->Message(m_note, msg_class.c_str());
c->Message(m_note, msg_race.c_str());
c->Message(m_note, msg_gender.c_str());
std::string window_title = "Bot Create Options";
std::string window_text;
std::string message_separator;
int object_count = 0;
const int object_max = 5;
window_text.append("<c \"#FFFFFF\">Classes:<c \"#FFFF\">");
message_separator = " ";
object_count = 1;
for (int i = 0; i <= 15; ++i) {
if (((1 << i) & RuleI(Bots, AllowedClasses)) == 0)
continue;
window_text.append(const_cast<const std::string&>(message_separator));
if (object_count >= object_max) {
window_text.append("<br>");
object_count = 0;
}
window_text.append(StringFormat(class_substrs[i + 1].c_str(), (i + 1)));
++object_count;
message_separator = ", ";
}
window_text.append("<br><br>");
window_text.append("<c \"#FFFFFF\">Races:<c \"#FFFF\">");
message_separator = " ";
object_count = 1;
for (int i = 0; i <= 15; ++i) {
if (((1 << i) & RuleI(Bots, AllowedRaces)) == 0)
continue;
window_text.append(const_cast<const std::string&>(message_separator));
if (object_count >= object_max) {
window_text.append("<br>");
object_count = 0;
}
window_text.append(StringFormat(race_substrs[i + 1].c_str(), race_values[i + 1]));
++object_count;
message_separator = ", ";
}
window_text.append("<br><br>");
window_text.append("<c \"#FFFFFF\">Genders:<c \"#FFFF\">");
message_separator = " ";
for (int i = 0; i <= 1; ++i) {
if (((1 << i) & RuleI(Bots, AllowedGenders)) == 0)
continue;
window_text.append(const_cast<const std::string&>(message_separator));
window_text.append(StringFormat(gender_substrs[i].c_str(), i));
message_separator = ", ";
}
c->SendPopupToClient(window_title.c_str(), window_text.c_str());
return;
}
@ -4363,19 +4410,19 @@ void bot_subcommand_bot_create(Client *c, const Seperator *sep)
std::string bot_name = sep->arg[1];
if (sep->arg[2][0] == '\0' || !sep->IsNumber(2)) {
c->Message(m_fail, msg_class.c_str());
c->Message(m_fail, "Invalid Class!");
return;
}
uint8 bot_class = atoi(sep->arg[2]);
if (sep->arg[3][0] == '\0' || !sep->IsNumber(3)) {
c->Message(m_fail, msg_race.c_str());
c->Message(m_fail, "Invalid Race!");
return;
}
uint16 bot_race = atoi(sep->arg[3]);
if (sep->arg[4][0] == '\0') {
c->Message(m_fail, msg_gender.c_str());
c->Message(m_fail, "Invalid Gender!");
return;
}
uint8 bot_gender = atoi(sep->arg[4]);
@ -5153,8 +5200,9 @@ void bot_subcommand_bot_spawn(Client *c, const Seperator *sep)
return;
}
static const char* bot_spawn_message[16] = {
"A solid weapon is my ally!", // WARRIOR / 'generic'
static const char* bot_spawn_message[17] = {
"I am ready to fight!", // DEFAULT
"A solid weapon is my ally!", // WARRIOR
"The pious shall never die!", // CLERIC
"I am the symbol of Light!", // PALADIN
"There are enemies near!", // RANGER
@ -5172,7 +5220,14 @@ void bot_subcommand_bot_spawn(Client *c, const Seperator *sep)
"My bloodthirst shall not be quenched!" // BERSERKER
};
Bot::BotGroupSay(my_bot, "%s", bot_spawn_message[CLASSIDTOINDEX(my_bot->GetClass())]);
uint8 message_index = 0;
if (c->GetBotOptionSpawnMessageClassSpecific())
message_index = VALIDATECLASSID(my_bot->GetClass());
if (c->GetBotOptionSpawnMessageSay())
Bot::BotGroupSay(my_bot, "%s", bot_spawn_message[message_index]);
else if (c->GetBotOptionSpawnMessageTell())
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)

View File

@ -2157,7 +2157,7 @@ bool BotDatabase::LoadOwnerOptions(Client *owner)
return false;
query = StringFormat(
"SELECT `death_marquee`, `stats_update` FROM `bot_owner_options`"
"SELECT `death_marquee`, `stats_update`, `spawn_message_enabled`, `spawn_message_type` FROM `bot_owner_options`"
" WHERE `owner_id` = '%u'",
owner->CharacterID()
);
@ -2174,6 +2174,18 @@ bool BotDatabase::LoadOwnerOptions(Client *owner)
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;
default:
owner->SetBotOptionSpawnMessageSilent();
break;
}
owner->SetBotOptionSpawnMessageClassSpecific((atoi(row[3]) != 0));
return true;
}
@ -2216,6 +2228,38 @@ bool BotDatabase::SaveOwnerOptionStatsUpdate(const uint32 owner_id, const bool f
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;
}
/* Bot bot-group functions */
bool BotDatabase::QueryBotGroupExistence(const std::string& group_name, bool& extant_flag)

View File

@ -141,6 +141,7 @@ public:
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);
/* Bot bot-group functions */
bool QueryBotGroupExistence(const std::string& botgroup_name, bool& extant_flag);

View File

@ -1629,21 +1629,34 @@ private:
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, // 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; }
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; }
private:
#endif

View File

@ -3952,6 +3952,9 @@ 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();
#endif
if (IsLFP())
worldserver.StopLFP(CharacterID());

View File

@ -1435,6 +1435,25 @@ void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= fal
}
}
#ifdef BOTS
if (GetOwner() && GetOwner()->IsBot() && GetOwner()->CastToBot()->GetBotOwner() && GetOwner()->CastToBot()->GetBotOwner()->IsClient()) {
auto bot_owner = GetOwner()->CastToBot()->GetBotOwner()->CastToClient();
if (bot_owner) {
bot_owner->QueuePacket(&hp_packet, false);
group = entity_list.GetGroupByClient(bot_owner);
if (group) {
group->SendHPPacketsFrom(this);
}
Raid *raid = entity_list.GetRaidByClient(bot_owner);
if (raid) {
raid->SendHPManaEndPacketsFrom(this);
}
}
}
#endif
if (GetPet() && GetPet()->IsClient()) {
GetPet()->CastToClient()->QueuePacket(&hp_packet, false);
}