mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 21:01:29 +00:00
Activation of the new 'Bots' command system
This commit is contained in:
parent
747895cbe5
commit
b327da7092
@ -3,6 +3,11 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||
== 03/24/2016 ==
|
||||
Kayen: Fix for AE taunt to use correct range and hate modifier.
|
||||
Fix for spell effect version of taunt to use correct range.
|
||||
Uleat: Activation of new 'Bots' command system
|
||||
- You will need to re-run cmake to capture the file additions and then re-compile your server binaries
|
||||
- You will also need to manually run eqemu_update.pl and select the bots update option - you should have 2 pending updates: 9001 & 9002
|
||||
- The new command system is accessed with the '^' character - start with '^help' and see where that takes you
|
||||
- More information can be found on the eqemu forums
|
||||
|
||||
== 03/05/2016 ==
|
||||
mackal: Implement extra bind points (secondary recall)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemu.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -18,275 +18,576 @@
|
||||
#include "../common/global_define.h"
|
||||
#include "../common/classes.h"
|
||||
|
||||
const char* GetEQClassName(uint8 class_, uint8 level) {
|
||||
switch(class_) {
|
||||
case WARRIOR:
|
||||
if (level >= 70)
|
||||
return "Vanquisher";
|
||||
else if (level >= 65)
|
||||
return "Overlord"; //Baron-Sprite: LEAVE MY CLASSES ALONE.
|
||||
else if (level >= 60)
|
||||
return "Warlord";
|
||||
else if (level >= 55)
|
||||
return "Myrmidon";
|
||||
else if (level >= 51)
|
||||
return "Champion";
|
||||
else
|
||||
return "Warrior";
|
||||
case CLERIC:
|
||||
if (level >= 70)
|
||||
return "Prelate";
|
||||
else if (level >= 65)
|
||||
return "Archon";
|
||||
else if (level >= 60)
|
||||
return "High Priest";
|
||||
else if (level >= 55)
|
||||
return "Templar";
|
||||
else if (level >= 51)
|
||||
return "Vicar";
|
||||
else
|
||||
return "Cleric";
|
||||
case PALADIN:
|
||||
if (level >= 70)
|
||||
return "Lord";
|
||||
else if (level >= 65)
|
||||
return "Lord Protector";
|
||||
else if (level >= 60)
|
||||
return "Crusader";
|
||||
else if (level >= 55)
|
||||
return "Knight";
|
||||
else if (level >= 51)
|
||||
return "Cavalier";
|
||||
else
|
||||
return "Paladin";
|
||||
case RANGER:
|
||||
if (level >= 70)
|
||||
return "Plainswalker";
|
||||
else if (level >= 65)
|
||||
return "Forest Stalker";
|
||||
else if (level >= 60)
|
||||
return "Warder";
|
||||
else if (level >= 55)
|
||||
return "Outrider";
|
||||
else if (level >= 51)
|
||||
return "Pathfinder";
|
||||
else
|
||||
return "Ranger";
|
||||
case SHADOWKNIGHT:
|
||||
if (level >= 70)
|
||||
return "Scourge Knight";
|
||||
else if (level >= 65)
|
||||
return "Dread Lord";
|
||||
else if (level >= 60)
|
||||
return "Grave Lord";
|
||||
else if (level >= 55)
|
||||
return "Revenant";
|
||||
else if (level >= 51)
|
||||
return "Reaver";
|
||||
else
|
||||
return "Shadowknight";
|
||||
case DRUID:
|
||||
if (level >= 70)
|
||||
return "Natureguard";
|
||||
else if (level >= 65)
|
||||
return "Storm Warden";
|
||||
else if (level >= 60)
|
||||
return "Hierophant";
|
||||
else if (level >= 55)
|
||||
return "Preserver";
|
||||
else if (level >= 51)
|
||||
return "Wanderer";
|
||||
else
|
||||
return "Druid";
|
||||
case MONK:
|
||||
if (level >= 70)
|
||||
return "Stone Fist";
|
||||
else if (level >= 65)
|
||||
return "Transcendent";
|
||||
else if (level >= 60)
|
||||
return "Grandmaster";
|
||||
else if (level >= 55)
|
||||
return "Master";
|
||||
else if (level >= 51)
|
||||
return "Disciple";
|
||||
else
|
||||
return "Monk";
|
||||
case BARD:
|
||||
if (level >= 70)
|
||||
return "Performer";
|
||||
else if (level >= 65)
|
||||
return "Maestro";
|
||||
else if (level >= 60)
|
||||
return "Virtuoso";
|
||||
else if (level >= 55)
|
||||
return "Troubadour";
|
||||
else if (level >= 51)
|
||||
return "Minstrel";
|
||||
else
|
||||
return "Bard";
|
||||
case ROGUE:
|
||||
if (level >= 70)
|
||||
return "Nemesis";
|
||||
else if (level >= 65)
|
||||
return "Deceiver";
|
||||
else if (level >= 60)
|
||||
return "Assassin";
|
||||
else if (level >= 55)
|
||||
return "Blackguard";
|
||||
else if (level >= 51)
|
||||
return "Rake";
|
||||
else
|
||||
return "Rogue";
|
||||
case SHAMAN:
|
||||
if (level >= 70)
|
||||
return "Soothsayer";
|
||||
else if (level >= 65)
|
||||
return "Prophet";
|
||||
else if (level >= 60)
|
||||
return "Oracle";
|
||||
else if (level >= 55)
|
||||
return "Luminary";
|
||||
else if (level >= 51)
|
||||
return "Mystic";
|
||||
else
|
||||
return "Shaman";
|
||||
case NECROMANCER:
|
||||
if (level >= 70)
|
||||
return "Wraith";
|
||||
else if (level >= 65)
|
||||
return "Arch Lich";
|
||||
else if (level >= 60)
|
||||
return "Warlock";
|
||||
else if (level >= 55)
|
||||
return "Defiler";
|
||||
else if (level >= 51)
|
||||
return "Heretic";
|
||||
else
|
||||
return "Necromancer";
|
||||
case WIZARD:
|
||||
if (level >= 70)
|
||||
return "Grand Arcanist";
|
||||
else if (level >= 65)
|
||||
return "Arcanist";
|
||||
else if (level >= 60)
|
||||
return "Sorcerer";
|
||||
else if (level >= 55)
|
||||
return "Evoker";
|
||||
else if (level >= 51)
|
||||
return "Channeler";
|
||||
else
|
||||
return "Wizard";
|
||||
case MAGICIAN:
|
||||
if (level >= 70)
|
||||
return "Arch Magus";
|
||||
else if (level >= 65)
|
||||
return "Arch Convoker";
|
||||
else if (level >= 60)
|
||||
return "Arch Mage";
|
||||
else if (level >= 55)
|
||||
return "Conjurer";
|
||||
if (level >= 51)
|
||||
return "Elementalist";
|
||||
else
|
||||
return "Magician";
|
||||
case ENCHANTER:
|
||||
if (level >= 70)
|
||||
return "Bedazzler";
|
||||
else if (level >= 65)
|
||||
return "Coercer";
|
||||
else if (level >= 60)
|
||||
return "Phantasmist";
|
||||
else if (level >= 55)
|
||||
return "Beguiler";
|
||||
else if (level >= 51)
|
||||
return "Illusionist";
|
||||
else
|
||||
return "Enchanter";
|
||||
case BEASTLORD:
|
||||
if (level >= 70)
|
||||
return "Wildblood";
|
||||
else if (level >= 65)
|
||||
return "Feral Lord";
|
||||
else if (level >= 60)
|
||||
return "Savage Lord";
|
||||
else if (level >= 55)
|
||||
return "Animist";
|
||||
else if (level >= 51)
|
||||
return "Primalist";
|
||||
else
|
||||
return "Beastlord";
|
||||
case BERSERKER:
|
||||
if (level >= 70)
|
||||
return "Ravager";
|
||||
else if (level >= 65)
|
||||
return "Fury";
|
||||
else if (level >= 60)
|
||||
return "Rager";
|
||||
else if (level >= 55)
|
||||
return "Vehement";
|
||||
else if (level >= 51)
|
||||
return "Brawler";
|
||||
else
|
||||
return "Berserker";
|
||||
case BANKER:
|
||||
if (level >= 70)
|
||||
return "Master Banker";
|
||||
else if (level >= 65)
|
||||
return "Elder Banker";
|
||||
else if (level >= 60)
|
||||
return "Oldest Banker";
|
||||
else if (level >= 55)
|
||||
return "Older Banker";
|
||||
else if (level >= 51)
|
||||
return "Old Banker";
|
||||
else
|
||||
return "Banker";
|
||||
case WARRIORGM:
|
||||
return "Warrior Guildmaster";
|
||||
case CLERICGM:
|
||||
return "Cleric Guildmaster";
|
||||
case PALADINGM:
|
||||
return "Paladin Guildmaster";
|
||||
case RANGERGM:
|
||||
return "Ranger Guildmaster";
|
||||
case SHADOWKNIGHTGM:
|
||||
return "Shadowknight Guildmaster";
|
||||
case DRUIDGM:
|
||||
return "Druid Guildmaster";
|
||||
case MONKGM:
|
||||
return "Monk Guildmaster";
|
||||
case BARDGM:
|
||||
return "Bard Guildmaster";
|
||||
case ROGUEGM:
|
||||
return "Rogue Guildmaster";
|
||||
case SHAMANGM:
|
||||
return "Shaman Guildmaster";
|
||||
case NECROMANCERGM:
|
||||
return "Necromancer Guildmaster";
|
||||
case WIZARDGM:
|
||||
return "Wizard Guildmaster";
|
||||
case MAGICIANGM:
|
||||
return "Magician Guildmaster";
|
||||
case ENCHANTERGM:
|
||||
return "Enchanter Guildmaster";
|
||||
case BEASTLORDGM:
|
||||
return "Beastlord Guildmaster";
|
||||
case BERSERKERGM:
|
||||
return "Berserker Guildmaster";
|
||||
case MERCHANT:
|
||||
return "Merchant";
|
||||
case ADVENTURERECRUITER:
|
||||
return "Adventure Recruiter";
|
||||
case ADVENTUREMERCHANT:
|
||||
return "Adventure Merchant";
|
||||
case CORPSE_CLASS:
|
||||
return "Corpse Class";
|
||||
case TRIBUTE_MASTER:
|
||||
return "Tribute Master";
|
||||
case GUILD_TRIBUTE_MASTER:
|
||||
return "Guild Tribute Master";
|
||||
default:
|
||||
return "Unknown";
|
||||
const char* GetClassIDName(uint8 class_id, uint8 level)
|
||||
{
|
||||
switch (class_id) {
|
||||
case WARRIOR:
|
||||
if (level >= 70)
|
||||
return "Vanquisher";
|
||||
else if (level >= 65)
|
||||
return "Overlord"; //Baron-Sprite: LEAVE MY CLASSES ALONE.
|
||||
else if (level >= 60)
|
||||
return "Warlord";
|
||||
else if (level >= 55)
|
||||
return "Myrmidon";
|
||||
else if (level >= 51)
|
||||
return "Champion";
|
||||
else
|
||||
return "Warrior";
|
||||
case CLERIC:
|
||||
if (level >= 70)
|
||||
return "Prelate";
|
||||
else if (level >= 65)
|
||||
return "Archon";
|
||||
else if (level >= 60)
|
||||
return "High Priest";
|
||||
else if (level >= 55)
|
||||
return "Templar";
|
||||
else if (level >= 51)
|
||||
return "Vicar";
|
||||
else
|
||||
return "Cleric";
|
||||
case PALADIN:
|
||||
if (level >= 70)
|
||||
return "Lord";
|
||||
else if (level >= 65)
|
||||
return "Lord Protector";
|
||||
else if (level >= 60)
|
||||
return "Crusader";
|
||||
else if (level >= 55)
|
||||
return "Knight";
|
||||
else if (level >= 51)
|
||||
return "Cavalier";
|
||||
else
|
||||
return "Paladin";
|
||||
case RANGER:
|
||||
if (level >= 70)
|
||||
return "Plainswalker";
|
||||
else if (level >= 65)
|
||||
return "Forest Stalker";
|
||||
else if (level >= 60)
|
||||
return "Warder";
|
||||
else if (level >= 55)
|
||||
return "Outrider";
|
||||
else if (level >= 51)
|
||||
return "Pathfinder";
|
||||
else
|
||||
return "Ranger";
|
||||
case SHADOWKNIGHT:
|
||||
if (level >= 70)
|
||||
return "Scourge Knight";
|
||||
else if (level >= 65)
|
||||
return "Dread Lord";
|
||||
else if (level >= 60)
|
||||
return "Grave Lord";
|
||||
else if (level >= 55)
|
||||
return "Revenant";
|
||||
else if (level >= 51)
|
||||
return "Reaver";
|
||||
else
|
||||
return "Shadowknight";
|
||||
case DRUID:
|
||||
if (level >= 70)
|
||||
return "Natureguard";
|
||||
else if (level >= 65)
|
||||
return "Storm Warden";
|
||||
else if (level >= 60)
|
||||
return "Hierophant";
|
||||
else if (level >= 55)
|
||||
return "Preserver";
|
||||
else if (level >= 51)
|
||||
return "Wanderer";
|
||||
else
|
||||
return "Druid";
|
||||
case MONK:
|
||||
if (level >= 70)
|
||||
return "Stone Fist";
|
||||
else if (level >= 65)
|
||||
return "Transcendent";
|
||||
else if (level >= 60)
|
||||
return "Grandmaster";
|
||||
else if (level >= 55)
|
||||
return "Master";
|
||||
else if (level >= 51)
|
||||
return "Disciple";
|
||||
else
|
||||
return "Monk";
|
||||
case BARD:
|
||||
if (level >= 70)
|
||||
return "Performer";
|
||||
else if (level >= 65)
|
||||
return "Maestro";
|
||||
else if (level >= 60)
|
||||
return "Virtuoso";
|
||||
else if (level >= 55)
|
||||
return "Troubadour";
|
||||
else if (level >= 51)
|
||||
return "Minstrel";
|
||||
else
|
||||
return "Bard";
|
||||
case ROGUE:
|
||||
if (level >= 70)
|
||||
return "Nemesis";
|
||||
else if (level >= 65)
|
||||
return "Deceiver";
|
||||
else if (level >= 60)
|
||||
return "Assassin";
|
||||
else if (level >= 55)
|
||||
return "Blackguard";
|
||||
else if (level >= 51)
|
||||
return "Rake";
|
||||
else
|
||||
return "Rogue";
|
||||
case SHAMAN:
|
||||
if (level >= 70)
|
||||
return "Soothsayer";
|
||||
else if (level >= 65)
|
||||
return "Prophet";
|
||||
else if (level >= 60)
|
||||
return "Oracle";
|
||||
else if (level >= 55)
|
||||
return "Luminary";
|
||||
else if (level >= 51)
|
||||
return "Mystic";
|
||||
else
|
||||
return "Shaman";
|
||||
case NECROMANCER:
|
||||
if (level >= 70)
|
||||
return "Wraith";
|
||||
else if (level >= 65)
|
||||
return "Arch Lich";
|
||||
else if (level >= 60)
|
||||
return "Warlock";
|
||||
else if (level >= 55)
|
||||
return "Defiler";
|
||||
else if (level >= 51)
|
||||
return "Heretic";
|
||||
else
|
||||
return "Necromancer";
|
||||
case WIZARD:
|
||||
if (level >= 70)
|
||||
return "Grand Arcanist";
|
||||
else if (level >= 65)
|
||||
return "Arcanist";
|
||||
else if (level >= 60)
|
||||
return "Sorcerer";
|
||||
else if (level >= 55)
|
||||
return "Evoker";
|
||||
else if (level >= 51)
|
||||
return "Channeler";
|
||||
else
|
||||
return "Wizard";
|
||||
case MAGICIAN:
|
||||
if (level >= 70)
|
||||
return "Arch Magus";
|
||||
else if (level >= 65)
|
||||
return "Arch Convoker";
|
||||
else if (level >= 60)
|
||||
return "Arch Mage";
|
||||
else if (level >= 55)
|
||||
return "Conjurer";
|
||||
if (level >= 51)
|
||||
return "Elementalist";
|
||||
else
|
||||
return "Magician";
|
||||
case ENCHANTER:
|
||||
if (level >= 70)
|
||||
return "Bedazzler";
|
||||
else if (level >= 65)
|
||||
return "Coercer";
|
||||
else if (level >= 60)
|
||||
return "Phantasmist";
|
||||
else if (level >= 55)
|
||||
return "Beguiler";
|
||||
else if (level >= 51)
|
||||
return "Illusionist";
|
||||
else
|
||||
return "Enchanter";
|
||||
case BEASTLORD:
|
||||
if (level >= 70)
|
||||
return "Wildblood";
|
||||
else if (level >= 65)
|
||||
return "Feral Lord";
|
||||
else if (level >= 60)
|
||||
return "Savage Lord";
|
||||
else if (level >= 55)
|
||||
return "Animist";
|
||||
else if (level >= 51)
|
||||
return "Primalist";
|
||||
else
|
||||
return "Beastlord";
|
||||
case BERSERKER:
|
||||
if (level >= 70)
|
||||
return "Ravager";
|
||||
else if (level >= 65)
|
||||
return "Fury";
|
||||
else if (level >= 60)
|
||||
return "Rager";
|
||||
else if (level >= 55)
|
||||
return "Vehement";
|
||||
else if (level >= 51)
|
||||
return "Brawler";
|
||||
else
|
||||
return "Berserker";
|
||||
case BANKER:
|
||||
if (level >= 70)
|
||||
return "Master Banker";
|
||||
else if (level >= 65)
|
||||
return "Elder Banker";
|
||||
else if (level >= 60)
|
||||
return "Oldest Banker";
|
||||
else if (level >= 55)
|
||||
return "Older Banker";
|
||||
else if (level >= 51)
|
||||
return "Old Banker";
|
||||
else
|
||||
return "Banker";
|
||||
case WARRIORGM:
|
||||
return "Warrior Guildmaster";
|
||||
case CLERICGM:
|
||||
return "Cleric Guildmaster";
|
||||
case PALADINGM:
|
||||
return "Paladin Guildmaster";
|
||||
case RANGERGM:
|
||||
return "Ranger Guildmaster";
|
||||
case SHADOWKNIGHTGM:
|
||||
return "Shadowknight Guildmaster";
|
||||
case DRUIDGM:
|
||||
return "Druid Guildmaster";
|
||||
case MONKGM:
|
||||
return "Monk Guildmaster";
|
||||
case BARDGM:
|
||||
return "Bard Guildmaster";
|
||||
case ROGUEGM:
|
||||
return "Rogue Guildmaster";
|
||||
case SHAMANGM:
|
||||
return "Shaman Guildmaster";
|
||||
case NECROMANCERGM:
|
||||
return "Necromancer Guildmaster";
|
||||
case WIZARDGM:
|
||||
return "Wizard Guildmaster";
|
||||
case MAGICIANGM:
|
||||
return "Magician Guildmaster";
|
||||
case ENCHANTERGM:
|
||||
return "Enchanter Guildmaster";
|
||||
case BEASTLORDGM:
|
||||
return "Beastlord Guildmaster";
|
||||
case BERSERKERGM:
|
||||
return "Berserker Guildmaster";
|
||||
case MERCHANT:
|
||||
return "Merchant";
|
||||
case ADVENTURERECRUITER:
|
||||
return "Adventure Recruiter";
|
||||
case ADVENTUREMERCHANT:
|
||||
return "Adventure Merchant";
|
||||
case CORPSE_CLASS:
|
||||
return "Corpse Class";
|
||||
case TRIBUTE_MASTER:
|
||||
return "Tribute Master";
|
||||
case GUILD_TRIBUTE_MASTER:
|
||||
return "Guild Tribute Master";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
const char* GetPlayerClassName(uint32 player_class_value, uint8 level)
|
||||
{
|
||||
return GetClassIDName(GetClassIDFromPlayerClassValue(player_class_value), level);
|
||||
}
|
||||
|
||||
uint32 GetPlayerClassValue(uint8 class_id)
|
||||
{
|
||||
switch (class_id) {
|
||||
case WARRIOR:
|
||||
case CLERIC:
|
||||
case PALADIN:
|
||||
case RANGER:
|
||||
case SHADOWKNIGHT:
|
||||
case DRUID:
|
||||
case MONK:
|
||||
case BARD:
|
||||
case ROGUE:
|
||||
case SHAMAN:
|
||||
case NECROMANCER:
|
||||
case WIZARD:
|
||||
case MAGICIAN:
|
||||
case ENCHANTER:
|
||||
case BEASTLORD:
|
||||
case BERSERKER:
|
||||
return class_id;
|
||||
default:
|
||||
return PLAYER_CLASS_UNKNOWN; // watch
|
||||
}
|
||||
}
|
||||
|
||||
uint32 GetPlayerClassBit(uint8 class_id)
|
||||
{
|
||||
switch (class_id) {
|
||||
case WARRIOR:
|
||||
return PLAYER_CLASS_WARRIOR_BIT;
|
||||
case CLERIC:
|
||||
return PLAYER_CLASS_CLERIC_BIT;
|
||||
case PALADIN:
|
||||
return PLAYER_CLASS_PALADIN_BIT;
|
||||
case RANGER:
|
||||
return PLAYER_CLASS_RANGER_BIT;
|
||||
case SHADOWKNIGHT:
|
||||
return PLAYER_CLASS_SHADOWKNIGHT_BIT;
|
||||
case DRUID:
|
||||
return PLAYER_CLASS_DRUID_BIT;
|
||||
case MONK:
|
||||
return PLAYER_CLASS_MONK_BIT;
|
||||
case BARD:
|
||||
return PLAYER_CLASS_BARD_BIT;
|
||||
case ROGUE:
|
||||
return PLAYER_CLASS_ROGUE_BIT;
|
||||
case SHAMAN:
|
||||
return PLAYER_CLASS_SHAMAN_BIT;
|
||||
case NECROMANCER:
|
||||
return PLAYER_CLASS_NECROMANCER_BIT;
|
||||
case WIZARD:
|
||||
return PLAYER_CLASS_WIZARD_BIT;
|
||||
case MAGICIAN:
|
||||
return PLAYER_CLASS_MAGICIAN_BIT;
|
||||
case ENCHANTER:
|
||||
return PLAYER_CLASS_ENCHANTER_BIT;
|
||||
case BEASTLORD:
|
||||
return PLAYER_CLASS_BEASTLORD_BIT;
|
||||
case BERSERKER:
|
||||
return PLAYER_CLASS_BERSERKER_BIT;
|
||||
default:
|
||||
return PLAYER_CLASS_UNKNOWN_BIT;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 GetClassIDFromPlayerClassValue(uint32 player_class_value)
|
||||
{
|
||||
switch (player_class_value) {
|
||||
case PLAYER_CLASS_WARRIOR:
|
||||
case PLAYER_CLASS_CLERIC:
|
||||
case PLAYER_CLASS_PALADIN:
|
||||
case PLAYER_CLASS_RANGER:
|
||||
case PLAYER_CLASS_SHADOWKNIGHT:
|
||||
case PLAYER_CLASS_DRUID:
|
||||
case PLAYER_CLASS_MONK:
|
||||
case PLAYER_CLASS_BARD:
|
||||
case PLAYER_CLASS_ROGUE:
|
||||
case PLAYER_CLASS_SHAMAN:
|
||||
case PLAYER_CLASS_NECROMANCER:
|
||||
case PLAYER_CLASS_WIZARD:
|
||||
case PLAYER_CLASS_MAGICIAN:
|
||||
case PLAYER_CLASS_ENCHANTER:
|
||||
case PLAYER_CLASS_BEASTLORD:
|
||||
case PLAYER_CLASS_BERSERKER:
|
||||
return player_class_value;
|
||||
default:
|
||||
return PLAYER_CLASS_UNKNOWN; // watch
|
||||
}
|
||||
}
|
||||
|
||||
uint8 GetClassIDFromPlayerClassBit(uint32 player_class_bit)
|
||||
{
|
||||
switch (player_class_bit) {
|
||||
case PLAYER_CLASS_WARRIOR_BIT:
|
||||
return WARRIOR;
|
||||
case PLAYER_CLASS_CLERIC_BIT:
|
||||
return CLERIC;
|
||||
case PLAYER_CLASS_PALADIN_BIT:
|
||||
return PALADIN;
|
||||
case PLAYER_CLASS_RANGER_BIT:
|
||||
return RANGER;
|
||||
case PLAYER_CLASS_SHADOWKNIGHT_BIT:
|
||||
return SHADOWKNIGHT;
|
||||
case PLAYER_CLASS_DRUID_BIT:
|
||||
return DRUID;
|
||||
case PLAYER_CLASS_MONK_BIT:
|
||||
return MONK;
|
||||
case PLAYER_CLASS_BARD_BIT:
|
||||
return BARD;
|
||||
case PLAYER_CLASS_ROGUE_BIT:
|
||||
return ROGUE;
|
||||
case PLAYER_CLASS_SHAMAN_BIT:
|
||||
return SHAMAN;
|
||||
case PLAYER_CLASS_NECROMANCER_BIT:
|
||||
return NECROMANCER;
|
||||
case PLAYER_CLASS_WIZARD_BIT:
|
||||
return WIZARD;
|
||||
case PLAYER_CLASS_MAGICIAN_BIT:
|
||||
return MAGICIAN;
|
||||
case PLAYER_CLASS_ENCHANTER_BIT:
|
||||
return ENCHANTER;
|
||||
case PLAYER_CLASS_BEASTLORD_BIT:
|
||||
return BEASTLORD;
|
||||
case PLAYER_CLASS_BERSERKER_BIT:
|
||||
return BERSERKER;
|
||||
default:
|
||||
return PLAYER_CLASS_UNKNOWN; // watch
|
||||
}
|
||||
}
|
||||
|
||||
bool IsFighterClass(uint8 class_id)
|
||||
{
|
||||
switch (class_id) {
|
||||
case WARRIOR:
|
||||
case PALADIN:
|
||||
case RANGER:
|
||||
case SHADOWKNIGHT:
|
||||
case MONK:
|
||||
case BARD:
|
||||
case ROGUE:
|
||||
case BEASTLORD:
|
||||
case BERSERKER:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsSpellFighterClass(uint8 class_id)
|
||||
{
|
||||
switch (class_id) {
|
||||
case PALADIN:
|
||||
case RANGER:
|
||||
case SHADOWKNIGHT:
|
||||
case BEASTLORD:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsNonSpellFighterClass(uint8 class_id)
|
||||
{
|
||||
switch (class_id) {
|
||||
case WARRIOR:
|
||||
case MONK:
|
||||
case BARD:
|
||||
case ROGUE:
|
||||
case BERSERKER:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsCasterClass(uint8 class_id)
|
||||
{
|
||||
switch (class_id) {
|
||||
case CLERIC:
|
||||
case DRUID:
|
||||
case SHAMAN:
|
||||
case NECROMANCER:
|
||||
case WIZARD:
|
||||
case MAGICIAN:
|
||||
case ENCHANTER:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsINTCasterClass(uint8 class_id)
|
||||
{
|
||||
switch (class_id) {
|
||||
case NECROMANCER:
|
||||
case WIZARD:
|
||||
case MAGICIAN:
|
||||
case ENCHANTER:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsWISCasterClass(uint8 class_id)
|
||||
{
|
||||
switch (class_id) {
|
||||
case CLERIC:
|
||||
case DRUID:
|
||||
case SHAMAN:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsPlateClass(uint8 class_id)
|
||||
{
|
||||
switch (class_id) {
|
||||
case WARRIOR:
|
||||
case CLERIC:
|
||||
case PALADIN:
|
||||
case SHADOWKNIGHT:
|
||||
case BARD:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsChainClass(uint8 class_id)
|
||||
{
|
||||
switch (class_id) {
|
||||
case RANGER:
|
||||
case ROGUE:
|
||||
case SHAMAN:
|
||||
case BERSERKER:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsLeatherClass(uint8 class_id)
|
||||
{
|
||||
switch (class_id) {
|
||||
case DRUID:
|
||||
case MONK:
|
||||
case BEASTLORD:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsClothClass(uint8 class_id)
|
||||
{
|
||||
switch (class_id) {
|
||||
case NECROMANCER:
|
||||
case WIZARD:
|
||||
case MAGICIAN:
|
||||
case ENCHANTER:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 ClassArmorType(uint8 class_id)
|
||||
{
|
||||
switch (class_id) {
|
||||
case WARRIOR:
|
||||
case CLERIC:
|
||||
case PALADIN:
|
||||
case SHADOWKNIGHT:
|
||||
case BARD:
|
||||
return ARMOR_TYPE_PLATE;
|
||||
case RANGER:
|
||||
case ROGUE:
|
||||
case SHAMAN:
|
||||
case BERSERKER:
|
||||
return ARMOR_TYPE_CHAIN;
|
||||
case DRUID:
|
||||
case MONK:
|
||||
case BEASTLORD:
|
||||
return ARMOR_TYPE_LEATHER;
|
||||
case NECROMANCER:
|
||||
case WIZARD:
|
||||
case MAGICIAN:
|
||||
case ENCHANTER:
|
||||
return ARMOR_TYPE_CLOTH;
|
||||
default:
|
||||
return ARMOR_TYPE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
142
common/classes.h
142
common/classes.h
@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemu.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -17,26 +17,25 @@
|
||||
*/
|
||||
#ifndef CLASSES_CH
|
||||
#define CLASSES_CH
|
||||
|
||||
#include "../common/types.h"
|
||||
|
||||
#define Array_Class_UNKNOWN 0
|
||||
#define WARRIOR 1
|
||||
#define CLERIC 2
|
||||
#define PALADIN 3
|
||||
#define RANGER 4
|
||||
#define SHADOWKNIGHT 5
|
||||
#define DRUID 6
|
||||
#define MONK 7
|
||||
#define BARD 8
|
||||
#define ROGUE 9
|
||||
#define SHAMAN 10
|
||||
#define NECROMANCER 11
|
||||
#define WIZARD 12
|
||||
#define MAGICIAN 13
|
||||
#define ENCHANTER 14
|
||||
#define BEASTLORD 15
|
||||
#define BERSERKER 16
|
||||
#define PLAYER_CLASS_COUNT 16 // used for array defines, must be the count of playable classes
|
||||
#define WARRIOR 1
|
||||
#define CLERIC 2
|
||||
#define PALADIN 3
|
||||
#define RANGER 4
|
||||
#define SHADOWKNIGHT 5
|
||||
#define DRUID 6
|
||||
#define MONK 7
|
||||
#define BARD 8
|
||||
#define ROGUE 9
|
||||
#define SHAMAN 10
|
||||
#define NECROMANCER 11
|
||||
#define WIZARD 12
|
||||
#define MAGICIAN 13
|
||||
#define ENCHANTER 14
|
||||
#define BEASTLORD 15
|
||||
#define BERSERKER 16
|
||||
#define WARRIORGM 20
|
||||
#define CLERICGM 21
|
||||
#define PALADINGM 22
|
||||
@ -58,33 +57,92 @@
|
||||
#define DISCORD_MERCHANT 59
|
||||
#define ADVENTURERECRUITER 60
|
||||
#define ADVENTUREMERCHANT 61
|
||||
#define LDON_TREASURE 62 //objects you can use /open on first seen in LDONs
|
||||
#define CORPSE_CLASS 62 //only seen on Danvi's Corpse in Akheva so far..
|
||||
#define TRIBUTE_MASTER 63
|
||||
#define GUILD_TRIBUTE_MASTER 64 //not sure
|
||||
#define LDON_TREASURE 62 // objects you can use /open on first seen in LDONs
|
||||
#define CORPSE_CLASS 62 // only seen on Danvi's Corpse in Akheva so far..
|
||||
#define TRIBUTE_MASTER 63
|
||||
#define GUILD_TRIBUTE_MASTER 64 // not sure
|
||||
#define NORRATHS_KEEPERS_MERCHANT 67
|
||||
#define DARK_REIGN_MERCHANT 68
|
||||
#define FELLOWSHIP_MASTER 69
|
||||
#define ALT_CURRENCY_MERCHANT 70
|
||||
#define MERCERNARY_MASTER 71
|
||||
#define warrior_1 1
|
||||
#define monk_1 64
|
||||
#define paladin_1 4
|
||||
#define shadow_1 16
|
||||
#define bard_1 128
|
||||
#define cleric_1 2
|
||||
#define necromancer_1 1024
|
||||
#define ranger_1 8
|
||||
#define druid_1 32
|
||||
#define mage_1 4096
|
||||
#define wizard_1 2048
|
||||
#define enchanter_1 8192
|
||||
#define rogue_1 256
|
||||
#define shaman_1 512
|
||||
#define beastlord_1 16384
|
||||
#define berserker_1 32768
|
||||
#define call_1 65536
|
||||
|
||||
const char* GetEQClassName(uint8 class_, uint8 level = 0);
|
||||
|
||||
// player class values
|
||||
#define PLAYER_CLASS_UNKNOWN 0
|
||||
#define PLAYER_CLASS_WARRIOR 1
|
||||
#define PLAYER_CLASS_CLERIC 2
|
||||
#define PLAYER_CLASS_PALADIN 3
|
||||
#define PLAYER_CLASS_RANGER 4
|
||||
#define PLAYER_CLASS_SHADOWKNIGHT 5
|
||||
#define PLAYER_CLASS_DRUID 6
|
||||
#define PLAYER_CLASS_MONK 7
|
||||
#define PLAYER_CLASS_BARD 8
|
||||
#define PLAYER_CLASS_ROGUE 9
|
||||
#define PLAYER_CLASS_SHAMAN 10
|
||||
#define PLAYER_CLASS_NECROMANCER 11
|
||||
#define PLAYER_CLASS_WIZARD 12
|
||||
#define PLAYER_CLASS_MAGICIAN 13
|
||||
#define PLAYER_CLASS_ENCHANTER 14
|
||||
#define PLAYER_CLASS_BEASTLORD 15
|
||||
#define PLAYER_CLASS_BERSERKER 16
|
||||
|
||||
#define PLAYER_CLASS_COUNT 16
|
||||
|
||||
|
||||
// player class bits
|
||||
#define PLAYER_CLASS_UNKNOWN_BIT 0
|
||||
#define PLAYER_CLASS_WARRIOR_BIT 1
|
||||
#define PLAYER_CLASS_CLERIC_BIT 2
|
||||
#define PLAYER_CLASS_PALADIN_BIT 4
|
||||
#define PLAYER_CLASS_RANGER_BIT 8
|
||||
#define PLAYER_CLASS_SHADOWKNIGHT_BIT 16
|
||||
#define PLAYER_CLASS_DRUID_BIT 32
|
||||
#define PLAYER_CLASS_MONK_BIT 64
|
||||
#define PLAYER_CLASS_BARD_BIT 128
|
||||
#define PLAYER_CLASS_ROGUE_BIT 256
|
||||
#define PLAYER_CLASS_SHAMAN_BIT 512
|
||||
#define PLAYER_CLASS_NECROMANCER_BIT 1024
|
||||
#define PLAYER_CLASS_WIZARD_BIT 2048
|
||||
#define PLAYER_CLASS_MAGICIAN_BIT 4096
|
||||
#define PLAYER_CLASS_ENCHANTER_BIT 8192
|
||||
#define PLAYER_CLASS_BEASTLORD_BIT 16384
|
||||
#define PLAYER_CLASS_BERSERKER_BIT 32768
|
||||
|
||||
#define PLAYER_CLASS_ALL_MASK 65535 // was 65536
|
||||
|
||||
|
||||
#define ARMOR_TYPE_UNKNOWN 0
|
||||
#define ARMOR_TYPE_CLOTH 1
|
||||
#define ARMOR_TYPE_LEATHER 2
|
||||
#define ARMOR_TYPE_CHAIN 3
|
||||
#define ARMOR_TYPE_PLATE 4
|
||||
|
||||
#define ARMOR_TYPE_FIRST ARMOR_TYPE_UNKNOWN
|
||||
#define ARMOR_TYPE_LAST ARMOR_TYPE_PLATE
|
||||
#define ARMOR_TYPE_COUNT 5
|
||||
|
||||
|
||||
const char* GetClassIDName(uint8 class_id, uint8 level = 0);
|
||||
const char* GetPlayerClassName(uint32 player_class_value, uint8 level = 0);
|
||||
|
||||
uint32 GetPlayerClassValue(uint8 class_id);
|
||||
uint32 GetPlayerClassBit(uint8 class_id);
|
||||
|
||||
uint8 GetClassIDFromPlayerClassValue(uint32 player_class_value);
|
||||
uint8 GetClassIDFromPlayerClassBit(uint32 player_class_bit);
|
||||
|
||||
bool IsFighterClass(uint8 class_id);
|
||||
bool IsSpellFighterClass(uint8 class_id);
|
||||
bool IsNonSpellFighterClass(uint8 class_id);
|
||||
bool IsCasterClass(uint8 class_id);
|
||||
bool IsINTCasterClass(uint8 class_id);
|
||||
bool IsWISCasterClass(uint8 class_id);
|
||||
|
||||
bool IsPlateClass(uint8 class_id);
|
||||
bool IsChainClass(uint8 class_id);
|
||||
bool IsLeatherClass(uint8 class_id);
|
||||
bool IsClothClass(uint8 class_id);
|
||||
uint8 ClassArmorType(uint8 class_id);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.net)
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -88,7 +88,7 @@ class Database : public DBcore {
|
||||
public:
|
||||
Database();
|
||||
Database(const char* host, const char* user, const char* passwd, const char* database,uint32 port);
|
||||
bool Connect(const char* host, const char* user, const char* passwd, const char* database,uint32 port);
|
||||
bool Connect(const char* host, const char* user, const char* passwd, const char* database, uint32 port);
|
||||
~Database();
|
||||
|
||||
/* Character Creation */
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.net)
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -390,30 +390,47 @@ enum {
|
||||
ET_Scroll = 7
|
||||
};
|
||||
|
||||
//SpawnAppearance types:
|
||||
#define AT_Die 0 // this causes the client to keel over and zone to bind point
|
||||
#define AT_WhoLevel 1 // the level that shows up on /who
|
||||
#define AT_Invis 3 // 0 = visible, 1 = invisible
|
||||
#define AT_PVP 4 // 0 = blue, 1 = pvp (red)
|
||||
#define AT_Light 5 // light type emitted by player (lightstone, shiny shield)
|
||||
#define AT_Anim 14 // 100=standing, 110=sitting, 111=ducking, 115=feigned, 105=looting
|
||||
#define AT_Sneak 15 // 0 = normal, 1 = sneaking
|
||||
#define AT_SpawnID 16 // server to client, sets player spawn id
|
||||
#define AT_HP 17 // Client->Server, my HP has changed (like regen tic)
|
||||
#define AT_Linkdead 18 // 0 = normal, 1 = linkdead
|
||||
#define AT_Levitate 19 // 0=off, 1=flymode, 2=levitate
|
||||
#define AT_GM 20 // 0 = normal, 1 = GM - all odd numbers seem to make it GM
|
||||
#define AT_Anon 21 // 0 = normal, 1 = anon, 2 = roleplay
|
||||
#define AT_GuildID 22
|
||||
#define AT_GuildRank 23 // 0=member, 1=officer, 2=leader
|
||||
#define AT_AFK 24 // 0 = normal, 1 = afk
|
||||
#define AT_Pet 25 // Param is EntityID of owner, or 0 for when charm breaks
|
||||
#define AT_Split 28 // 0 = normal, 1 = autosplit on
|
||||
#define AT_Size 29 // spawn's size
|
||||
#define AT_NPCName 31 // change PC's name's color to NPC color 0 = normal, 1 = npc name
|
||||
#define AT_ShowHelm 43 // 0 = do not show helmet graphic, 1 = show graphic
|
||||
#define AT_DamageState 44 // The damage state of a destructible object (0 through 4)
|
||||
//#define AT_Trader 300 // Bazzar Trader Mode
|
||||
//SpawnAppearance types: (compared two clients for server-originating types: SoF & RoF2)
|
||||
#define AT_Die 0 // this causes the client to keel over and zone to bind point (default action)
|
||||
#define AT_WhoLevel 1 // the level that shows up on /who
|
||||
//#define AT_2 2 // unknown
|
||||
#define AT_Invis 3 // 0 = visible, 1 = invisible
|
||||
#define AT_PVP 4 // 0 = blue, 1 = pvp (red)
|
||||
#define AT_Light 5 // light type emitted by player (lightstone, shiny shield)
|
||||
#define AT_Anim 14 // 100=standing, 110=sitting, 111=ducking, 115=feigned, 105=looting
|
||||
#define AT_Sneak 15 // 0 = normal, 1 = sneaking
|
||||
#define AT_SpawnID 16 // server to client, sets player spawn id
|
||||
#define AT_HP 17 // Client->Server, my HP has changed (like regen tic)
|
||||
#define AT_Linkdead 18 // 0 = normal, 1 = linkdead
|
||||
#define AT_Levitate 19 // 0=off, 1=flymode, 2=levitate
|
||||
#define AT_GM 20 // 0 = normal, 1 = GM - all odd numbers seem to make it GM
|
||||
#define AT_Anon 21 // 0 = normal, 1 = anon, 2 = roleplay
|
||||
#define AT_GuildID 22
|
||||
#define AT_GuildRank 23 // 0=member, 1=officer, 2=leader
|
||||
#define AT_AFK 24 // 0 = normal, 1 = afk
|
||||
#define AT_Pet 25 // Param is EntityID of owner, or 0 for when charm breaks
|
||||
//#define AT_27 27 // unknown
|
||||
#define AT_Split 28 // 0 = normal, 1 = autosplit on (not showing in SoF+) (client-to-server only)
|
||||
#define AT_Size 29 // spawn's size (present: SoF, absent: RoF2)
|
||||
//#define AT_30 30 // unknown
|
||||
#define AT_NPCName 31 // change PC's name's color to NPC color 0 = normal, 1 = npc name
|
||||
//#define AT_32 32 // unknown
|
||||
//#define AT_33 33 // unknown
|
||||
//#define AT_34 34 // unknown (present: SoF, absent: RoF2)
|
||||
//#define AT_35 35 // unknown
|
||||
//#define AT_36 36 // unknown
|
||||
//#define AT_37 37 // unknown
|
||||
//#define AT_38 38 // unknown
|
||||
//#define AT_39 39 // unknown
|
||||
#define AT_ShowHelm 43 // 0 = hide graphic, 1 = show graphic
|
||||
#define AT_DamageState 44 // The damage state of a destructible object (0 through 4)
|
||||
//#define AT_46 46 // unknown
|
||||
//#define AT_48 48 // unknown
|
||||
//#define AT_49 49 // unknown
|
||||
//#define AT_52 52 // (absent: SoF, present: RoF2) (not a replacement for RoF absent 29 or 34)
|
||||
//#define AT_53 53 // (absent: SoF, present: RoF2) (not a replacement for RoF absent 29 or 34)
|
||||
|
||||
//#define AT_Trader 300 // Bazaar Trader Mode (not present in SoF or RoF2)
|
||||
|
||||
// animations for AT_Anim
|
||||
#define ANIM_FREEZE 102
|
||||
@ -519,15 +536,40 @@ typedef enum {
|
||||
#define MT_StrikeThrough 339
|
||||
#define MT_Stun 340
|
||||
|
||||
// TODO: Really should combine above and below into one
|
||||
|
||||
//from showeq
|
||||
enum ChatColor
|
||||
{
|
||||
/*
|
||||
CC_Default = 0,
|
||||
CC_DarkGrey = 1,
|
||||
CC_DarkGreen = 2,
|
||||
CC_DarkBlue = 3,
|
||||
CC_Purple = 5,
|
||||
CC_LightGrey = 6,
|
||||
*/
|
||||
|
||||
CC_WhiteSmoke = 0, // FF|F0F0F0
|
||||
CC_Green = 2, // FF|008000
|
||||
CC_BrightBlue = 3, // FF|0040FF
|
||||
CC_Magenta = 5, // FF|F000F0
|
||||
CC_Gray = 6, // FF|808080
|
||||
CC_LightGray = 7, // FF|E0E0E0
|
||||
//CC_WhiteSmoke2 = 10, // FF|F0F0F0
|
||||
CC_DarkGray = 12, // FF|A0A0A0
|
||||
CC_Red = 13, // FF|F00000
|
||||
CC_Lime = 14, // FF|00F000
|
||||
CC_Yellow = 15, // FF|F0F000
|
||||
CC_Blue = 16, // FF|0000F0
|
||||
CC_LightNavy = 17, // FF|0000AF
|
||||
CC_Cyan = 18, // FF|00F0F0
|
||||
CC_Black = 20, // FF|000000
|
||||
|
||||
// any index <= 255 that is not defined above
|
||||
CC_DimGray = 1, // FF|606060
|
||||
CC_Default = 1,
|
||||
|
||||
CC_User_Say = 256,
|
||||
CC_User_Tell = 257,
|
||||
CC_User_Group = 258,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.net)
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -3063,7 +3063,7 @@ bool Item_Struct::IsEquipable(uint16 Race, uint16 Class_) const
|
||||
|
||||
uint32 Classes_ = Classes;
|
||||
uint32 Races_ = Races;
|
||||
uint32 Race_ = GetArrayRace(Race);
|
||||
uint32 Race_ = GetPlayerRaceValue(Race);
|
||||
|
||||
for (int CurrentClass = 1; CurrentClass <= PLAYER_CLASS_COUNT; ++CurrentClass) {
|
||||
if (Classes_ & 1) {
|
||||
|
||||
@ -1,3 +1,20 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#define ENCODE(x) void Strategy::Encode_##x(EQApplicationPacket **p, std::shared_ptr<EQStream> dest, bool ack_req)
|
||||
#define DECODE(x) void Strategy::Decode_##x(EQApplicationPacket *__packet)
|
||||
@ -116,6 +133,12 @@
|
||||
//a shorter assignment for direct mode
|
||||
#undef IN
|
||||
#define IN(x) emu->x = eq->x;
|
||||
#define IN_str(x) \
|
||||
strncpy(emu->x, eq->x, sizeof(emu->x)); \
|
||||
emu->x[sizeof(emu->x)-1] = '\0';
|
||||
#define IN_array(x, n) \
|
||||
for(__i = 0; __i < n; __i++) \
|
||||
emu->x[__i] = eq->x[__i];
|
||||
|
||||
//call before any premature returns in an encoder using SETUP_DIRECT_DECODE
|
||||
#define FAIL_DIRECT_DECODE() \
|
||||
|
||||
910
common/races.cpp
910
common/races.cpp
@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemu.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -18,95 +18,831 @@
|
||||
|
||||
#include "../common/races.h"
|
||||
|
||||
const char* GetRaceName(uint16 race) {
|
||||
switch(race) {
|
||||
case HUMAN:
|
||||
return "Human";
|
||||
case BARBARIAN:
|
||||
return "Barbarian";
|
||||
case ERUDITE:
|
||||
return "Erudite";
|
||||
case WOOD_ELF:
|
||||
return "Wood Elf";
|
||||
case HIGH_ELF:
|
||||
return "High Elf";
|
||||
case DARK_ELF:
|
||||
return "Dark Elf";
|
||||
case HALF_ELF:
|
||||
return "Half Elf";
|
||||
case DWARF:
|
||||
return "Dwarf";
|
||||
case TROLL:
|
||||
return "Troll";
|
||||
case OGRE:
|
||||
return "Ogre";
|
||||
case HALFLING:
|
||||
return "Halfling";
|
||||
case GNOME:
|
||||
return "Gnome";
|
||||
case IKSAR:
|
||||
return "Iksar";
|
||||
case WEREWOLF:
|
||||
return "Werewolf";
|
||||
case SKELETON:
|
||||
return "Skeleton";
|
||||
case ELEMENTAL:
|
||||
return "Elemental";
|
||||
case EYE_OF_ZOMM:
|
||||
return "Eye of Zomm";
|
||||
case WOLF_ELEMENTAL:
|
||||
return "Wolf Elemental";
|
||||
case IKSAR_SKELETON:
|
||||
return "Iksar Skeleton";
|
||||
case VAHSHIR:
|
||||
return "Vah Shir";
|
||||
case FROGLOK:
|
||||
case FROGLOK2:
|
||||
return "Froglok";
|
||||
case DRAKKIN:
|
||||
return "Drakkin";
|
||||
default:
|
||||
return "Unknown";
|
||||
const char* GetRaceIDName(uint16 race_id)
|
||||
{
|
||||
switch (race_id) {
|
||||
case HUMAN:
|
||||
return "Human";
|
||||
case BARBARIAN:
|
||||
return "Barbarian";
|
||||
case ERUDITE:
|
||||
return "Erudite";
|
||||
case WOOD_ELF:
|
||||
return "Wood Elf";
|
||||
case HIGH_ELF:
|
||||
return "High Elf";
|
||||
case DARK_ELF:
|
||||
return "Dark Elf";
|
||||
case HALF_ELF:
|
||||
return "Half Elf";
|
||||
case DWARF:
|
||||
return "Dwarf";
|
||||
case TROLL:
|
||||
return "Troll";
|
||||
case OGRE:
|
||||
return "Ogre";
|
||||
case HALFLING:
|
||||
return "Halfling";
|
||||
case GNOME:
|
||||
return "Gnome";
|
||||
case IKSAR:
|
||||
return "Iksar";
|
||||
case WEREWOLF:
|
||||
return "Werewolf";
|
||||
case SKELETON:
|
||||
return "Skeleton";
|
||||
case ELEMENTAL:
|
||||
return "Elemental";
|
||||
case EYE_OF_ZOMM:
|
||||
return "Eye of Zomm";
|
||||
case WOLF_ELEMENTAL:
|
||||
return "Wolf Elemental";
|
||||
case IKSAR_SKELETON:
|
||||
return "Iksar Skeleton";
|
||||
case VAHSHIR:
|
||||
return "Vah Shir";
|
||||
case FROGLOK:
|
||||
case FROGLOK2:
|
||||
return "Froglok";
|
||||
case DRAKKIN:
|
||||
return "Drakkin";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
uint32 GetArrayRace(uint16 race) {
|
||||
switch(race) {
|
||||
case HUMAN:
|
||||
return Array_Race_HUMAN;
|
||||
case BARBARIAN:
|
||||
return Array_Race_BARBARIAN;
|
||||
case ERUDITE:
|
||||
return Array_Race_ERUDITE;
|
||||
case WOOD_ELF:
|
||||
return Array_Race_WOOD_ELF;
|
||||
case HIGH_ELF:
|
||||
return Array_Race_HIGH_ELF;
|
||||
case DARK_ELF:
|
||||
return Array_Race_DARK_ELF;
|
||||
case HALF_ELF:
|
||||
return Array_Race_HALF_ELF;
|
||||
case DWARF:
|
||||
return Array_Race_DWARF;
|
||||
case TROLL:
|
||||
return Array_Race_TROLL;
|
||||
case OGRE:
|
||||
return Array_Race_OGRE;
|
||||
case HALFLING:
|
||||
return Array_Race_HALFLING;
|
||||
case GNOME:
|
||||
return Array_Race_GNOME;
|
||||
case IKSAR:
|
||||
return Array_Race_IKSAR;
|
||||
case VAHSHIR:
|
||||
return Array_Race_VAHSHIR;
|
||||
case FROGLOK:
|
||||
case FROGLOK2:
|
||||
return Array_Race_FROGLOK;
|
||||
case DRAKKIN:
|
||||
return Array_Race_DRAKKIN;
|
||||
default:
|
||||
return Array_Race_UNKNOWN;
|
||||
const char* GetPlayerRaceName(uint32 player_race_value)
|
||||
{
|
||||
return GetRaceIDName(GetRaceIDFromPlayerRaceValue(player_race_value));
|
||||
}
|
||||
|
||||
uint32 GetPlayerRaceValue(uint16 race_id)
|
||||
{
|
||||
switch (race_id) {
|
||||
case HUMAN:
|
||||
case BARBARIAN:
|
||||
case ERUDITE:
|
||||
case WOOD_ELF:
|
||||
case HIGH_ELF:
|
||||
case DARK_ELF:
|
||||
case HALF_ELF:
|
||||
case DWARF:
|
||||
case TROLL:
|
||||
case OGRE:
|
||||
case HALFLING:
|
||||
case GNOME:
|
||||
return race_id;
|
||||
case IKSAR:
|
||||
return PLAYER_RACE_IKSAR;
|
||||
case VAHSHIR:
|
||||
return PLAYER_RACE_VAHSHIR;
|
||||
case FROGLOK:
|
||||
case FROGLOK2:
|
||||
return PLAYER_RACE_FROGLOK;
|
||||
case DRAKKIN:
|
||||
return PLAYER_RACE_DRAKKIN;
|
||||
default:
|
||||
return PLAYER_RACE_UNKNOWN; // watch
|
||||
}
|
||||
}
|
||||
|
||||
uint32 GetPlayerRaceBit(uint16 race_id)
|
||||
{
|
||||
switch (race_id) {
|
||||
case HUMAN:
|
||||
return PLAYER_RACE_HUMAN_BIT;
|
||||
case BARBARIAN:
|
||||
return PLAYER_RACE_BARBARIAN_BIT;
|
||||
case ERUDITE:
|
||||
return PLAYER_RACE_ERUDITE_BIT;
|
||||
case WOOD_ELF:
|
||||
return PLAYER_RACE_WOOD_ELF_BIT;
|
||||
case HIGH_ELF:
|
||||
return PLAYER_RACE_HIGH_ELF_BIT;
|
||||
case DARK_ELF:
|
||||
return PLAYER_RACE_DARK_ELF_BIT;
|
||||
case HALF_ELF:
|
||||
return PLAYER_RACE_HALF_ELF_BIT;
|
||||
case DWARF:
|
||||
return PLAYER_RACE_DWARF_BIT;
|
||||
case TROLL:
|
||||
return PLAYER_RACE_TROLL_BIT;
|
||||
case OGRE:
|
||||
return PLAYER_RACE_OGRE_BIT;
|
||||
case HALFLING:
|
||||
return PLAYER_RACE_HALFLING_BIT;
|
||||
case GNOME:
|
||||
return PLAYER_RACE_GNOME_BIT;
|
||||
case IKSAR:
|
||||
return PLAYER_RACE_IKSAR_BIT;
|
||||
case VAHSHIR:
|
||||
return PLAYER_RACE_VAHSHIR_BIT;
|
||||
case FROGLOK:
|
||||
return PLAYER_RACE_FROGLOK_BIT;
|
||||
case DRAKKIN:
|
||||
return PLAYER_RACE_DRAKKIN_BIT;
|
||||
default:
|
||||
return PLAYER_RACE_UNKNOWN_BIT;
|
||||
}
|
||||
}
|
||||
|
||||
uint16 GetRaceIDFromPlayerRaceValue(uint32 player_race_value)
|
||||
{
|
||||
switch (player_race_value) {
|
||||
case PLAYER_RACE_HUMAN:
|
||||
case PLAYER_RACE_BARBARIAN:
|
||||
case PLAYER_RACE_ERUDITE:
|
||||
case PLAYER_RACE_WOOD_ELF:
|
||||
case PLAYER_RACE_HIGH_ELF:
|
||||
case PLAYER_RACE_DARK_ELF:
|
||||
case PLAYER_RACE_HALF_ELF:
|
||||
case PLAYER_RACE_DWARF:
|
||||
case PLAYER_RACE_TROLL:
|
||||
case PLAYER_RACE_OGRE:
|
||||
case PLAYER_RACE_HALFLING:
|
||||
case PLAYER_RACE_GNOME:
|
||||
return player_race_value;
|
||||
case PLAYER_RACE_IKSAR:
|
||||
return IKSAR;
|
||||
case PLAYER_RACE_VAHSHIR:
|
||||
return VAHSHIR;
|
||||
case PLAYER_RACE_FROGLOK:
|
||||
return FROGLOK;
|
||||
case PLAYER_RACE_DRAKKIN:
|
||||
return DRAKKIN;
|
||||
default:
|
||||
return PLAYER_RACE_UNKNOWN; // watch
|
||||
}
|
||||
}
|
||||
|
||||
uint16 GetRaceIDFromPlayerRaceBit(uint32 player_race_bit)
|
||||
{
|
||||
switch (player_race_bit) {
|
||||
case PLAYER_RACE_HUMAN_BIT:
|
||||
return HUMAN;
|
||||
case PLAYER_RACE_BARBARIAN_BIT:
|
||||
return BARBARIAN;
|
||||
case PLAYER_RACE_ERUDITE_BIT:
|
||||
return ERUDITE;
|
||||
case PLAYER_RACE_WOOD_ELF_BIT:
|
||||
return WOOD_ELF;
|
||||
case PLAYER_RACE_HIGH_ELF_BIT:
|
||||
return HIGH_ELF;
|
||||
case PLAYER_RACE_DARK_ELF_BIT:
|
||||
return DARK_ELF;
|
||||
case PLAYER_RACE_HALF_ELF_BIT:
|
||||
return HALF_ELF;
|
||||
case PLAYER_RACE_DWARF_BIT:
|
||||
return DWARF;
|
||||
case PLAYER_RACE_TROLL_BIT:
|
||||
return TROLL;
|
||||
case PLAYER_RACE_OGRE_BIT:
|
||||
return OGRE;
|
||||
case PLAYER_RACE_HALFLING_BIT:
|
||||
return HALFLING;
|
||||
case PLAYER_RACE_GNOME_BIT:
|
||||
return GNOME;
|
||||
case PLAYER_RACE_IKSAR_BIT:
|
||||
return IKSAR;
|
||||
case PLAYER_RACE_VAHSHIR_BIT:
|
||||
return VAHSHIR;
|
||||
case PLAYER_RACE_FROGLOK_BIT:
|
||||
return FROGLOK;
|
||||
case PLAYER_RACE_DRAKKIN_BIT:
|
||||
return DRAKKIN;
|
||||
default:
|
||||
return PLAYER_RACE_UNKNOWN; // watch
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// PlayerAppearance prep
|
||||
#define HUMAN_MALE ((HUMAN << 8) | MALE)
|
||||
#define HUMAN_FEMALE ((HUMAN << 8) | FEMALE)
|
||||
#define BARBARIAN_MALE ((BARBARIAN << 8) | MALE)
|
||||
#define BARBARIAN_FEMALE ((BARBARIAN << 8) | FEMALE)
|
||||
#define ERUDITE_MALE ((ERUDITE << 8) | MALE)
|
||||
#define ERUDITE_FEMALE ((ERUDITE << 8) | FEMALE)
|
||||
#define WOOD_ELF_MALE ((WOOD_ELF << 8) | MALE)
|
||||
#define WOOD_ELF_FEMALE ((WOOD_ELF << 8) | FEMALE)
|
||||
#define HIGH_ELF_MALE ((HIGH_ELF << 8) | MALE)
|
||||
#define HIGH_ELF_FEMALE ((HIGH_ELF << 8) | FEMALE)
|
||||
#define DARK_ELF_MALE ((DARK_ELF << 8) | MALE)
|
||||
#define DARK_ELF_FEMALE ((DARK_ELF << 8) | FEMALE)
|
||||
#define HALF_ELF_MALE ((HALF_ELF << 8) | MALE)
|
||||
#define HALF_ELF_FEMALE ((HALF_ELF << 8) | FEMALE)
|
||||
#define DWARF_MALE ((DWARF << 8) | MALE)
|
||||
#define DWARF_FEMALE ((DWARF << 8) | FEMALE)
|
||||
#define TROLL_MALE ((TROLL << 8) | MALE)
|
||||
#define TROLL_FEMALE ((TROLL << 8) | FEMALE)
|
||||
#define OGRE_MALE ((OGRE << 8) | MALE)
|
||||
#define OGRE_FEMALE ((OGRE << 8) | FEMALE)
|
||||
#define HALFLING_MALE ((HALFLING << 8) | MALE)
|
||||
#define HALFLING_FEMALE ((HALFLING << 8) | FEMALE)
|
||||
#define GNOME_MALE ((GNOME << 8) | MALE)
|
||||
#define GNOME_FEMALE ((GNOME << 8) | FEMALE)
|
||||
#define IKSAR_MALE ((IKSAR << 8) | MALE)
|
||||
#define IKSAR_FEMALE ((IKSAR << 8) | FEMALE)
|
||||
#define VAHSHIR_MALE ((VAHSHIR << 8) | MALE)
|
||||
#define VAHSHIR_FEMALE ((VAHSHIR << 8) | FEMALE)
|
||||
#define FROGLOK_MALE ((FROGLOK << 8) | MALE)
|
||||
#define FROGLOK_FEMALE ((FROGLOK << 8) | FEMALE)
|
||||
#define DRAKKIN_MALE ((DRAKKIN << 8) | MALE)
|
||||
#define DRAKKIN_FEMALE ((DRAKKIN << 8) | FEMALE)
|
||||
|
||||
#define BINDRG(r, g) (((int)r << 8) | g)
|
||||
|
||||
|
||||
bool PlayerAppearance::IsValidBeard(uint16 race_id, uint8 gender_id, uint8 beard_value, bool use_luclin)
|
||||
{
|
||||
if (beard_value == 0xFF)
|
||||
return true;
|
||||
|
||||
if (use_luclin) {
|
||||
switch (BINDRG(race_id, gender_id)) {
|
||||
case DWARF_FEMALE:
|
||||
if (beard_value <= 1)
|
||||
return true;
|
||||
break;
|
||||
case HIGH_ELF_MALE:
|
||||
case DARK_ELF_MALE:
|
||||
case HALF_ELF_MALE:
|
||||
case DRAKKIN_FEMALE:
|
||||
if (beard_value <= 3)
|
||||
return true;
|
||||
break;
|
||||
case HUMAN_MALE:
|
||||
case BARBARIAN_MALE:
|
||||
case ERUDITE_MALE:
|
||||
case DWARF_MALE:
|
||||
case HALFLING_MALE:
|
||||
case GNOME_MALE:
|
||||
if (beard_value <= 5)
|
||||
return true;
|
||||
break;
|
||||
case DRAKKIN_MALE:
|
||||
if (beard_value <= 11)
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
switch (BINDRG(race_id, gender_id)) {
|
||||
case DRAKKIN_FEMALE:
|
||||
if (beard_value <= 3)
|
||||
return true;
|
||||
break;
|
||||
case DRAKKIN_MALE:
|
||||
if (beard_value <= 11)
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool PlayerAppearance::IsValidBeardColor(uint16 race_id, uint8 gender_id, uint8 beard_color_value, bool use_luclin)
|
||||
{
|
||||
if (beard_color_value == 0xFF)
|
||||
return true;
|
||||
|
||||
switch (BINDRG(race_id, gender_id)) {
|
||||
case GNOME_MALE:
|
||||
if (beard_color_value <= 24)
|
||||
return true;
|
||||
break;
|
||||
case HUMAN_MALE:
|
||||
case BARBARIAN_MALE:
|
||||
case ERUDITE_MALE:
|
||||
case HALF_ELF_MALE:
|
||||
case DWARF_MALE:
|
||||
case DWARF_FEMALE:
|
||||
case HALFLING_MALE:
|
||||
if (beard_color_value <= 19)
|
||||
return true;
|
||||
break;
|
||||
case DARK_ELF_MALE:
|
||||
if (beard_color_value >= 13 && beard_color_value <= 18)
|
||||
return true;
|
||||
break;
|
||||
case HIGH_ELF_MALE:
|
||||
if (beard_color_value <= 14)
|
||||
return true;
|
||||
break;
|
||||
case FROGLOK_MALE:
|
||||
case FROGLOK_FEMALE:
|
||||
case DRAKKIN_MALE:
|
||||
case DRAKKIN_FEMALE:
|
||||
if (beard_color_value <= 3)
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PlayerAppearance::IsValidDetail(uint16 race_id, uint8 gender_id, uint32 detail_value, bool use_luclin)
|
||||
{
|
||||
if (detail_value == 0xFFFFFFFF)
|
||||
return true;
|
||||
|
||||
switch (BINDRG(race_id, gender_id)) {
|
||||
case DRAKKIN_MALE:
|
||||
case DRAKKIN_FEMALE:
|
||||
if (detail_value <= 7)
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PlayerAppearance::IsValidEyeColor(uint16 race_id, uint8 gender_id, uint8 eye_color_value, bool use_luclin)
|
||||
{
|
||||
return true; // need valid criteria
|
||||
|
||||
switch (BINDRG(race_id, gender_id)) {
|
||||
case HUMAN_MALE:
|
||||
case HUMAN_FEMALE:
|
||||
case BARBARIAN_MALE:
|
||||
case BARBARIAN_FEMALE:
|
||||
case ERUDITE_MALE:
|
||||
case ERUDITE_FEMALE:
|
||||
case WOOD_ELF_MALE:
|
||||
case WOOD_ELF_FEMALE:
|
||||
case HIGH_ELF_MALE:
|
||||
case HIGH_ELF_FEMALE:
|
||||
case DARK_ELF_MALE:
|
||||
case DARK_ELF_FEMALE:
|
||||
case HALF_ELF_MALE:
|
||||
case HALF_ELF_FEMALE:
|
||||
case DWARF_MALE:
|
||||
case DWARF_FEMALE:
|
||||
case OGRE_MALE:
|
||||
case OGRE_FEMALE:
|
||||
case HALFLING_MALE:
|
||||
case HALFLING_FEMALE:
|
||||
case GNOME_MALE:
|
||||
case GNOME_FEMALE:
|
||||
case IKSAR_MALE:
|
||||
case IKSAR_FEMALE:
|
||||
case VAHSHIR_MALE:
|
||||
case VAHSHIR_FEMALE:
|
||||
if (eye_color_value <= 9)
|
||||
return true;
|
||||
break;
|
||||
case TROLL_MALE:
|
||||
case TROLL_FEMALE:
|
||||
if (eye_color_value <= 10)
|
||||
return true;
|
||||
break;
|
||||
case FROGLOK_MALE:
|
||||
case FROGLOK_FEMALE:
|
||||
case DRAKKIN_MALE:
|
||||
case DRAKKIN_FEMALE:
|
||||
if (eye_color_value <= 11)
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PlayerAppearance::IsValidFace(uint16 race_id, uint8 gender_id, uint8 face_value, bool use_luclin)
|
||||
{
|
||||
if (face_value == 0xFF)
|
||||
return true;
|
||||
|
||||
switch (BINDRG(race_id, gender_id)) {
|
||||
case DRAKKIN_MALE:
|
||||
case DRAKKIN_FEMALE:
|
||||
if (face_value <= 6)
|
||||
return true;
|
||||
break;
|
||||
case HUMAN_MALE:
|
||||
case HUMAN_FEMALE:
|
||||
case BARBARIAN_MALE:
|
||||
case BARBARIAN_FEMALE:
|
||||
case ERUDITE_MALE:
|
||||
case ERUDITE_FEMALE:
|
||||
case WOOD_ELF_MALE:
|
||||
case WOOD_ELF_FEMALE:
|
||||
case HIGH_ELF_MALE:
|
||||
case HIGH_ELF_FEMALE:
|
||||
case DARK_ELF_MALE:
|
||||
case DARK_ELF_FEMALE:
|
||||
case HALF_ELF_MALE:
|
||||
case HALF_ELF_FEMALE:
|
||||
case DWARF_MALE:
|
||||
case DWARF_FEMALE:
|
||||
case TROLL_MALE:
|
||||
case TROLL_FEMALE:
|
||||
case OGRE_MALE:
|
||||
case OGRE_FEMALE:
|
||||
case HALFLING_MALE:
|
||||
case HALFLING_FEMALE:
|
||||
case GNOME_MALE:
|
||||
case GNOME_FEMALE:
|
||||
case IKSAR_MALE:
|
||||
case IKSAR_FEMALE:
|
||||
case VAHSHIR_MALE:
|
||||
case VAHSHIR_FEMALE:
|
||||
if (face_value <= 7)
|
||||
return true;
|
||||
break;
|
||||
case FROGLOK_MALE:
|
||||
case FROGLOK_FEMALE:
|
||||
if (face_value <= 9)
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PlayerAppearance::IsValidHair(uint16 race_id, uint8 gender_id, uint8 hair_value, bool use_luclin)
|
||||
{
|
||||
if (hair_value == 0xFF)
|
||||
return true;
|
||||
|
||||
if (use_luclin) {
|
||||
switch (BINDRG(race_id, gender_id)) {
|
||||
case HUMAN_MALE:
|
||||
case HUMAN_FEMALE:
|
||||
case BARBARIAN_MALE:
|
||||
case BARBARIAN_FEMALE:
|
||||
case WOOD_ELF_MALE:
|
||||
case WOOD_ELF_FEMALE:
|
||||
case HIGH_ELF_MALE:
|
||||
case HIGH_ELF_FEMALE:
|
||||
case DARK_ELF_MALE:
|
||||
case DARK_ELF_FEMALE:
|
||||
case HALF_ELF_MALE:
|
||||
case HALF_ELF_FEMALE:
|
||||
case DWARF_MALE:
|
||||
case DWARF_FEMALE:
|
||||
case TROLL_FEMALE:
|
||||
case OGRE_FEMALE:
|
||||
case HALFLING_MALE:
|
||||
case HALFLING_FEMALE:
|
||||
case GNOME_MALE:
|
||||
case GNOME_FEMALE:
|
||||
if (hair_value <= 3)
|
||||
return true;
|
||||
break;
|
||||
case ERUDITE_MALE:
|
||||
if (hair_value <= 5)
|
||||
return true;
|
||||
break;
|
||||
case DRAKKIN_FEMALE:
|
||||
if (hair_value <= 7)
|
||||
return true;
|
||||
break;
|
||||
case ERUDITE_FEMALE:
|
||||
case DRAKKIN_MALE:
|
||||
if (hair_value <= 8)
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
switch (BINDRG(race_id, gender_id)) {
|
||||
case DRAKKIN_FEMALE:
|
||||
if (hair_value <= 7)
|
||||
return true;
|
||||
break;
|
||||
case DRAKKIN_MALE:
|
||||
if (hair_value <= 8)
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool PlayerAppearance::IsValidHairColor(uint16 race_id, uint8 gender_id, uint8 hair_color_value, bool use_luclin)
|
||||
{
|
||||
if (hair_color_value == 0xFF)
|
||||
return true;
|
||||
|
||||
switch (BINDRG(race_id, gender_id)) {
|
||||
case GNOME_MALE:
|
||||
case GNOME_FEMALE:
|
||||
if (hair_color_value <= 24)
|
||||
return true;
|
||||
break;
|
||||
case TROLL_FEMALE:
|
||||
case OGRE_FEMALE:
|
||||
if (hair_color_value <= 23)
|
||||
return true;
|
||||
break;
|
||||
case HUMAN_MALE:
|
||||
case HUMAN_FEMALE:
|
||||
case BARBARIAN_MALE:
|
||||
case BARBARIAN_FEMALE:
|
||||
case WOOD_ELF_MALE:
|
||||
case WOOD_ELF_FEMALE:
|
||||
case HALF_ELF_MALE:
|
||||
case HALF_ELF_FEMALE:
|
||||
case DWARF_MALE:
|
||||
case DWARF_FEMALE:
|
||||
case HALFLING_MALE:
|
||||
case HALFLING_FEMALE:
|
||||
if (hair_color_value <= 19)
|
||||
return true;
|
||||
break;
|
||||
case DARK_ELF_MALE:
|
||||
case DARK_ELF_FEMALE:
|
||||
if (hair_color_value >= 13 && hair_color_value <= 18)
|
||||
return true;
|
||||
break;
|
||||
case HIGH_ELF_MALE:
|
||||
case HIGH_ELF_FEMALE:
|
||||
if (hair_color_value <= 14)
|
||||
return true;
|
||||
break;
|
||||
case FROGLOK_MALE:
|
||||
case FROGLOK_FEMALE:
|
||||
case DRAKKIN_MALE:
|
||||
case DRAKKIN_FEMALE:
|
||||
if (hair_color_value <= 3)
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PlayerAppearance::IsValidHead(uint16 race_id, uint8 gender_id, uint8 head_value, bool use_luclin)
|
||||
{
|
||||
if (head_value == 0xFF)
|
||||
return true;
|
||||
|
||||
if (use_luclin) {
|
||||
switch (BINDRG(race_id, gender_id)) {
|
||||
case HUMAN_MALE:
|
||||
case HUMAN_FEMALE:
|
||||
case BARBARIAN_MALE:
|
||||
case BARBARIAN_FEMALE:
|
||||
case WOOD_ELF_MALE:
|
||||
case WOOD_ELF_FEMALE:
|
||||
case HIGH_ELF_MALE:
|
||||
case HIGH_ELF_FEMALE:
|
||||
case DARK_ELF_MALE:
|
||||
case DARK_ELF_FEMALE:
|
||||
case HALF_ELF_MALE:
|
||||
case HALF_ELF_FEMALE:
|
||||
case DWARF_MALE:
|
||||
case DWARF_FEMALE:
|
||||
case TROLL_MALE:
|
||||
case TROLL_FEMALE:
|
||||
case OGRE_MALE:
|
||||
case OGRE_FEMALE:
|
||||
case HALFLING_MALE:
|
||||
case HALFLING_FEMALE:
|
||||
case GNOME_MALE:
|
||||
case GNOME_FEMALE:
|
||||
case IKSAR_MALE:
|
||||
case IKSAR_FEMALE:
|
||||
case VAHSHIR_MALE:
|
||||
case VAHSHIR_FEMALE:
|
||||
case FROGLOK_MALE:
|
||||
case FROGLOK_FEMALE:
|
||||
case DRAKKIN_MALE:
|
||||
case DRAKKIN_FEMALE:
|
||||
if (head_value <= 3)
|
||||
return true;
|
||||
break;
|
||||
case ERUDITE_MALE:
|
||||
case ERUDITE_FEMALE:
|
||||
if (head_value <= 4)
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
switch (BINDRG(race_id, gender_id)) {
|
||||
case HUMAN_MALE:
|
||||
case HUMAN_FEMALE:
|
||||
case BARBARIAN_MALE:
|
||||
case BARBARIAN_FEMALE:
|
||||
case ERUDITE_MALE:
|
||||
case ERUDITE_FEMALE:
|
||||
case WOOD_ELF_MALE:
|
||||
case WOOD_ELF_FEMALE:
|
||||
case HIGH_ELF_MALE:
|
||||
case HIGH_ELF_FEMALE:
|
||||
case DARK_ELF_MALE:
|
||||
case DARK_ELF_FEMALE:
|
||||
case HALF_ELF_MALE:
|
||||
case HALF_ELF_FEMALE:
|
||||
case DWARF_MALE:
|
||||
case DWARF_FEMALE:
|
||||
case TROLL_MALE:
|
||||
case TROLL_FEMALE:
|
||||
case OGRE_MALE:
|
||||
case OGRE_FEMALE:
|
||||
case HALFLING_MALE:
|
||||
case HALFLING_FEMALE:
|
||||
case IKSAR_MALE:
|
||||
case IKSAR_FEMALE:
|
||||
case VAHSHIR_MALE:
|
||||
case VAHSHIR_FEMALE:
|
||||
case FROGLOK_MALE:
|
||||
case FROGLOK_FEMALE:
|
||||
case DRAKKIN_MALE:
|
||||
case DRAKKIN_FEMALE:
|
||||
if (head_value <= 3)
|
||||
return true;
|
||||
break;
|
||||
case GNOME_MALE:
|
||||
case GNOME_FEMALE:
|
||||
if (head_value <= 4)
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool PlayerAppearance::IsValidHeritage(uint16 race_id, uint8 gender_id, uint32 heritage_value, bool use_luclin)
|
||||
{
|
||||
if (heritage_value == 0xFFFFFFFF)
|
||||
return true;
|
||||
|
||||
switch (BINDRG(race_id, gender_id)) {
|
||||
case DRAKKIN_MALE:
|
||||
case DRAKKIN_FEMALE:
|
||||
if (heritage_value <= 7) // > 5 seems to jumble other features..else, some heritages have 'specialized' features
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PlayerAppearance::IsValidTattoo(uint16 race_id, uint8 gender_id, uint32 tattoo_value, bool use_luclin)
|
||||
{
|
||||
if (tattoo_value == 0xFFFFFFFF)
|
||||
return true;
|
||||
|
||||
switch (BINDRG(race_id, gender_id)) {
|
||||
case DRAKKIN_MALE:
|
||||
case DRAKKIN_FEMALE:
|
||||
if (tattoo_value <= 7)
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PlayerAppearance::IsValidTexture(uint16 race_id, uint8 gender_id, uint8 texture_value, bool use_luclin)
|
||||
{
|
||||
if (texture_value == 0xFF)
|
||||
return true;
|
||||
|
||||
if (use_luclin) {
|
||||
switch (BINDRG(race_id, gender_id)) {
|
||||
case HUMAN_MALE:
|
||||
case HUMAN_FEMALE:
|
||||
case IKSAR_MALE:
|
||||
case IKSAR_FEMALE:
|
||||
case DRAKKIN_MALE:
|
||||
case DRAKKIN_FEMALE:
|
||||
if ((texture_value >= 10 && texture_value <= 16) || texture_value <= 4)
|
||||
return true;
|
||||
break;
|
||||
case ERUDITE_MALE:
|
||||
case ERUDITE_FEMALE:
|
||||
case HIGH_ELF_MALE:
|
||||
case HIGH_ELF_FEMALE:
|
||||
case DARK_ELF_MALE:
|
||||
case DARK_ELF_FEMALE:
|
||||
case GNOME_MALE:
|
||||
case GNOME_FEMALE:
|
||||
case FROGLOK_MALE:
|
||||
case FROGLOK_FEMALE:
|
||||
if ((texture_value >= 10 && texture_value <= 16) || texture_value <= 3)
|
||||
return true;
|
||||
break;
|
||||
case BARBARIAN_MALE:
|
||||
case BARBARIAN_FEMALE:
|
||||
case WOOD_ELF_MALE:
|
||||
case WOOD_ELF_FEMALE:
|
||||
case HALF_ELF_MALE:
|
||||
case HALF_ELF_FEMALE:
|
||||
case DWARF_MALE:
|
||||
case DWARF_FEMALE:
|
||||
case TROLL_MALE:
|
||||
case TROLL_FEMALE:
|
||||
case OGRE_MALE:
|
||||
case OGRE_FEMALE:
|
||||
case HALFLING_MALE:
|
||||
case HALFLING_FEMALE:
|
||||
case VAHSHIR_MALE:
|
||||
case VAHSHIR_FEMALE:
|
||||
if (texture_value <= 3)
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
switch (BINDRG(race_id, gender_id)) {
|
||||
case HUMAN_MALE:
|
||||
case HUMAN_FEMALE:
|
||||
case ERUDITE_MALE:
|
||||
case ERUDITE_FEMALE:
|
||||
case DRAKKIN_MALE:
|
||||
case DRAKKIN_FEMALE:
|
||||
if ((texture_value >= 10 && texture_value <= 16) || texture_value <= 4)
|
||||
return true;
|
||||
break;
|
||||
case HIGH_ELF_MALE:
|
||||
case HIGH_ELF_FEMALE:
|
||||
case DARK_ELF_MALE:
|
||||
case DARK_ELF_FEMALE:
|
||||
case GNOME_MALE:
|
||||
case GNOME_FEMALE:
|
||||
case FROGLOK_MALE:
|
||||
case FROGLOK_FEMALE:
|
||||
if ((texture_value >= 10 && texture_value <= 16) || texture_value <= 3)
|
||||
return true;
|
||||
break;
|
||||
case VAHSHIR_MALE:
|
||||
case VAHSHIR_FEMALE:
|
||||
if (texture_value == 50 || texture_value <= 3)
|
||||
return true;
|
||||
break;
|
||||
case IKSAR_MALE:
|
||||
case IKSAR_FEMALE:
|
||||
if (texture_value == 10 || texture_value <= 4)
|
||||
return true;
|
||||
break;
|
||||
case BARBARIAN_MALE:
|
||||
case BARBARIAN_FEMALE:
|
||||
case WOOD_ELF_MALE:
|
||||
case WOOD_ELF_FEMALE:
|
||||
case HALF_ELF_MALE:
|
||||
case HALF_ELF_FEMALE:
|
||||
case DWARF_MALE:
|
||||
case DWARF_FEMALE:
|
||||
case TROLL_MALE:
|
||||
case TROLL_FEMALE:
|
||||
case OGRE_MALE:
|
||||
case OGRE_FEMALE:
|
||||
case HALFLING_MALE:
|
||||
case HALFLING_FEMALE:
|
||||
if (texture_value <= 3)
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool PlayerAppearance::IsValidWoad(uint16 race_id, uint8 gender_id, uint8 woad_value, bool use_luclin)
|
||||
{
|
||||
if (woad_value == 0xFF)
|
||||
return true;
|
||||
|
||||
if (use_luclin) {
|
||||
switch (BINDRG(race_id, gender_id)) {
|
||||
case BARBARIAN_MALE:
|
||||
case BARBARIAN_FEMALE:
|
||||
if (woad_value <= 8)
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
186
common/races.h
186
common/races.h
@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemu.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -15,92 +15,130 @@
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef RACES_H
|
||||
#define RACES_H
|
||||
#include "../common/types.h"
|
||||
#include <cmath>
|
||||
|
||||
#define MALE 0
|
||||
#define FEMALE 1
|
||||
#define NEUTER 2
|
||||
|
||||
//theres a big list straight from the client below.
|
||||
|
||||
#define HUMAN 1
|
||||
#define BARBARIAN 2
|
||||
#define ERUDITE 3
|
||||
#define WOOD_ELF 4
|
||||
#define HIGH_ELF 5
|
||||
#define DARK_ELF 6
|
||||
#define HALF_ELF 7
|
||||
#define DWARF 8
|
||||
#define TROLL 9
|
||||
#define OGRE 10
|
||||
#define HALFLING 11
|
||||
#define GNOME 12
|
||||
#define WEREWOLF 14
|
||||
#define WOLF 42
|
||||
#define BEAR 43
|
||||
#define SKELETON 60
|
||||
#define TIGER 63
|
||||
#define ELEMENTAL 75
|
||||
#define ALLIGATOR 91
|
||||
#define EYE_OF_ZOMM 108
|
||||
#define WOLF_ELEMENTAL 120
|
||||
#define INVISIBLE_MAN 127
|
||||
#define IKSAR 128
|
||||
#define VAHSHIR 130
|
||||
#define HUMAN 1
|
||||
#define BARBARIAN 2
|
||||
#define ERUDITE 3
|
||||
#define WOOD_ELF 4
|
||||
#define HIGH_ELF 5
|
||||
#define DARK_ELF 6
|
||||
#define HALF_ELF 7
|
||||
#define DWARF 8
|
||||
#define TROLL 9
|
||||
#define OGRE 10
|
||||
#define HALFLING 11
|
||||
#define GNOME 12
|
||||
#define WEREWOLF 14
|
||||
#define WOLF 42
|
||||
#define BEAR 43
|
||||
#define SKELETON 60
|
||||
#define TIGER 63
|
||||
#define ELEMENTAL 75
|
||||
#define ALLIGATOR 91
|
||||
#define EYE_OF_ZOMM 108
|
||||
#define WOLF_ELEMENTAL 120
|
||||
#define INVISIBLE_MAN 127
|
||||
#define IKSAR 128
|
||||
#define VAHSHIR 130
|
||||
#define CONTROLLED_BOAT 141
|
||||
#define MINOR_ILL_OBJ 142
|
||||
#define TREE 143
|
||||
#define IKSAR_SKELETON 161
|
||||
#define FROGLOK 330
|
||||
#define FROGLOK2 74 // Not sure why /who all reports race as 74 for frogloks
|
||||
#define DRAKKIN 522 // 32768
|
||||
#define EMU_RACE_NPC 131069 // was 65533
|
||||
#define EMU_RACE_PET 131070 // was 65534
|
||||
#define MINOR_ILL_OBJ 142
|
||||
#define TREE 143
|
||||
#define IKSAR_SKELETON 161
|
||||
#define FROGLOK 330
|
||||
// TODO: check all clients for (BYTE) usage of '/who all' class and remove FROGLOK2, if possible (330 - 74 = 256 .. WORD->BYTE conversion loss...)
|
||||
#define FROGLOK2 74 // Not sure why /who all reports race as 74 for frogloks
|
||||
#define FAIRY 473
|
||||
#define DRAKKIN 522 // 32768
|
||||
#define EMU_RACE_NPC 131069 // was 65533
|
||||
#define EMU_RACE_PET 131070 // was 65534
|
||||
#define EMU_RACE_UNKNOWN 131071 // was 65535
|
||||
|
||||
|
||||
#define human_1 1
|
||||
#define barbarian_1 2
|
||||
#define erudite_1 4
|
||||
#define woodelf_1 8
|
||||
#define highelf_1 16
|
||||
#define darkelf_1 32
|
||||
#define halfelf_1 64
|
||||
#define dwarf_1 128
|
||||
#define troll_1 256
|
||||
#define ogre_1 512
|
||||
#define halfling_1 1024
|
||||
#define gnome_1 2048
|
||||
#define iksar_1 4096
|
||||
#define vahshir_1 8192
|
||||
#define rall_1 16384 //froglok?
|
||||
#define drakkin_1 32768
|
||||
// player race values
|
||||
#define PLAYER_RACE_UNKNOWN 0
|
||||
#define PLAYER_RACE_HUMAN 1
|
||||
#define PLAYER_RACE_BARBARIAN 2
|
||||
#define PLAYER_RACE_ERUDITE 3
|
||||
#define PLAYER_RACE_WOOD_ELF 4
|
||||
#define PLAYER_RACE_HIGH_ELF 5
|
||||
#define PLAYER_RACE_DARK_ELF 6
|
||||
#define PLAYER_RACE_HALF_ELF 7
|
||||
#define PLAYER_RACE_DWARF 8
|
||||
#define PLAYER_RACE_TROLL 9
|
||||
#define PLAYER_RACE_OGRE 10
|
||||
#define PLAYER_RACE_HALFLING 11
|
||||
#define PLAYER_RACE_GNOME 12
|
||||
#define PLAYER_RACE_IKSAR 13
|
||||
#define PLAYER_RACE_VAHSHIR 14
|
||||
#define PLAYER_RACE_FROGLOK 15
|
||||
#define PLAYER_RACE_DRAKKIN 16
|
||||
|
||||
const char* GetRaceName(uint16 race);
|
||||
#define PLAYER_RACE_COUNT 16
|
||||
|
||||
uint32 GetArrayRace(uint16 race);
|
||||
inline uint32 GetRaceBitmask(uint16 race) { return uint32(pow(2.0f, float(GetArrayRace(race) - 1))); }
|
||||
|
||||
#define Array_Race_UNKNOWN 0
|
||||
#define Array_Race_HUMAN 1
|
||||
#define Array_Race_BARBARIAN 2
|
||||
#define Array_Race_ERUDITE 3
|
||||
#define Array_Race_WOOD_ELF 4
|
||||
#define Array_Race_HIGH_ELF 5
|
||||
#define Array_Race_DARK_ELF 6
|
||||
#define Array_Race_HALF_ELF 7
|
||||
#define Array_Race_DWARF 8
|
||||
#define Array_Race_TROLL 9
|
||||
#define Array_Race_OGRE 10
|
||||
#define Array_Race_HALFLING 11
|
||||
#define Array_Race_GNOME 12
|
||||
#define Array_Race_IKSAR 13
|
||||
#define Array_Race_VAHSHIR 14
|
||||
#define Array_Race_FROGLOK 15
|
||||
#define Array_Race_DRAKKIN 16
|
||||
#define Array_Race_NPC 17
|
||||
#define Array_Race_PET 18
|
||||
#define Count_Array_Race 19 // used for array defines, must be the max + 1
|
||||
#define PLAYER_RACE_COUNT 16 // The count of all player races
|
||||
#define PLAYER_RACE_EMU_NPC 17
|
||||
#define PLAYER_RACE_EMU_PET 18
|
||||
#define PLAYER_RACE_EMU_COUNT 19
|
||||
|
||||
|
||||
// player race bits
|
||||
#define PLAYER_RACE_UNKNOWN_BIT 0
|
||||
#define PLAYER_RACE_HUMAN_BIT 1
|
||||
#define PLAYER_RACE_BARBARIAN_BIT 2
|
||||
#define PLAYER_RACE_ERUDITE_BIT 4
|
||||
#define PLAYER_RACE_WOOD_ELF_BIT 8
|
||||
#define PLAYER_RACE_HIGH_ELF_BIT 16
|
||||
#define PLAYER_RACE_DARK_ELF_BIT 32
|
||||
#define PLAYER_RACE_HALF_ELF_BIT 64
|
||||
#define PLAYER_RACE_DWARF_BIT 128
|
||||
#define PLAYER_RACE_TROLL_BIT 256
|
||||
#define PLAYER_RACE_OGRE_BIT 512
|
||||
#define PLAYER_RACE_HALFLING_BIT 1024
|
||||
#define PLAYER_RACE_GNOME_BIT 2048
|
||||
#define PLAYER_RACE_IKSAR_BIT 4096
|
||||
#define PLAYER_RACE_VAHSHIR_BIT 8192
|
||||
#define PLAYER_RACE_FROGLOK_BIT 16384
|
||||
#define PLAYER_RACE_DRAKKIN_BIT 32768
|
||||
|
||||
#define PLAYER_RACE_ALL_MASK 65535
|
||||
|
||||
|
||||
const char* GetRaceIDName(uint16 race_id);
|
||||
const char* GetPlayerRaceName(uint32 player_race_value);
|
||||
|
||||
uint32 GetPlayerRaceValue(uint16 race_id);
|
||||
uint32 GetPlayerRaceBit(uint16 race_id);
|
||||
|
||||
uint16 GetRaceIDFromPlayerRaceValue(uint32 player_race_value);
|
||||
uint16 GetRaceIDFromPlayerRaceBit(uint32 player_race_bit);
|
||||
|
||||
|
||||
// player race-/gender-based model feature validators
|
||||
namespace PlayerAppearance
|
||||
{
|
||||
bool IsValidBeard(uint16 race_id, uint8 gender_id, uint8 beard_value, bool use_luclin = true);
|
||||
bool IsValidBeardColor(uint16 race_id, uint8 gender_id, uint8 beard_color_value, bool use_luclin = true);
|
||||
bool IsValidDetail(uint16 race_id, uint8 gender_id, uint32 detail_value, bool use_luclin = true);
|
||||
bool IsValidEyeColor(uint16 race_id, uint8 gender_id, uint8 eye_color_value, bool use_luclin = true);
|
||||
bool IsValidFace(uint16 race_id, uint8 gender_id, uint8 face_value, bool use_luclin = true);
|
||||
bool IsValidHair(uint16 race_id, uint8 gender_id, uint8 hair_value, bool use_luclin = true);
|
||||
bool IsValidHairColor(uint16 race_id, uint8 gender_id, uint8 hair_color_value, bool use_luclin = true);
|
||||
bool IsValidHead(uint16 race_id, uint8 gender_id, uint8 head_value, bool use_luclin = true);
|
||||
bool IsValidHeritage(uint16 race_id, uint8 gender_id, uint32 heritage_value, bool use_luclin = true);
|
||||
bool IsValidTattoo(uint16 race_id, uint8 gender_id, uint32 tattoo_value, bool use_luclin = true);
|
||||
bool IsValidTexture(uint16 race_id, uint8 gender_id, uint8 texture_value, bool use_luclin = true);
|
||||
bool IsValidWoad(uint16 race_id, uint8 gender_id, uint8 woad_value, bool use_luclin = true);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
|
||||
@ -1,5 +1,20 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef RULE_CATEGORY
|
||||
#define RULE_CATEGORY(name)
|
||||
@ -516,10 +531,14 @@ RULE_CATEGORY_END()
|
||||
#ifdef BOTS
|
||||
RULE_CATEGORY(Bots)
|
||||
RULE_INT(Bots, AAExpansion, 8) // Bots get AAs through this expansion
|
||||
RULE_INT(Bots, CommandSpellRank, 1) // Filters bot command spells by rank (1, 2 and 3 are valid filters - any other number allows all ranks)
|
||||
RULE_INT(Bots, CreationLimit, 150) // Number of bots that each account can create
|
||||
RULE_BOOL(Bots, FinishBuffing, false) // Allow for buffs to complete even if the bot caster is out of mana. Only affects buffing out of combat.
|
||||
RULE_BOOL(Bots, GroupBuffing, false) // Bots will cast single target buffs as group buffs, default is false for single. Does not make single target buffs work for MGB.
|
||||
RULE_INT(Bots, HealRotationMaxMembers, 24) // Maximum number of heal rotation members
|
||||
RULE_INT(Bots, HealRotationMaxTargets, 12) // Maximum number of heal rotation targets
|
||||
RULE_REAL(Bots, ManaRegen, 2.0) // Adjust mana regen for bots, 1 is fast and higher numbers slow it down 3 is about the same as players.
|
||||
RULE_BOOL(Bots, PreferNoManaCommandSpells, true) // Give sorting priority to newer no-mana spells (i.e., 'Bind Affinity')
|
||||
RULE_BOOL(Bots, QuestableSpawnLimit, false) // Optional quest method to manage bot spawn limits using the quest_globals name bot_spawn_limit, see: /bazaar/Aediles_Thrall.pl
|
||||
RULE_BOOL(Bots, QuestableSpells, false) // Anita Thrall's (Anita_Thrall.pl) Bot Spell Scriber quests.
|
||||
RULE_INT(Bots, SpawnLimit, 71) // Number of bots a character can have spawned at one time, You + 71 bots is a 12 group raid
|
||||
|
||||
@ -1,3 +1,21 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
||||
@ -1647,6 +1665,7 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
|
||||
|
||||
sp[tempid].short_buff_box = atoi(row[154]);
|
||||
sp[tempid].descnum = atoi(row[155]);
|
||||
sp[tempid].typedescnum = atoi(row[156]);
|
||||
sp[tempid].effectdescnum = atoi(row[157]);
|
||||
|
||||
sp[tempid].npc_no_los = atoi(row[159]) != 0;
|
||||
@ -2025,22 +2044,3 @@ void SharedDatabase::SaveCharacterInspectMessage(uint32 character_id, const Insp
|
||||
std::string query = StringFormat("REPLACE INTO `character_inspect_messages` (id, inspect_message) VALUES (%u, '%s')", character_id, EscapeString(message->text).c_str());
|
||||
auto results = QueryDatabase(query);
|
||||
}
|
||||
|
||||
#ifdef BOTS
|
||||
void SharedDatabase::GetBotInspectMessage(uint32 bot_id, InspectMessage_Struct* message)
|
||||
{
|
||||
std::string query = StringFormat("SELECT `inspect_message` FROM `bot_inspect_messages` WHERE `bot_id` = %i LIMIT 1", bot_id);
|
||||
auto results = QueryDatabase(query);
|
||||
auto row = results.begin();
|
||||
memset(message, '\0', sizeof(InspectMessage_Struct));
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
memcpy(message, row[0], sizeof(InspectMessage_Struct));
|
||||
}
|
||||
}
|
||||
|
||||
void SharedDatabase::SetBotInspectMessage(uint32 bot_id, const InspectMessage_Struct* message)
|
||||
{
|
||||
std::string query = StringFormat("REPLACE INTO `bot_inspect_messages` (bot_id, inspect_message) VALUES (%u, '%s')", bot_id, EscapeString(message->text).c_str());
|
||||
auto results = QueryDatabase(query);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1,3 +1,21 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef SHAREDDB_H_
|
||||
#define SHAREDDB_H_
|
||||
|
||||
@ -126,11 +144,6 @@ class SharedDatabase : public Database
|
||||
void LoadBaseData(void *data, int max_level);
|
||||
const BaseDataStruct* GetBaseData(int lvl, int cl);
|
||||
|
||||
#ifdef BOTS
|
||||
void GetBotInspectMessage(uint32 botid, InspectMessage_Struct* message);
|
||||
void SetBotInspectMessage(uint32 botid, const InspectMessage_Struct* message);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
std::unique_ptr<EQEmu::MemoryMappedFile> skill_caps_mmf;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2005 EQEMu Development Team (http://eqemulator.net)
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -639,7 +639,7 @@ typedef enum {
|
||||
// number. note that the id field is counted as 0, this way the numbers
|
||||
// here match the numbers given to sep in the loading function net.cpp
|
||||
//
|
||||
#define SPELL_LOAD_FIELD_COUNT 231
|
||||
#define SPELL_LOAD_FIELD_COUNT 236
|
||||
|
||||
struct SPDat_Spell_Struct
|
||||
{
|
||||
@ -707,7 +707,7 @@ struct SPDat_Spell_Struct
|
||||
// 152 & 153: all set to 0
|
||||
/* 154 */ int8 short_buff_box; // != 0, goes to short buff box.
|
||||
/* 155 */ int descnum; // eqstr of description of spell
|
||||
/* 156 */ //int typedescnum; // eqstr of type description
|
||||
/* 156 */ int typedescnum; // eqstr of type description
|
||||
/* 157 */ int effectdescnum; // eqstr of effect description
|
||||
/* 158 */ //Category Desc ID 3
|
||||
/* 159 */ bool npc_no_los;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2013 EQEMu Development Team (http://eqemulator.net)
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -32,7 +32,7 @@
|
||||
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9096
|
||||
#ifdef BOTS
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9000
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9002
|
||||
#else
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 0 // must be 0
|
||||
#endif
|
||||
|
||||
@ -745,6 +745,7 @@ def discoverserverhandlers():
|
||||
locations['Zone'].append('/zone/aa.cpp')
|
||||
locations['Zone'].append('/zone/attack.cpp')
|
||||
locations['Zone'].append('/zone/bot.cpp')
|
||||
locations['Zone'].append('/zone/bot_command.cpp')
|
||||
locations['Zone'].append('/zone/client.cpp')
|
||||
locations['Zone'].append('/zone/client_packet.cpp')
|
||||
locations['Zone'].append('/zone/client_process.cpp')
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
9000|2015_09_30_bots.sql|SHOW TABLES LIKE 'bot_data'|empty|
|
||||
9001|2016_03_24_bots_command_settings.sql|SHOW TABLES LIKE 'bot_command_settings'|empty|
|
||||
9002|2016_03_24_bots_command_rules.sql|SELECT * FROM `rule_values` WHERE `rule_name` LIKE 'Bots:CommandSpellRank'|empty|
|
||||
|
||||
# Upgrade conditions:
|
||||
# This won't be needed after this system is implemented, but it is used database that are not
|
||||
|
||||
@ -0,0 +1,5 @@
|
||||
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES
|
||||
(1, 'Bots:CommandSpellRank', '1', 'Filters bot command spells by rank (1, 2 and 3 are valid filters - any other number allows all ranks)'),
|
||||
(1, 'Bots:HealRotationMaxMembers', '24', 'Maximum number of heal rotation members'),
|
||||
(1, 'Bots:HealRotationMaxTargets', '12', 'Maximum number of heal rotation targets'),
|
||||
(1, 'Bots:PreferNoManaCommandSpells', 'true', 'Give sorting priority to newer no-mana spells (i.e., \'Bind Affinity\')');
|
||||
102
utils/sql/git/bots/required/2016_03_24_bots_command_settings.sql
Normal file
102
utils/sql/git/bots/required/2016_03_24_bots_command_settings.sql
Normal file
@ -0,0 +1,102 @@
|
||||
CREATE TABLE `bot_command_settings` (
|
||||
`bot_command` varchar(128) NOT NULL DEFAULT '',
|
||||
`access` int(11) NOT NULL DEFAULT '0',
|
||||
`aliases` varchar(256) NOT NULL DEFAULT '',
|
||||
PRIMARY KEY (`bot_command`),
|
||||
UNIQUE KEY `UK_bot_command_settings_1` (`bot_command`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
|
||||
INSERT INTO `bot_command_settings` VALUES
|
||||
('actionable', 0, ''),
|
||||
('aggressive', 0, 'agg'),
|
||||
('attack', 0, 'atk'),
|
||||
('bindaffinity', 0, 'bind'),
|
||||
('bot', 0, 'b'),
|
||||
('botappearance', 0, 'app|appearance'),
|
||||
('botbeardcolor', 0, 'bc|beardcolor'),
|
||||
('botbeardstyle', 0, 'bs|beardstyle'),
|
||||
('botcamp', 0, 'camp'),
|
||||
('botclone', 200, 'clone'),
|
||||
('botcreate', 0, 'create'),
|
||||
('botdelete', 0, 'delete'),
|
||||
('botdetails', 0, 'details'),
|
||||
('botdyearmor', 0, 'dyearmor'),
|
||||
('boteyes', 0, 'eyes'),
|
||||
('botface', 0, 'face'),
|
||||
('botfollowdistance', 0, 'followd'),
|
||||
('botgroup', 0, 'bg'),
|
||||
('botgroupaddmember', 0, 'bgadd'),
|
||||
('botgroupcreate', 0, 'bgcreate'),
|
||||
('botgroupdelete', 0, 'bgdelete'),
|
||||
('botgrouplist', 0, 'bglist'),
|
||||
('botgroupload', 0, 'bgload'),
|
||||
('botgroupremovemember', 0, 'bgremove'),
|
||||
('bothaircolor', 0, 'hc|haircolor'),
|
||||
('bothairstyle', 0, 'hs|hairstyle'),
|
||||
('botheritage', 0, 'her|heritage'),
|
||||
('botinspectmessage', 0, 'inspect'),
|
||||
('botlist', 0, 'list'),
|
||||
('botoutofcombat', 0, 'ooc|outofcombat'),
|
||||
('botreport', 0, 'report|health|mana'),
|
||||
('botspawn', 0, 'spawn'),
|
||||
('botstance', 0, 'stance'),
|
||||
('botsummon', 0, 'summon'),
|
||||
('bottattoo', 0, 'tattoo'),
|
||||
('bottogglearcher', 0, 'archer|togglearcher'),
|
||||
('bottogglehelm', 0, 'helm|togglehelm'),
|
||||
('botupdate', 0, 'update'),
|
||||
('botwoad', 0, 'woad'),
|
||||
('charm', 0, ''),
|
||||
('circle', 0, 'cir'),
|
||||
('cure', 0, ''),
|
||||
('defensive', 0, 'def'),
|
||||
('depart', 0, 'dep'),
|
||||
('escape', 0, 'evac|succor'),
|
||||
('findaliases', 0, 'alias'),
|
||||
('follow', 0, ''),
|
||||
('guard', 0, ''),
|
||||
('healrotation', 0, 'hr'),
|
||||
('healrotationadaptivetargeting', 0, 'hradapt'),
|
||||
('healrotationaddmember', 0, 'hraddm'),
|
||||
('healrotationaddtarget', 0, 'hraddt'),
|
||||
('healrotationadjustcritical', 0, 'hrcrit'),
|
||||
('healrotationadjustsafe', 0, 'hrsafe'),
|
||||
('healrotationcastingoverride', 0, 'hroverride'),
|
||||
('healrotationchangeinterval', 0, 'hrinterval'),
|
||||
('healrotationcleartargets', 0, 'hrclear'),
|
||||
('healrotationcreate', 0, 'hrcreate'),
|
||||
('healrotationfastheals', 0, 'hrfastheals'),
|
||||
('healrotationlist', 0, 'hrlist'),
|
||||
('healrotationremovemember', 0, 'hrremm'),
|
||||
('healrotationremovetarget', 0, 'hrremt'),
|
||||
('healrotationresetlimits', 0, 'hrreset'),
|
||||
('healrotationstart', 0, 'hrstart'),
|
||||
('healrotationstop', 0, 'hrstop'),
|
||||
('help', 0, '?'),
|
||||
('hold', 0, ''),
|
||||
('identify', 0, 'lore'),
|
||||
('inventory', 0, 'inv'),
|
||||
('inventorygive', 0, 'invgive'),
|
||||
('inventorylist', 0, 'invlist'),
|
||||
('inventoryremove', 0, 'invremove'),
|
||||
('invisibility', 0, 'invis'),
|
||||
('levitation', 0, 'lev'),
|
||||
('lull', 0, 'calm|pacify'),
|
||||
('mesmerize', 0, 'mez'),
|
||||
('movementspeed', 0, 'sow'),
|
||||
('pet', 0, 'p'),
|
||||
('petremove', 0, 'prem'),
|
||||
('petsettype', 0, 'pset'),
|
||||
('picklock', 0, 'pl'),
|
||||
('portal', 0, 'port'),
|
||||
('pull', 0, ''),
|
||||
('release', 0, ''),
|
||||
('resistance', 0, 'resist'),
|
||||
('resurrect', 0, 'revive'),
|
||||
('rune', 0, ''),
|
||||
('sendhome', 0, 'gate'),
|
||||
('size', 0, ''),
|
||||
('summoncorpse', 0, 'scorpse'),
|
||||
('taunt', 0, ''),
|
||||
('track', 0, ''),
|
||||
('waterbreathing', 0, 'wb|eb');
|
||||
@ -1,3 +1,21 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "../common/global_define.h"
|
||||
#include "../common/eq_packet.h"
|
||||
#include "../common/eq_stream_intf.h"
|
||||
@ -498,7 +516,7 @@ bool Client::HandleNameApprovalPacket(const EQApplicationPacket *app)
|
||||
uchar race = app->pBuffer[64];
|
||||
uchar clas = app->pBuffer[68];
|
||||
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "Name approval request. Name=%s, race=%s, class=%s", char_name, GetRaceName(race), GetEQClassName(clas));
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "Name approval request. Name=%s, race=%s, class=%s", char_name, GetRaceIDName(race), GetClassIDName(clas));
|
||||
|
||||
EQApplicationPacket *outapp;
|
||||
outapp = new EQApplicationPacket;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2005 EQEMu Development Team (http://eqemulator.net)
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -15,6 +15,7 @@
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "../common/global_define.h"
|
||||
#include "clientlist.h"
|
||||
#include "zoneserver.h"
|
||||
@ -1064,7 +1065,7 @@ void ClientList::ConsoleSendWhoAll(const char* to, int16 admin, Who_All_Struct*
|
||||
|
||||
if (cle->Anon() == 2) { // Roleplay
|
||||
if (admin >= 100 && admin >= cle->Admin())
|
||||
sprintf(line, " %s[RolePlay %i %s] %s (%s)%s zone: %s%s%s", tmpgm, cle->level(), GetEQClassName(cle->class_(),cle->level()), cle->name(), GetRaceName(cle->race()), tmpguild, tmpZone, LFG, accinfo);
|
||||
sprintf(line, " %s[RolePlay %i %s] %s (%s)%s zone: %s%s%s", tmpgm, cle->level(), GetClassIDName(cle->class_(),cle->level()), cle->name(), GetRaceIDName(cle->race()), tmpguild, tmpZone, LFG, accinfo);
|
||||
else if (cle->Admin() >= 80 && admin < 80 && cle->GetGM()) {
|
||||
iterator.Advance();
|
||||
continue;
|
||||
@ -1074,7 +1075,7 @@ void ClientList::ConsoleSendWhoAll(const char* to, int16 admin, Who_All_Struct*
|
||||
}
|
||||
else if (cle->Anon() == 1) { // Anon
|
||||
if (admin >= 100 && admin >= cle->Admin())
|
||||
sprintf(line, " %s[ANON %i %s] %s (%s)%s zone: %s%s%s", tmpgm, cle->level(), GetEQClassName(cle->class_(),cle->level()), cle->name(), GetRaceName(cle->race()), tmpguild, tmpZone, LFG, accinfo);
|
||||
sprintf(line, " %s[ANON %i %s] %s (%s)%s zone: %s%s%s", tmpgm, cle->level(), GetClassIDName(cle->class_(),cle->level()), cle->name(), GetRaceIDName(cle->race()), tmpguild, tmpZone, LFG, accinfo);
|
||||
else if (cle->Admin() >= 80 && cle->GetGM()) {
|
||||
iterator.Advance();
|
||||
continue;
|
||||
@ -1083,7 +1084,7 @@ void ClientList::ConsoleSendWhoAll(const char* to, int16 admin, Who_All_Struct*
|
||||
sprintf(line, " %s[ANONYMOUS] %s%s%s", tmpgm, cle->name(), LFG, accinfo);
|
||||
}
|
||||
else
|
||||
sprintf(line, " %s[%i %s] %s (%s)%s zone: %s%s%s", tmpgm, cle->level(), GetEQClassName(cle->class_(),cle->level()), cle->name(), GetRaceName(cle->race()), tmpguild, tmpZone, LFG, accinfo);
|
||||
sprintf(line, " %s[%i %s] %s (%s)%s zone: %s%s%s", tmpgm, cle->level(), GetClassIDName(cle->class_(),cle->level()), cle->name(), GetRaceIDName(cle->race()), tmpguild, tmpZone, LFG, accinfo);
|
||||
|
||||
AppendAnyLenString(&output, &outsize, &outlen, line);
|
||||
if (outlen >= 3584) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -193,9 +193,9 @@ std::map<std::string,std::string> EQW::GetPlayerDetails(Const_char *char_name) {
|
||||
res["location_id"] = itoa(cle->zone());
|
||||
res["ip"] = long2ip(cle->GetIP());
|
||||
res["level"] = itoa(cle->level());
|
||||
res["race"] = GetRaceName(cle->race());
|
||||
res["race"] = GetRaceIDName(cle->race());
|
||||
res["race_id"] = itoa(cle->race());
|
||||
res["class"] = GetEQClassName(cle->class_());
|
||||
res["class"] = GetClassIDName(cle->class_());
|
||||
res["class_id"] = itoa(cle->class_());
|
||||
res["guild_id"] = itoa(cle->GuildID());
|
||||
res["guild"] = guild_mgr.GetGuildName(cle->GuildID());
|
||||
|
||||
@ -8,6 +8,8 @@ SET(zone_sources
|
||||
beacon.cpp
|
||||
bonuses.cpp
|
||||
bot.cpp
|
||||
bot_command.cpp
|
||||
bot_database.cpp
|
||||
botspellsai.cpp
|
||||
client.cpp
|
||||
client_mods.cpp
|
||||
@ -30,6 +32,7 @@ SET(zone_sources
|
||||
guild.cpp
|
||||
guild_mgr.cpp
|
||||
hate_list.cpp
|
||||
heal_rotation.cpp
|
||||
horse.cpp
|
||||
inventory.cpp
|
||||
loottables.cpp
|
||||
@ -131,6 +134,8 @@ SET(zone_headers
|
||||
basic_functions.h
|
||||
beacon.h
|
||||
bot.h
|
||||
bot_command.h
|
||||
bot_database.h
|
||||
bot_structs.h
|
||||
client.h
|
||||
client_packet.h
|
||||
@ -149,6 +154,7 @@ SET(zone_headers
|
||||
groups.h
|
||||
guild_mgr.h
|
||||
hate_list.h
|
||||
heal_rotation.h
|
||||
horse.h
|
||||
lua_bit.h
|
||||
lua_client.h
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2004 EQEMu Development Team (http://eqemulator.net)
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -1428,7 +1428,7 @@ bool Mob::CanUseAlternateAdvancementRank(AA::Rank *rank) {
|
||||
}
|
||||
}
|
||||
|
||||
auto race = GetArrayRace(GetBaseRace());
|
||||
auto race = GetPlayerRaceValue(GetBaseRace());
|
||||
race = race > 16 ? 1 : race;
|
||||
if(!(ability->races & (1 << (race - 1)))) {
|
||||
return false;
|
||||
|
||||
5245
zone/bot.cpp
5245
zone/bot.cpp
File diff suppressed because it is too large
Load Diff
221
zone/bot.h
221
zone/bot.h
@ -1,3 +1,21 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef BOT_H
|
||||
#define BOT_H
|
||||
|
||||
@ -7,9 +25,11 @@
|
||||
#include "mob.h"
|
||||
#include "client.h"
|
||||
#include "pets.h"
|
||||
#include "heal_rotation.h"
|
||||
#include "groups.h"
|
||||
#include "corpse.h"
|
||||
#include "zonedb.h"
|
||||
#include "bot_database.h"
|
||||
#include "string_ids.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/global_define.h"
|
||||
@ -29,8 +49,6 @@ const int DisciplineReuseStart = MaxSpellTimer + 1;
|
||||
const int MaxTimer = MaxSpellTimer + MaxDisciplineTimer;
|
||||
const int MaxStances = 7;
|
||||
const int MaxSpellTypes = 16;
|
||||
const int MaxHealRotationMembers = 6;
|
||||
const int MaxHealRotationTargets = 3;
|
||||
|
||||
enum BotStanceType {
|
||||
BotStancePassive,
|
||||
@ -39,9 +57,58 @@ enum BotStanceType {
|
||||
BotStanceReactive,
|
||||
BotStanceAggressive,
|
||||
BotStanceBurn,
|
||||
BotStanceBurnAE
|
||||
BotStanceBurnAE,
|
||||
BotStanceUnknown
|
||||
};
|
||||
|
||||
#define BOT_STANCE_COUNT 8
|
||||
#define VALIDBOTSTANCE(x) ((x >= (int)BotStancePassive && x <= (int)BotStanceBurnAE) ? ((BotStanceType)x) : (BotStanceUnknown))
|
||||
|
||||
static const std::string bot_stance_name[BOT_STANCE_COUNT] = {
|
||||
"Passive", // 0
|
||||
"Balanced", // 1
|
||||
"Efficient", // 2
|
||||
"Reactive", // 3
|
||||
"Aggressive", // 4
|
||||
"Burn", // 5
|
||||
"BurnAE", // 6
|
||||
"Unknown" // 7
|
||||
};
|
||||
|
||||
static const char* GetBotStanceName(int stance_id) { return bot_stance_name[VALIDBOTSTANCE(stance_id)].c_str(); }
|
||||
|
||||
#define VALIDBOTEQUIPSLOT(x) ((x >= EmuConstants::EQUIPMENT_BEGIN && x <= EmuConstants::EQUIPMENT_END) ? (x) : ((x == MainPowerSource) ? (22) : (23)))
|
||||
|
||||
static std::string bot_equip_slot_name[EmuConstants::EQUIPMENT_SIZE + 2] =
|
||||
{
|
||||
"Charm", // MainCharm
|
||||
"Left Ear", // MainEar1
|
||||
"Head", // MainHead
|
||||
"Face", // MainFace
|
||||
"Right Ear", // MainEar2
|
||||
"Neck", // MainNeck
|
||||
"Shoulders", // MainShoulders
|
||||
"Arms", // MainArms
|
||||
"Back", // MainBack
|
||||
"Left Wrist", // MainWrist1
|
||||
"Right Wrist", // MainWrist2
|
||||
"Range", // MainRange
|
||||
"Hands", // MainHands
|
||||
"Primary Hand", // MainPrimary
|
||||
"Secondary Hand", // MainSecondary
|
||||
"Left Finger", // MainFinger1
|
||||
"Right Finger", // MainFinger2
|
||||
"Chest", // MainChest
|
||||
"Legs", // MainLegs
|
||||
"Feet", // MainFeet
|
||||
"Waist", // MainWaist
|
||||
"Ammo", // MainAmmo
|
||||
"Power Source", // 22 (MainPowerSource = 9999)
|
||||
"Unknown"
|
||||
};
|
||||
|
||||
static const char* GetBotEquipSlotName(int slot_id) { return bot_equip_slot_name[VALIDBOTEQUIPSLOT(slot_id)].c_str(); }
|
||||
|
||||
enum SpellTypeIndex {
|
||||
SpellType_NukeIndex,
|
||||
SpellType_HealIndex,
|
||||
@ -110,7 +177,7 @@ public:
|
||||
BotRoleRaidHealer
|
||||
};
|
||||
|
||||
enum EqExpansions {
|
||||
enum EqExpansions { // expansions are off..EQ should be '0'
|
||||
ExpansionNone,
|
||||
ExpansionEQ,
|
||||
ExpansionRoK,
|
||||
@ -156,8 +223,10 @@ public:
|
||||
|
||||
// Class Methods
|
||||
bool IsValidRaceClassCombo();
|
||||
static bool IsValidRaceClassCombo(uint16 r, uint8 c);
|
||||
bool IsValidName();
|
||||
static bool IsBotNameAvailable(char *botName, std::string* errorMessage);
|
||||
static bool IsValidName(std::string& name);
|
||||
static bool IsBotNameAvailable(const char *botName, std::string* errorMessage);
|
||||
bool DeleteBot(std::string* errorMessage);
|
||||
void Spawn(Client* botCharacterOwner, std::string* errorMessage);
|
||||
virtual void SetLevel(uint8 in_level, bool command = false);
|
||||
@ -230,18 +299,7 @@ public:
|
||||
bool HasOrMayGetAggro();
|
||||
void SetDefaultBotStance();
|
||||
void CalcChanceToCast();
|
||||
void CreateHealRotation( Mob* target, uint32 timer = 10000 );
|
||||
bool AddHealRotationMember( Bot* healer );
|
||||
bool RemoveHealRotationMember( Bot* healer );
|
||||
bool AddHealRotationTarget( Mob* target );
|
||||
//bool AddHealRotationTarget( const char *targetName, int index);
|
||||
bool AddHealRotationTarget( Mob* target, int index);
|
||||
bool RemoveHealRotationTarget( Mob* target );
|
||||
bool RemoveHealRotationTarget( int index);
|
||||
void NotifyNextHealRotationMember( bool notifyNow = false );
|
||||
void ClearHealRotationLeader() { _healRotationLeader = 0; }
|
||||
void ClearHealRotationMembers();
|
||||
void ClearHealRotationTargets();
|
||||
|
||||
inline virtual int32 GetMaxStat();
|
||||
inline virtual int32 GetMaxResist();
|
||||
inline virtual int32 GetMaxSTR();
|
||||
@ -299,6 +357,9 @@ public:
|
||||
virtual bool AI_PursueCastCheck();
|
||||
virtual bool AI_IdleCastCheck();
|
||||
bool AIHealRotation(Mob* tar, bool useFastHeals);
|
||||
bool GetPauseAI() { return _pauseAI; }
|
||||
void SetPauseAI(bool pause_flag) { _pauseAI = pause_flag; }
|
||||
|
||||
|
||||
// Mob AI Virtual Override Methods
|
||||
virtual void AI_Process();
|
||||
@ -322,15 +383,6 @@ public:
|
||||
virtual bool DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction);
|
||||
virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot = USE_ITEM_SPELL_SLOT, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF, uint32 aa_id = 0);
|
||||
|
||||
// Bot Action Command Methods
|
||||
bool MesmerizeTarget(Mob* target);
|
||||
bool Bot_Command_Resist(int resisttype, int level);
|
||||
bool Bot_Command_DireTarget(int diretype, Mob *target);
|
||||
bool Bot_Command_CharmTarget(int charmtype, Mob *target);
|
||||
bool Bot_Command_CalmTarget(Mob *target);
|
||||
bool Bot_Command_RezzTarget(Mob *target);
|
||||
bool Bot_Command_Cure(int curetype, int level);
|
||||
|
||||
// Bot Equipment & Inventory Class Methods
|
||||
void BotTradeSwapItem(Client* client, int16 lootSlot, const ItemInst* inst, const ItemInst* inst_swap, uint32 equipableSlots, std::string* errorMessage, bool swap = true);
|
||||
void BotTradeAddItem(uint32 id, const ItemInst* inst, int16 charges, uint32 equipableSlots, uint16 lootSlot, std::string* errorMessage, bool addToDb = true);
|
||||
@ -339,20 +391,11 @@ public:
|
||||
uint32 GetEquipmentColor(uint8 material_slot) const;
|
||||
virtual void UpdateEquipmentLight() { m_Light.Type.Equipment = m_inv.FindBrightestLightType(); m_Light.Level.Equipment = m_Light.TypeToLevel(m_Light.Type.Equipment); }
|
||||
|
||||
// Static Class Methods
|
||||
static void SaveBotGroup(Group* botGroup, std::string botGroupName, std::string* errorMessage);
|
||||
static void DeleteBotGroup(std::string botGroupName, std::string* errorMessage);
|
||||
static std::list<BotGroup> LoadBotGroup(std::string botGroupName, std::string* errorMessage);
|
||||
static uint32 CanLoadBotGroup(uint32 botOwnerCharacterId, std::string botGroupName, std::string* errorMessage);
|
||||
static uint32 GetBotGroupIdByBotGroupName(std::string botGroupName, std::string* errorMessage);
|
||||
static uint32 GetBotGroupLeaderIdByBotGroupName(std::string botGroupName);
|
||||
static std::list<BotGroupList> GetBotGroupListByBotOwnerCharacterId(uint32 botOwnerCharacterId, std::string* errorMessage);
|
||||
static bool DoesBotGroupNameExist(std::string botGroupName);
|
||||
// Static Class Methods
|
||||
//static void DestroyBotRaidObjects(Client* client); // Can be removed after bot raids are dumped
|
||||
static uint32 GetBotIDByBotName(std::string botName);
|
||||
static Bot* LoadBot(uint32 botID, std::string* errorMessage);
|
||||
static std::list<BotsAvailableList> GetBotList(uint32 botOwnerCharacterID, std::string* errorMessage);
|
||||
static void ProcessBotCommands(Client *c, const Seperator *sep);
|
||||
static std::list<SpawnedBotsList> ListSpawnedBots(uint32 characterID, std::string* errorMessage);
|
||||
static uint32 SpawnedBotCount(uint32 botOwnerCharacterID, std::string* errorMessage);
|
||||
static uint32 CreatedBotCount(uint32 botOwnerCharacterID, std::string* errorMessage);
|
||||
@ -363,15 +406,10 @@ public:
|
||||
static std::string ClassIdToString(uint16 classId);
|
||||
static std::string RaceIdToString(uint16 raceId);
|
||||
static bool IsBotAttackAllowed(Mob* attacker, Mob* target, bool& hasRuleDefined);
|
||||
static void BotGroupOrderFollow(Group* group, Client* client);
|
||||
static void BotGroupOrderGuard(Group* group, Client* client);
|
||||
static void BotGroupOrderAttack(Group* group, Mob* target, Client* client);
|
||||
static void BotGroupSummon(Group* group, Client* client);
|
||||
static Bot* GetBotByBotClientOwnerAndBotName(Client* c, std::string botName);
|
||||
static void ProcessBotGroupInvite(Client* c, std::string botName);
|
||||
static void ProcessBotGroupDisband(Client* c, std::string botName);
|
||||
static void BotOrderCampAll(Client* c);
|
||||
static void BotHealRotationsClear( Client* c );
|
||||
static void ProcessBotInspectionRequest(Bot* inspectedBot, Client* client);
|
||||
static std::list<uint32> GetGroupedBotsByGroupId(uint32 groupId, std::string* errorMessage);
|
||||
static void LoadAndSpawnAllZonedBots(Client* botOwner);
|
||||
@ -411,13 +449,10 @@ public:
|
||||
static BotSpell GetBestBotSpellForCure(Bot* botCaster, Mob* target);
|
||||
static BotSpell GetBestBotSpellForResistDebuff(Bot* botCaster, Mob* target);
|
||||
static NPCType CreateDefaultNPCTypeStructForBot(std::string botName, std::string botLastName, uint8 botLevel, uint16 botRace, uint8 botClass, uint8 gender);
|
||||
static std::list<Bot*> GetBotsInHealRotation( Bot* leader );
|
||||
|
||||
// Static Bot Group Methods
|
||||
static bool AddBotToGroup(Bot* bot, Group* group);
|
||||
static bool RemoveBotFromGroup(Bot* bot, Group* group);
|
||||
static bool BotGroupCreate(std::string botGroupLeaderName);
|
||||
static bool BotGroupCreate(Bot* botGroupLeader);
|
||||
static bool GroupHasClass(Group* group, uint8 classId);
|
||||
static bool GroupHasClericClass(Group* group) { return GroupHasClass(group, CLERIC); }
|
||||
static bool GroupHasDruidClass(Group* group) { return GroupHasClass(group, DRUID); }
|
||||
@ -445,26 +480,38 @@ public:
|
||||
uint8 GetChanceToCastBySpellType(uint16 spellType);
|
||||
bool IsGroupPrimaryHealer();
|
||||
bool IsGroupPrimarySlower();
|
||||
bool IsBotCaster() { return (GetClass() == CLERIC || GetClass() == DRUID || GetClass() == SHAMAN || GetClass() == NECROMANCER || GetClass() == WIZARD || GetClass() == MAGICIAN || GetClass() == ENCHANTER); }
|
||||
bool IsBotINTCaster() { return (GetClass() == NECROMANCER || GetClass() == WIZARD || GetClass() == MAGICIAN || GetClass() == ENCHANTER); }
|
||||
bool IsBotWISCaster() { return (GetClass() == CLERIC || GetClass() == DRUID || GetClass() == SHAMAN); }
|
||||
bool IsBotCaster() { return IsCasterClass(GetClass()); }
|
||||
bool IsBotINTCaster() { return IsINTCasterClass(GetClass()); }
|
||||
bool IsBotWISCaster() { return IsWISCasterClass(GetClass()); }
|
||||
bool CanHeal();
|
||||
int GetRawACNoShield(int &shield_ac);
|
||||
bool GetHasBeenSummoned() { return _hasBeenSummoned; }
|
||||
const glm::vec3 GetPreSummonLocation() const { return m_PreSummonLocation; }
|
||||
bool GetInHealRotation() { return _isInHealRotation; }
|
||||
bool GetHealRotationActive() { return (GetInHealRotation() && _isHealRotationActive); }
|
||||
bool GetHealRotationUseFastHeals() { return _healRotationUseFastHeals; }
|
||||
bool GetHasHealedThisCycle() { return _hasHealedThisCycle; }
|
||||
Mob* GetHealRotationTarget();
|
||||
Mob* GetHealRotationTarget(uint8 index);
|
||||
Bot* GetHealRotationLeader();
|
||||
Bot* GetNextHealRotationMember();
|
||||
Bot* GetPrevHealRotationMember();
|
||||
uint8 GetNumHealRotationMembers () { return _numHealRotationMembers; }
|
||||
uint32 GetHealRotationNextHealTime() { return _healRotationNextHeal; }
|
||||
uint32 GetHealRotationTimer () { return _healRotationTimer; }
|
||||
bool GetBardUseOutOfCombatSongs() { return _bardUseOutOfCombatSongs;}
|
||||
|
||||
// new heal rotation code
|
||||
bool CreateHealRotation(uint32 cycle_duration_ms = 5000, bool fast_heals = false, bool adaptive_targeting = false, bool casting_override = false);
|
||||
bool DestroyHealRotation();
|
||||
bool JoinHealRotationMemberPool(std::shared_ptr<HealRotation>* heal_rotation);
|
||||
bool LeaveHealRotationMemberPool();
|
||||
|
||||
bool IsHealRotationMember() { return (m_member_of_heal_rotation.use_count() && m_member_of_heal_rotation.get()); }
|
||||
bool UseHealRotationFastHeals();
|
||||
bool UseHealRotationAdaptiveTargeting();
|
||||
|
||||
bool IsHealRotationActive();
|
||||
bool IsHealRotationReady();
|
||||
bool IsHealRotationCaster();
|
||||
bool HealRotationPokeTarget();
|
||||
Mob* HealRotationTarget();
|
||||
bool AdvanceHealRotation(bool use_interval = true);
|
||||
|
||||
bool IsMyHealRotationSet();
|
||||
bool AmICastingForHealRotation();
|
||||
void SetMyCastingForHealRotation(bool flag = true);
|
||||
|
||||
std::shared_ptr<HealRotation>* MemberOfHealRotation() { return &m_member_of_heal_rotation; }
|
||||
|
||||
bool GetAltOutOfCombatBehavior() { return _altoutofcombatbehavior;}
|
||||
bool GetShowHelm() { return _showhelm; }
|
||||
inline virtual int32 GetAC() const { return AC; }
|
||||
inline virtual int32 GetSTR() const { return STR; }
|
||||
@ -532,34 +579,41 @@ public:
|
||||
// void SetBotOwnerCharacterID(uint32 botOwnerCharacterID) { _botOwnerCharacterID = botOwnerCharacterID; }
|
||||
void SetRangerAutoWeaponSelect(bool enable) { GetClass() == RANGER ? _rangerAutoWeaponSelect = enable : _rangerAutoWeaponSelect = false; }
|
||||
void SetBotRole(BotRoleType botRole) { _botRole = botRole; }
|
||||
void SetBotStance(BotStanceType botStance) { _botStance = botStance; }
|
||||
void SetBotStance(BotStanceType botStance) { _botStance = ((botStance != BotStanceUnknown) ? (botStance) : (BotStancePassive)); }
|
||||
void SetSpellRecastTimer(int timer_index, int32 recast_delay);
|
||||
void SetDisciplineRecastTimer(int timer_index, int32 recast_delay);
|
||||
void SetHasBeenSummoned(bool s);
|
||||
void SetPreSummonLocation(const glm::vec3& location) { m_PreSummonLocation = location; }
|
||||
void SetInHealRotation( bool inRotation ) { _isInHealRotation = inRotation; }
|
||||
void SetHealRotationActive( bool isActive ) { _isHealRotationActive = isActive; }
|
||||
void SetHealRotationUseFastHeals( bool useFastHeals ) { _healRotationUseFastHeals = useFastHeals; }
|
||||
void SetHasHealedThisCycle( bool hasHealed ) { _hasHealedThisCycle = hasHealed; }
|
||||
void SetHealRotationLeader( Bot* leader );
|
||||
void SetNextHealRotationMember( Bot* healer );
|
||||
void SetPrevHealRotationMember( Bot* healer );
|
||||
void SetHealRotationNextHealTime( uint32 nextHealTime ) { _healRotationNextHeal = nextHealTime; }
|
||||
void SetHealRotationTimer( uint32 timer ) { _healRotationTimer = timer; }
|
||||
void SetNumHealRotationMembers( uint8 numMembers ) { _numHealRotationMembers = numMembers; }
|
||||
void SetBardUseOutOfCombatSongs(bool useOutOfCombatSongs) { _bardUseOutOfCombatSongs = useOutOfCombatSongs;}
|
||||
|
||||
void SetAltOutOfCombatBehavior(bool behavior_flag) { _altoutofcombatbehavior = behavior_flag;}
|
||||
void SetShowHelm(bool showhelm) { _showhelm = showhelm; }
|
||||
void SetBeardColor(uint8 value) { beardcolor = value; }
|
||||
void SetBeard(uint8 value) { beard = value; }
|
||||
void SetEyeColor1(uint8 value) { eyecolor1 = value; }
|
||||
void SetEyeColor2(uint8 value) { eyecolor2 = value; }
|
||||
void SetLuclinFace(uint8 value) { luclinface = value; }
|
||||
void SetHairColor(uint8 value) { haircolor = value; }
|
||||
void SetHairStyle(uint8 value) { hairstyle = value; }
|
||||
void SetDrakkinDetails(uint32 value) { drakkin_details = value; }
|
||||
void SetDrakkinHeritage(uint32 value) { drakkin_heritage = value; }
|
||||
void SetDrakkinTattoo(uint32 value) { drakkin_tattoo = value; }
|
||||
bool DyeArmor(int16 slot_id, uint32 rgb, bool all_flag = false, bool save_flag = true);
|
||||
|
||||
std::string CreateSayLink(Client* botOwner, const char* message, const char* name);
|
||||
|
||||
// Class Destructors
|
||||
virtual ~Bot();
|
||||
|
||||
// Publicized protected/private functions
|
||||
virtual void BotRangedAttack(Mob* other); // protected
|
||||
uint32 GetBotItemsCount(std::string* errorMessage); // private
|
||||
void BotRemoveEquipItem(int slot); // private
|
||||
void RemoveBotItemBySlot(uint32 slotID, std::string* errorMessage); // private
|
||||
|
||||
protected:
|
||||
virtual void PetAIProcess();
|
||||
static NPCType FillNPCTypeStruct(uint32 botSpellsID, std::string botName, std::string botLastName, uint8 botLevel, uint16 botRace, uint8 botClass, uint8 gender, float size, uint32 face, uint32 hairStyle, uint32 hairColor, uint32 eyeColor, uint32 eyeColor2, uint32 beardColor, uint32 beard, uint32 drakkinHeritage, uint32 drakkinTattoo, uint32 drakkinDetails, int32 hp, int32 mana, int32 mr, int32 cr, int32 dr, int32 fr, int32 pr, int32 corrup, int32 ac, uint32 str, uint32 sta, uint32 dex, uint32 agi, uint32 _int, uint32 wis, uint32 cha, uint32 attack);
|
||||
virtual void BotMeditate(bool isSitting);
|
||||
virtual void BotRangedAttack(Mob* other);
|
||||
virtual bool CheckBotDoubleAttack(bool Triple = false);
|
||||
virtual int32 GetBotFocusEffect(BotfocusType bottype, uint16 spell_id);
|
||||
virtual int32 CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spell_id, bool best_focus=false);
|
||||
@ -607,22 +661,14 @@ private:
|
||||
bool _hasBeenSummoned;
|
||||
glm::vec3 m_PreSummonLocation;
|
||||
uint8 _spellCastingChances[MaxStances][MaxSpellTypes];
|
||||
bool _isInHealRotation;
|
||||
bool _isHealRotationActive;
|
||||
bool _healRotationUseFastHeals;
|
||||
bool _hasHealedThisCycle;
|
||||
uint32 _healRotationTimer;
|
||||
uint32 _healRotationNextHeal;
|
||||
//char _healRotationTargets[MaxHealRotationTargets][64];
|
||||
uint16 _healRotationTargets[MaxHealRotationTargets];
|
||||
uint32 _healRotationLeader;
|
||||
uint32 _healRotationMemberNext;
|
||||
uint32 _healRotationMemberPrev;
|
||||
uint8 _numHealRotationMembers;
|
||||
|
||||
std::shared_ptr<HealRotation> m_member_of_heal_rotation;
|
||||
|
||||
std::map<uint32, BotAA> botAAs;
|
||||
InspectMessage_Struct _botInspectMessage;
|
||||
bool _bardUseOutOfCombatSongs;
|
||||
bool _altoutofcombatbehavior;
|
||||
bool _showhelm;
|
||||
bool _pauseAI;
|
||||
|
||||
// Private "base stats" Members
|
||||
int32 _baseMR;
|
||||
@ -656,12 +702,9 @@ private:
|
||||
|
||||
// Private "Inventory" Methods
|
||||
void GetBotItems(std::string* errorMessage, Inventory &inv);
|
||||
void BotRemoveEquipItem(int slot);
|
||||
void BotAddEquipItem(int slot, uint32 id);
|
||||
uint32 GetBotItemBySlot(uint32 slotID);
|
||||
void RemoveBotItemBySlot(uint32 slotID, std::string* errorMessage);
|
||||
void SetBotItemInSlot(uint32 slotID, uint32 itemID, const ItemInst* inst, std::string* errorMessage);
|
||||
uint32 GetBotItemsCount(std::string* errorMessage);
|
||||
uint32 GetTotalPlayTime();
|
||||
void SaveBuffs(); // Saves existing buffs to the database to persist zoning and camping
|
||||
void LoadBuffs(); // Retrieves saved buffs from the database on spawning
|
||||
|
||||
7312
zone/bot_command.cpp
Normal file
7312
zone/bot_command.cpp
Normal file
File diff suppressed because it is too large
Load Diff
667
zone/bot_command.h
Normal file
667
zone/bot_command.h
Normal file
@ -0,0 +1,667 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BOT_COMMAND_H
|
||||
#define BOT_COMMAND_H
|
||||
|
||||
class Client;
|
||||
class Seperator;
|
||||
|
||||
#include "../common/types.h"
|
||||
#include "bot.h"
|
||||
|
||||
|
||||
class BCEnum
|
||||
{
|
||||
public:
|
||||
typedef enum SpellType {
|
||||
SpT_None = 0,
|
||||
SpT_BindAffinity,
|
||||
SpT_Charm,
|
||||
SpT_Cure,
|
||||
SpT_Depart,
|
||||
SpT_Escape,
|
||||
SpT_Identify,
|
||||
SpT_Invisibility,
|
||||
SpT_Levitation,
|
||||
SpT_Lull,
|
||||
SpT_Mesmerize,
|
||||
SpT_MovementSpeed,
|
||||
SpT_Resistance,
|
||||
SpT_Resurrect,
|
||||
SpT_Rune,
|
||||
SpT_SendHome,
|
||||
SpT_Size,
|
||||
SpT_Stance,
|
||||
SpT_SummonCorpse,
|
||||
SpT_WaterBreathing
|
||||
} SpType;
|
||||
static const int SpellTypeFirst = SpT_BindAffinity;
|
||||
static const int SpellTypeLast = SpT_WaterBreathing;
|
||||
|
||||
typedef enum TargetType {
|
||||
TT_None = 0,
|
||||
TT_Corpse,
|
||||
TT_Self,
|
||||
TT_Animal,
|
||||
TT_Undead,
|
||||
TT_Summoned,
|
||||
TT_Plant,
|
||||
TT_Single,
|
||||
TT_GroupV1,
|
||||
TT_GroupV2,
|
||||
TT_AECaster,
|
||||
TT_AEBard,
|
||||
TT_AETarget
|
||||
} TType;
|
||||
static const int TargetTypeFirst = TT_Corpse;
|
||||
static const int TargetTypeLast = TT_AETarget;
|
||||
static const int TargetTypeCount = 13;
|
||||
|
||||
typedef enum TargetMask {
|
||||
TM_None = 0,
|
||||
TM_Corpse = 1,
|
||||
TM_Self = 2,
|
||||
TM_Animal = 4,
|
||||
TM_Undead = 8,
|
||||
TM_Summoned = 16,
|
||||
TM_Plant = 32,
|
||||
TM_Single = 124, // currently, 2^6 + 2^{2..5}) -or- (64+32+16+8+4)
|
||||
TM_GroupV1 = 128,
|
||||
TM_GroupV2 = 256,
|
||||
TM_AECaster = 512,
|
||||
TM_AEBard = 1024,
|
||||
TM_AETarget = 2048
|
||||
} TMask;
|
||||
|
||||
typedef enum AppearanceFailType {
|
||||
AFT_None = 0,
|
||||
AFT_Value,
|
||||
AFT_GenderRace,
|
||||
AFT_Race
|
||||
} AFType;
|
||||
|
||||
typedef enum AilmentType {
|
||||
AT_None = 0,
|
||||
AT_Blindness, // SE: 20
|
||||
AT_Disease, // SE: 35
|
||||
AT_Poison, // SE: 36
|
||||
AT_Curse, // SE: 116
|
||||
AT_Corruption // SE: 369
|
||||
} AType;
|
||||
static const int AilmentTypeCount = 5;
|
||||
|
||||
typedef enum InvisibilityType {
|
||||
IT_None = 0,
|
||||
IT_Animal,
|
||||
IT_Undead,
|
||||
IT_Living,
|
||||
IT_See
|
||||
} IType;
|
||||
|
||||
typedef enum ResistanceType {
|
||||
RT_None = 0,
|
||||
RT_Fire, // SE: 46
|
||||
RT_Cold, // SE: 47
|
||||
RT_Poison, // SE: 48
|
||||
RT_Disease, // SE: 49
|
||||
RT_Magic, // SE: 50
|
||||
RT_Corruption // SE: 370
|
||||
} RType;
|
||||
static const int ResistanceTypeCount = 6;
|
||||
|
||||
typedef enum SizeType {
|
||||
SzT_None = 0,
|
||||
SzT_Enlarge,
|
||||
SzT_Reduce
|
||||
} SzType;
|
||||
|
||||
typedef enum StanceType {
|
||||
StT_None = 0,
|
||||
StT_Aggressive,
|
||||
StT_Defensive
|
||||
} StType;
|
||||
|
||||
static std::string SpellTypeEnumToString(BCEnum::SpType spell_type) {
|
||||
switch (spell_type) {
|
||||
case SpT_BindAffinity:
|
||||
return "SpT_BindAffinity";
|
||||
case SpT_Charm:
|
||||
return "SpT_Charm";
|
||||
case SpT_Cure:
|
||||
return "SpT_Cure";
|
||||
case SpT_Depart:
|
||||
return "SpT_Depart";
|
||||
case SpT_Escape:
|
||||
return "SpT_Escape";
|
||||
case SpT_Identify:
|
||||
return "SpT_Identify";
|
||||
case SpT_Invisibility:
|
||||
return "SpT_Invisibility";
|
||||
case SpT_Levitation:
|
||||
return "SpT_Levitation";
|
||||
case SpT_Lull:
|
||||
return "SpT_Lull";
|
||||
case SpT_Mesmerize:
|
||||
return "SpT_Mesmerize";
|
||||
case SpT_MovementSpeed:
|
||||
return "SpT_MovementSpeed";
|
||||
case SpT_Resistance:
|
||||
return "SpT_Resistance";
|
||||
case SpT_Resurrect:
|
||||
return "SpT_Resurrect";
|
||||
case SpT_Rune:
|
||||
return "SpT_Rune";
|
||||
case SpT_SendHome:
|
||||
return "SpT_SendHome";
|
||||
case SpT_Size:
|
||||
return "SpT_Size";
|
||||
case SpT_Stance:
|
||||
return "SpT_Stance";
|
||||
case SpT_SummonCorpse:
|
||||
return "SpT_SummonCorpse";
|
||||
case SpT_WaterBreathing:
|
||||
return "SpT_WaterBreathing";
|
||||
default:
|
||||
return "SpT_None";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string TargetTypeEnumToString(BCEnum::TType target_type) {
|
||||
switch (target_type) {
|
||||
case TT_Self:
|
||||
return "TT_Self";
|
||||
case TT_Animal:
|
||||
return "TT_Animal";
|
||||
case TT_Undead:
|
||||
return "TT_Undead";
|
||||
case TT_Summoned:
|
||||
return "TT_Summoned";
|
||||
case TT_Plant:
|
||||
return "TT_Plant";
|
||||
case TT_Single:
|
||||
return "TT_Single";
|
||||
case TT_GroupV1:
|
||||
return "TT_GroupV1";
|
||||
case TT_GroupV2:
|
||||
return "TT_GroupV2";
|
||||
case TT_AECaster:
|
||||
return "TT_AECaster";
|
||||
case TT_AEBard:
|
||||
return "TT_AEBard";
|
||||
case TT_AETarget:
|
||||
return "TT_AETarget";
|
||||
case TT_Corpse:
|
||||
return "TT_Corpse";
|
||||
default:
|
||||
return "TT_None";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class STBaseEntry;
|
||||
class STCharmEntry;
|
||||
class STCureEntry;
|
||||
class STDepartEntry;
|
||||
class STEscapeEntry;
|
||||
class STInvisibilityEntry;
|
||||
class STMovementSpeedEntry;
|
||||
class STResistanceEntry;
|
||||
class STResurrectEntry;
|
||||
class STSendHomeEntry;
|
||||
class STSizeEntry;
|
||||
class STStanceEntry;
|
||||
|
||||
class STBaseEntry
|
||||
{
|
||||
protected:
|
||||
BCEnum::SpType m_bcst;
|
||||
|
||||
public:
|
||||
int spell_id;
|
||||
uint8 spell_level;
|
||||
uint8 caster_class;
|
||||
BCEnum::TType target_type;
|
||||
|
||||
// A non-polymorphic constructor requires an appropriate, non-'ST_None' BCEnum::SType
|
||||
STBaseEntry(BCEnum::SpType init_bcst = BCEnum::SpT_None) {
|
||||
spell_id = 0;
|
||||
spell_level = 255;
|
||||
caster_class = 255;
|
||||
target_type = BCEnum::TT_None;
|
||||
m_bcst = init_bcst;
|
||||
}
|
||||
STBaseEntry(STBaseEntry* prototype) {
|
||||
spell_id = prototype->spell_id;
|
||||
spell_level = 255;
|
||||
caster_class = 255;
|
||||
target_type = prototype->target_type;
|
||||
m_bcst = prototype->BCST();
|
||||
}
|
||||
virtual ~STBaseEntry() { return; };
|
||||
|
||||
BCEnum::SpType BCST() { return m_bcst; }
|
||||
|
||||
virtual bool IsDerived() { return false; }
|
||||
|
||||
bool IsCharm() const { return (m_bcst == BCEnum::SpT_Charm); }
|
||||
bool IsCure() const { return (m_bcst == BCEnum::SpT_Cure); }
|
||||
bool IsDepart() const { return (m_bcst == BCEnum::SpT_Depart); }
|
||||
bool IsEscape() const { return (m_bcst == BCEnum::SpT_Escape); }
|
||||
bool IsInvisibility() const { return (m_bcst == BCEnum::SpT_Invisibility); }
|
||||
bool IsMovementSpeed() const { return (m_bcst == BCEnum::SpT_MovementSpeed); }
|
||||
bool IsResistance() const { return (m_bcst == BCEnum::SpT_Resistance); }
|
||||
bool IsResurrect() const { return (m_bcst == BCEnum::SpT_Resurrect); }
|
||||
bool IsSendHome() const { return (m_bcst == BCEnum::SpT_SendHome); }
|
||||
bool IsSize() const { return (m_bcst == BCEnum::SpT_Size); }
|
||||
bool IsStance() const { return (m_bcst == BCEnum::SpT_Stance); }
|
||||
|
||||
virtual STCharmEntry* SafeCastToCharm() { return nullptr; }
|
||||
virtual STCureEntry* SafeCastToCure() { return nullptr; }
|
||||
virtual STDepartEntry* SafeCastToDepart() { return nullptr; }
|
||||
virtual STEscapeEntry* SafeCastToEscape() { return nullptr; }
|
||||
virtual STInvisibilityEntry* SafeCastToInvisibility() { return nullptr; }
|
||||
virtual STMovementSpeedEntry* SafeCastToMovementSpeed() { return nullptr; }
|
||||
virtual STResistanceEntry* SafeCastToResistance() { return nullptr; }
|
||||
virtual STResurrectEntry* SafeCastToResurrect() { return nullptr; }
|
||||
virtual STSendHomeEntry* SafeCastToSendHome() { return nullptr; }
|
||||
virtual STSizeEntry* SafeCastToSize() { return nullptr; }
|
||||
virtual STStanceEntry* SafeCastToStance() { return nullptr; }
|
||||
};
|
||||
|
||||
class STCharmEntry : public STBaseEntry
|
||||
{
|
||||
public:
|
||||
bool dire;
|
||||
|
||||
STCharmEntry() {
|
||||
m_bcst = BCEnum::SpT_Charm;
|
||||
dire = false;
|
||||
}
|
||||
STCharmEntry(STCharmEntry* prototype) : STBaseEntry(prototype) {
|
||||
m_bcst = BCEnum::SpT_Charm;
|
||||
dire = prototype->dire;
|
||||
}
|
||||
virtual ~STCharmEntry() { return; };
|
||||
|
||||
virtual bool IsDerived() { return true; }
|
||||
|
||||
virtual STCharmEntry* SafeCastToCharm() { return ((m_bcst == BCEnum::SpT_Charm) ? (static_cast<STCharmEntry*>(this)) : (nullptr)); }
|
||||
};
|
||||
|
||||
class STCureEntry : public STBaseEntry
|
||||
{
|
||||
public:
|
||||
int cure_value[BCEnum::AilmentTypeCount];
|
||||
int cure_total;
|
||||
|
||||
STCureEntry() {
|
||||
m_bcst = BCEnum::SpT_Cure;
|
||||
memset(&cure_value, 0, (sizeof(int) * BCEnum::AilmentTypeCount));
|
||||
cure_total = 0;
|
||||
}
|
||||
STCureEntry(STCureEntry* prototype) : STBaseEntry(prototype) {
|
||||
m_bcst = BCEnum::SpT_Cure;
|
||||
memcpy(&cure_value, prototype->cure_value, (sizeof(int) * BCEnum::AilmentTypeCount));
|
||||
cure_total = prototype->cure_total;
|
||||
}
|
||||
virtual ~STCureEntry() { return; };
|
||||
|
||||
virtual bool IsDerived() { return true; }
|
||||
|
||||
virtual STCureEntry* SafeCastToCure() { return ((m_bcst == BCEnum::SpT_Cure) ? (static_cast<STCureEntry*>(this)) : (nullptr)); }
|
||||
};
|
||||
|
||||
class STDepartEntry : public STBaseEntry
|
||||
{
|
||||
public:
|
||||
bool single;
|
||||
std::string long_name;
|
||||
|
||||
STDepartEntry() {
|
||||
m_bcst = BCEnum::SpT_Depart;
|
||||
single = false;
|
||||
long_name.clear();
|
||||
}
|
||||
STDepartEntry(STDepartEntry* prototype) : STBaseEntry(prototype) {
|
||||
m_bcst = BCEnum::SpT_Depart;
|
||||
single = prototype->single;
|
||||
long_name = prototype->long_name;
|
||||
}
|
||||
virtual ~STDepartEntry() { return; };
|
||||
|
||||
virtual bool IsDerived() { return true; }
|
||||
|
||||
virtual STDepartEntry* SafeCastToDepart() { return ((m_bcst == BCEnum::SpT_Depart) ? (static_cast<STDepartEntry*>(this)) : (nullptr)); }
|
||||
};
|
||||
|
||||
class STEscapeEntry : public STBaseEntry
|
||||
{
|
||||
public:
|
||||
bool lesser;
|
||||
|
||||
STEscapeEntry() {
|
||||
m_bcst = BCEnum::SpT_Escape;
|
||||
lesser = false;
|
||||
}
|
||||
STEscapeEntry(STEscapeEntry* prototype) : STBaseEntry(prototype) {
|
||||
m_bcst = BCEnum::SpT_Escape;
|
||||
lesser = prototype->lesser;
|
||||
}
|
||||
virtual ~STEscapeEntry() { return; };
|
||||
|
||||
virtual bool IsDerived() { return true; }
|
||||
|
||||
virtual STEscapeEntry* SafeCastToEscape() { return ((m_bcst == BCEnum::SpT_Escape) ? (static_cast<STEscapeEntry*>(this)) : (nullptr)); }
|
||||
};
|
||||
|
||||
class STInvisibilityEntry : public STBaseEntry
|
||||
{
|
||||
public:
|
||||
BCEnum::IType invis_type;
|
||||
|
||||
STInvisibilityEntry() {
|
||||
m_bcst = BCEnum::SpT_Invisibility;
|
||||
invis_type = BCEnum::IT_None;
|
||||
}
|
||||
STInvisibilityEntry(STInvisibilityEntry* prototype) : STBaseEntry(prototype) {
|
||||
m_bcst = BCEnum::SpT_Invisibility;
|
||||
invis_type = prototype->invis_type;
|
||||
}
|
||||
virtual ~STInvisibilityEntry() { return; };
|
||||
|
||||
virtual bool IsDerived() { return true; }
|
||||
|
||||
virtual STInvisibilityEntry* SafeCastToInvisibility() { return ((m_bcst == BCEnum::SpT_Invisibility) ? (static_cast<STInvisibilityEntry*>(this)) : (nullptr)); }
|
||||
};
|
||||
|
||||
class STMovementSpeedEntry : public STBaseEntry
|
||||
{
|
||||
public:
|
||||
bool group;
|
||||
|
||||
STMovementSpeedEntry() {
|
||||
m_bcst = BCEnum::SpT_MovementSpeed;
|
||||
group = false;
|
||||
}
|
||||
STMovementSpeedEntry(STMovementSpeedEntry* prototype) : STBaseEntry(prototype) {
|
||||
m_bcst = BCEnum::SpT_MovementSpeed;
|
||||
group = prototype->group;
|
||||
}
|
||||
virtual ~STMovementSpeedEntry() { return; };
|
||||
|
||||
virtual bool IsDerived() { return true; }
|
||||
|
||||
virtual STMovementSpeedEntry* SafeCastToMovementSpeed() { return ((m_bcst == BCEnum::SpT_MovementSpeed) ? (static_cast<STMovementSpeedEntry*>(this)) : (nullptr)); }
|
||||
};
|
||||
|
||||
class STResistanceEntry : public STBaseEntry
|
||||
{
|
||||
public:
|
||||
int resist_value[BCEnum::ResistanceTypeCount];
|
||||
int resist_total;
|
||||
|
||||
STResistanceEntry() {
|
||||
m_bcst = BCEnum::SpT_Resistance;
|
||||
memset(&resist_value, 0, (sizeof(int) * BCEnum::ResistanceTypeCount));
|
||||
resist_total = 0;
|
||||
}
|
||||
STResistanceEntry(STResistanceEntry* prototype) : STBaseEntry(prototype) {
|
||||
m_bcst = BCEnum::SpT_Resistance;
|
||||
memcpy(&resist_value, prototype->resist_value, (sizeof(int) * BCEnum::ResistanceTypeCount));
|
||||
resist_total = prototype->resist_total;
|
||||
}
|
||||
virtual ~STResistanceEntry() { return; };
|
||||
|
||||
virtual bool IsDerived() { return true; }
|
||||
|
||||
virtual STResistanceEntry* SafeCastToResistance() { return ((m_bcst == BCEnum::SpT_Resistance) ? (static_cast<STResistanceEntry*>(this)) : (nullptr)); }
|
||||
};
|
||||
|
||||
class STResurrectEntry : public STBaseEntry
|
||||
{
|
||||
public:
|
||||
bool aoe;
|
||||
|
||||
STResurrectEntry() {
|
||||
m_bcst = BCEnum::SpT_Resurrect;
|
||||
aoe = false;
|
||||
}
|
||||
STResurrectEntry(STResurrectEntry* prototype) : STBaseEntry(prototype) {
|
||||
m_bcst = BCEnum::SpT_Resurrect;
|
||||
aoe = prototype->aoe;
|
||||
}
|
||||
virtual ~STResurrectEntry() { return; };
|
||||
|
||||
virtual bool IsDerived() { return true; }
|
||||
|
||||
virtual STResurrectEntry* SafeCastToResurrect() { return ((m_bcst == BCEnum::SpT_Resurrect) ? (static_cast<STResurrectEntry*>(this)) : (nullptr)); }
|
||||
};
|
||||
|
||||
class STSendHomeEntry : public STBaseEntry
|
||||
{
|
||||
public:
|
||||
bool group;
|
||||
|
||||
STSendHomeEntry() {
|
||||
m_bcst = BCEnum::SpT_SendHome;
|
||||
group = false;
|
||||
}
|
||||
STSendHomeEntry(STSendHomeEntry* prototype) : STBaseEntry(prototype) {
|
||||
m_bcst = BCEnum::SpT_SendHome;
|
||||
group = prototype->group;
|
||||
}
|
||||
virtual ~STSendHomeEntry() { return; };
|
||||
|
||||
virtual bool IsDerived() { return true; }
|
||||
|
||||
virtual STSendHomeEntry* SafeCastToSendHome() { return ((m_bcst == BCEnum::SpT_SendHome) ? (static_cast<STSendHomeEntry*>(this)) : (nullptr)); }
|
||||
};
|
||||
|
||||
class STSizeEntry : public STBaseEntry
|
||||
{
|
||||
public:
|
||||
BCEnum::SzType size_type;
|
||||
|
||||
STSizeEntry() {
|
||||
m_bcst = BCEnum::SpT_Size;
|
||||
size_type = BCEnum::SzT_None;
|
||||
}
|
||||
STSizeEntry(STSizeEntry* prototype) : STBaseEntry(prototype) {
|
||||
m_bcst = BCEnum::SpT_Size;
|
||||
size_type = prototype->size_type;
|
||||
}
|
||||
virtual ~STSizeEntry() { return; };
|
||||
|
||||
virtual bool IsDerived() { return true; }
|
||||
|
||||
virtual STSizeEntry* SafeCastToSize() { return ((m_bcst == BCEnum::SpT_Size) ? (static_cast<STSizeEntry*>(this)) : (nullptr)); }
|
||||
};
|
||||
|
||||
class STStanceEntry : public STBaseEntry {
|
||||
public:
|
||||
BCEnum::StType stance_type;
|
||||
|
||||
STStanceEntry() {
|
||||
m_bcst = BCEnum::SpT_Stance;
|
||||
stance_type = BCEnum::StT_None;
|
||||
}
|
||||
STStanceEntry(STStanceEntry* prototype) : STBaseEntry(prototype) {
|
||||
m_bcst = BCEnum::SpT_Stance;
|
||||
stance_type = prototype->stance_type;
|
||||
}
|
||||
virtual ~STStanceEntry() { return; };
|
||||
|
||||
virtual bool IsDerived() { return true; }
|
||||
|
||||
virtual STStanceEntry* SafeCastToStance() { return ((m_bcst == BCEnum::SpT_Stance) ? (static_cast<STStanceEntry*>(this)) : (nullptr)); }
|
||||
};
|
||||
|
||||
|
||||
typedef std::list<STBaseEntry*> bcst_list;
|
||||
typedef std::map<BCEnum::SpType, bcst_list> bcst_map;
|
||||
|
||||
typedef std::map<BCEnum::SpType, std::string> bcst_required_bot_classes_map;
|
||||
typedef std::map<BCEnum::SpType, std::map<uint8, std::string>> bcst_required_bot_classes_map_by_class;
|
||||
|
||||
typedef std::map<uint8, uint8> bcst_levels;
|
||||
typedef std::map<BCEnum::SpType, bcst_levels> bcst_levels_map;
|
||||
|
||||
|
||||
#define BOT_COMMAND_CHAR '^'
|
||||
|
||||
typedef void (*BotCmdFuncPtr)(Client *,const Seperator *);
|
||||
|
||||
typedef struct {
|
||||
int access;
|
||||
const char *desc; // description of bot command
|
||||
BotCmdFuncPtr function; // null means perl function
|
||||
} BotCommandRecord;
|
||||
|
||||
extern int (*bot_command_dispatch)(Client *,char const*);
|
||||
extern int bot_command_count; // number of bot commands loaded
|
||||
|
||||
|
||||
// the bot command system:
|
||||
int bot_command_init(void);
|
||||
void bot_command_deinit(void);
|
||||
int bot_command_add(std::string bot_command_name, const char *desc, int access, BotCmdFuncPtr function);
|
||||
int bot_command_not_avail(Client *c, const char *message);
|
||||
int bot_command_real_dispatch(Client *c, char const *message);
|
||||
void bot_command_log_command(Client *c, const char *message);
|
||||
|
||||
|
||||
// bot commands
|
||||
void bot_command_actionable(Client *c, const Seperator *sep);
|
||||
void bot_command_aggressive(Client *c, const Seperator *sep);
|
||||
void bot_command_attack(Client *c, const Seperator *sep);
|
||||
void bot_command_bind_affinity(Client *c, const Seperator *sep);
|
||||
void bot_command_bot(Client *c, const Seperator *sep);
|
||||
void bot_command_botgroup(Client *c, const Seperator *sep);
|
||||
void bot_command_charm(Client *c, const Seperator *sep);
|
||||
void bot_command_cure(Client *c, const Seperator *sep);
|
||||
void bot_command_defensive(Client *c, const Seperator *sep);
|
||||
void bot_command_depart(Client *c, const Seperator *sep);
|
||||
void bot_command_escape(Client *c, const Seperator *sep);
|
||||
void bot_command_find_aliases(Client *c, const Seperator *sep);
|
||||
void bot_command_follow(Client *c, const Seperator *sep);
|
||||
void bot_command_guard(Client *c, const Seperator *sep);
|
||||
void bot_command_heal_rotation(Client *c, const Seperator *sep);
|
||||
void bot_command_help(Client *c, const Seperator *sep);
|
||||
void bot_command_hold(Client *c, const Seperator *sep);
|
||||
void bot_command_identify(Client *c, const Seperator *sep);
|
||||
void bot_command_inventory(Client *c, const Seperator *sep);
|
||||
void bot_command_invisibility(Client *c, const Seperator *sep);
|
||||
void bot_command_levitation(Client *c, const Seperator *sep);
|
||||
void bot_command_lull(Client *c, const Seperator *sep);
|
||||
void bot_command_mesmerize(Client *c, const Seperator *sep);
|
||||
void bot_command_movement_speed(Client *c, const Seperator *sep);
|
||||
void bot_command_pet(Client *c, const Seperator *sep);
|
||||
void bot_command_pick_lock(Client *c, const Seperator *sep);
|
||||
void bot_command_pull(Client *c, const Seperator *sep);
|
||||
void bot_command_release(Client *c, const Seperator *sep);
|
||||
void bot_command_resistance(Client *c, const Seperator *sep);
|
||||
void bot_command_resurrect(Client *c, const Seperator *sep);
|
||||
void bot_command_rune(Client *c, const Seperator *sep);
|
||||
void bot_command_send_home(Client *c, const Seperator *sep);
|
||||
void bot_command_size(Client *c, const Seperator *sep);
|
||||
void bot_command_summon_corpse(Client *c, const Seperator *sep);
|
||||
void bot_command_taunt(Client *c, const Seperator *sep);
|
||||
void bot_command_track(Client *c, const Seperator *sep);
|
||||
void bot_command_water_breathing(Client *c, const Seperator *sep);
|
||||
|
||||
|
||||
// bot subcommands
|
||||
void bot_subcommand_bot_appearance(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_beard_color(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_beard_style(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_camp(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_clone(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_create(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_delete(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_details(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_dye_armor(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_eyes(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_face(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_follow_distance(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_hair_color(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_hairstyle(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_heritage(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_inspect_message(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_list(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_out_of_combat(Client *c, const Seperator *sep);
|
||||
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_summon(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_bot_tattoo(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);
|
||||
void bot_subcommand_bot_woad(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_botgroup_add_member(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_botgroup_create(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_botgroup_delete(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_botgroup_list(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_botgroup_load(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_botgroup_remove_member(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_circle(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_evacuate(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_heal_rotation_adaptive_targeting(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_heal_rotation_add_member(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_heal_rotation_add_target(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_heal_rotation_adjust_critical(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_heal_rotation_adjust_safe(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_heal_rotation_casting_override(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_heal_rotation_change_interval(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_heal_rotation_clear_targets(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_heal_rotation_create(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_heal_rotation_fast_heals(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_heal_rotation_list(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_heal_rotation_remove_member(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_heal_rotation_remove_target(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_heal_rotation_reset_limits(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_heal_rotation_start(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_heal_rotation_stop(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_inventory_give(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_inventory_list(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_inventory_remove(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_pet_remove(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_pet_set_type(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_portal(Client *c, const Seperator *sep);
|
||||
void bot_subcommand_succor(Client *c, const Seperator *sep);
|
||||
|
||||
|
||||
// bot command helpers
|
||||
bool helper_bot_appearance_fail(Client *bot_owner, Bot *my_bot, BCEnum::AFType fail_type, const char* type_desc);
|
||||
void helper_bot_appearance_form_final(Client *bot_owner, Bot *my_bot);
|
||||
void helper_bot_appearance_form_update(Bot *my_bot);
|
||||
uint32 helper_bot_create(Client *bot_owner, std::string bot_name, uint8 bot_class, uint16 bot_race, uint8 bot_gender);
|
||||
void helper_bot_out_of_combat(Client *bot_owner, Bot *my_bot);
|
||||
bool helper_cast_standard_spell(Bot* casting_bot, Mob* target_mob, int spell_id, bool annouce_cast = true, uint32* dont_root_before = nullptr);
|
||||
bool helper_command_alias_fail(Client *bot_owner, const char* command_handler, const char *alias, const char *command);
|
||||
void helper_command_depart_list(Client* bot_owner, Bot* druid_bot, Bot* wizard_bot, bcst_list* local_list, bool single_flag = false);
|
||||
bool helper_is_help_or_usage(const char* arg);
|
||||
bool helper_no_available_bots(Client *bot_owner, Bot *my_bot = nullptr);
|
||||
void helper_send_available_subcommands(Client *bot_owner, const char* command_simile, const std::list<const char*>& subcommand_list);
|
||||
void helper_send_usage_required_bots(Client *bot_owner, BCEnum::SpType spell_type, uint8 bot_class = 0);
|
||||
bool helper_spell_check_fail(STBaseEntry* local_entry);
|
||||
bool helper_spell_list_fail(Client *bot_owner, bcst_list* spell_list, BCEnum::SpType spell_type);
|
||||
#endif
|
||||
732
zone/bot_database.cpp
Normal file
732
zone/bot_database.cpp
Normal file
@ -0,0 +1,732 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
#include "../common/global_define.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
|
||||
#include "bot_database.h"
|
||||
#include "bot.h"
|
||||
|
||||
BotDatabase botdb;
|
||||
|
||||
|
||||
BotDatabase::BotDatabase()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
BotDatabase::BotDatabase(const char* host, const char* user, const char* passwd, const char* database, uint32 port)
|
||||
{
|
||||
Connect(host, user, passwd, database, port);
|
||||
}
|
||||
|
||||
BotDatabase::~BotDatabase()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool BotDatabase::Connect(const char* host, const char* user, const char* passwd, const char* database, uint32 port) {
|
||||
uint32 errnum = 0;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
if (!Open(host, user, passwd, database, port, &errnum, errbuf)) {
|
||||
Log.Out(Logs::General, Logs::Error, "Failed to connect to bot database: Error: %s", errbuf);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
Log.Out(Logs::General, Logs::Status, "Using bot database '%s' at %s:%d", database, host, port);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool BotDatabase::GetCommandSettings(std::map<std::string, std::pair<uint8, std::vector<std::string>>> &bot_command_settings)
|
||||
{
|
||||
bot_command_settings.clear();
|
||||
|
||||
std::string query = "SELECT `bot_command`, `access`, `aliases` FROM `bot_command_settings`";
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return false;
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
bot_command_settings[row[0]].first = atoi(row[1]);
|
||||
if (row[2][0] == 0)
|
||||
continue;
|
||||
|
||||
auto aliases = SplitString(row[2], '|');
|
||||
for (auto iter : aliases) {
|
||||
if (!iter.empty())
|
||||
bot_command_settings[row[0]].second.push_back(iter);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Bot command functions
|
||||
bool BotDatabase::GetInspectMessage(uint32 bot_id, InspectMessage_Struct* message)
|
||||
{
|
||||
std::string query = StringFormat("SELECT `inspect_message` FROM `bot_inspect_messages` WHERE `bot_id` = %i LIMIT 1", bot_id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return false;
|
||||
|
||||
auto row = results.begin();
|
||||
memset(message, '\0', sizeof(InspectMessage_Struct));
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
memcpy(message, row[0], sizeof(InspectMessage_Struct));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BotDatabase::SetInspectMessage(uint32 bot_id, const InspectMessage_Struct* message)
|
||||
{
|
||||
std::string query = StringFormat("REPLACE INTO `bot_inspect_messages` (bot_id, inspect_message) VALUES (%u, '%s')", bot_id, EscapeString(message->text).c_str());
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
return results.Success();
|
||||
}
|
||||
|
||||
bool BotDatabase::SetAllInspectMessages(uint32 owner_id, const InspectMessage_Struct* message)
|
||||
{
|
||||
std::string query = StringFormat(
|
||||
"UPDATE `bot_inspect_messages`"
|
||||
" SET `inspect_message` = '%s'"
|
||||
" WHERE `bot_id`"
|
||||
" IN (SELECT `bot_id` FROM `bot_data` WHERE `owner_id` = '%u')",
|
||||
EscapeString(message->text).c_str(), owner_id
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
return results.Success();
|
||||
}
|
||||
|
||||
bool BotDatabase::SetAllArmorColorBySlot(uint32 owner_id, int16 slot_id, uint32 rgb_value)
|
||||
{
|
||||
if (!owner_id)
|
||||
return false;
|
||||
|
||||
std::string query = StringFormat(
|
||||
"UPDATE `bot_inventories` bi"
|
||||
" INNER JOIN `bot_data` bd"
|
||||
" ON bd.`owner_id` = '%u'"
|
||||
" SET bi.`inst_color` = '%u'"
|
||||
" WHERE bi.`bot_id` = bd.`bot_id`"
|
||||
" AND bi.`slot_id` IN (%u, %u, %u, %u, %u, %u, %u, %u)"
|
||||
" AND bi.`slot_id` = '%i'",
|
||||
owner_id,
|
||||
rgb_value,
|
||||
MainHead, MainChest, MainArms, MainWrist1, MainWrist2, MainHands, MainLegs, MainFeet,
|
||||
slot_id
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
return results.Success();
|
||||
}
|
||||
|
||||
bool BotDatabase::SetAllArmorColors(uint32 owner_id, uint32 rgb_value)
|
||||
{
|
||||
if (!owner_id)
|
||||
return false;
|
||||
|
||||
std::string query = StringFormat(
|
||||
"UPDATE `bot_inventories` bi"
|
||||
" INNER JOIN `bot_data` bd"
|
||||
" ON bd.`owner_id` = '%u'"
|
||||
" SET bi.`inst_color` = '%u'"
|
||||
" WHERE bi.`bot_id` = bd.`bot_id`"
|
||||
" AND bi.`slot_id` IN (%u, %u, %u, %u, %u, %u, %u, %u)",
|
||||
owner_id,
|
||||
rgb_value,
|
||||
MainHead, MainChest, MainArms, MainWrist1, MainWrist2, MainHands, MainLegs, MainFeet
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
return results.Success();
|
||||
}
|
||||
|
||||
bool BotDatabase::SetHelmAppearance(uint32 owner_id, uint32 bot_id, bool show_flag)
|
||||
{
|
||||
if (!owner_id || !bot_id)
|
||||
return false;
|
||||
|
||||
std::string query = StringFormat(
|
||||
"UPDATE `bot_data`"
|
||||
" SET `show_helm` = '%u'"
|
||||
" WHERE `owner_id` = '%u'"
|
||||
" AND `bot_id` = '%u'",
|
||||
(show_flag ? 1 : 0),
|
||||
owner_id,
|
||||
bot_id
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
return results.Success();
|
||||
}
|
||||
|
||||
bool BotDatabase::SetAllHelmAppearances(uint32 owner_id, bool show_flag)
|
||||
{
|
||||
if (!owner_id)
|
||||
return false;
|
||||
|
||||
std::string query = StringFormat(
|
||||
"UPDATE `bot_data`"
|
||||
" SET `show_helm` = '%u'"
|
||||
" WHERE `owner_id` = '%u'",
|
||||
(show_flag ? 1 : 0),
|
||||
owner_id
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
return results.Success();
|
||||
}
|
||||
|
||||
bool BotDatabase::ToggleHelmAppearance(uint32 owner_id, uint32 bot_id)
|
||||
{
|
||||
if (!owner_id || !bot_id)
|
||||
return false;
|
||||
|
||||
std::string query = StringFormat(
|
||||
"UPDATE `bot_data`"
|
||||
" SET `show_helm` = (`show_helm` XOR '1')"
|
||||
" WHERE `owner_id` = '%u'"
|
||||
" AND `bot_id` = '%u'",
|
||||
owner_id,
|
||||
bot_id
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
return results.Success();
|
||||
}
|
||||
|
||||
bool BotDatabase::ToggleAllHelmAppearances(uint32 owner_id)
|
||||
{
|
||||
if (!owner_id)
|
||||
return false;
|
||||
|
||||
std::string query = StringFormat(
|
||||
"UPDATE `bot_data`"
|
||||
" SET `show_helm` = (`show_helm` XOR '1')"
|
||||
" WHERE `owner_id` = '%u'",
|
||||
owner_id
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
return results.Success();
|
||||
}
|
||||
|
||||
bool BotDatabase::SetFollowDistance(uint32 owner_id, uint32 bot_id, uint32 follow_distance)
|
||||
{
|
||||
if (!owner_id || !bot_id || !follow_distance)
|
||||
return false;
|
||||
|
||||
std::string query = StringFormat(
|
||||
"UPDATE `bot_data`"
|
||||
" SET `follow_distance` = '%u'"
|
||||
" WHERE `owner_id` = '%u'"
|
||||
" AND `bot_id` = '%u'",
|
||||
follow_distance,
|
||||
owner_id,
|
||||
bot_id
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
return results.Success();
|
||||
}
|
||||
|
||||
bool BotDatabase::SetAllFollowDistances(uint32 owner_id, uint32 follow_distance)
|
||||
{
|
||||
if (!owner_id || !follow_distance)
|
||||
return false;
|
||||
|
||||
std::string query = StringFormat(
|
||||
"UPDATE `bot_data`"
|
||||
" SET `follow_distance` = '%u'"
|
||||
" WHERE `owner_id` = '%u'",
|
||||
follow_distance,
|
||||
owner_id
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
return results.Success();
|
||||
}
|
||||
|
||||
uint32 BotDatabase::Clone(uint32 owner_id, uint32 bot_id, const char* clone_name)
|
||||
{
|
||||
if (!owner_id || !bot_id || !clone_name)
|
||||
return 0;
|
||||
|
||||
std::string data_query = StringFormat(
|
||||
"INSERT INTO `bot_data`"
|
||||
" ("
|
||||
"`owner_id`,"
|
||||
" `spells_id`,"
|
||||
" `name`,"
|
||||
" `last_name`,"
|
||||
" `title`,"
|
||||
" `suffix`,"
|
||||
" `zone_id`,"
|
||||
" `gender`,"
|
||||
" `race`,"
|
||||
" `class`,"
|
||||
" `level`,"
|
||||
" `deity`,"
|
||||
" `creation_day`,"
|
||||
" `last_spawn`,"
|
||||
" `time_spawned`,"
|
||||
" `size`,"
|
||||
" `face`,"
|
||||
" `hair_color`,"
|
||||
" `hair_style`,"
|
||||
" `beard`,"
|
||||
" `beard_color`,"
|
||||
" `eye_color_1`,"
|
||||
" `eye_color_2`,"
|
||||
" `drakkin_heritage`,"
|
||||
" `drakkin_tattoo`,"
|
||||
" `drakkin_details`,"
|
||||
" `ac`,"
|
||||
" `atk`,"
|
||||
" `hp`,"
|
||||
" `mana`,"
|
||||
" `str`,"
|
||||
" `sta`,"
|
||||
" `cha`,"
|
||||
" `dex`,"
|
||||
" `int`,"
|
||||
" `agi`,"
|
||||
" `wis`,"
|
||||
" `fire`,"
|
||||
" `cold`,"
|
||||
" `magic`,"
|
||||
" `poison`,"
|
||||
" `disease`,"
|
||||
" `corruption`,"
|
||||
" `show_helm`,"
|
||||
" `follow_distance`"
|
||||
")"
|
||||
" SELECT"
|
||||
" bd.`owner_id`,"
|
||||
" bd.`spells_id`,"
|
||||
" '%s',"
|
||||
" '',"
|
||||
" bd.`title`,"
|
||||
" bd.`suffix`,"
|
||||
" bd.`zone_id`,"
|
||||
" bd.`gender`,"
|
||||
" bd.`race`,"
|
||||
" bd.`class`,"
|
||||
" bd.`level`,"
|
||||
" bd.`deity`,"
|
||||
" UNIX_TIMESTAMP(),"
|
||||
" UNIX_TIMESTAMP(),"
|
||||
" '0',"
|
||||
" bd.`size`,"
|
||||
" bd.`face`,"
|
||||
" bd.`hair_color`,"
|
||||
" bd.`hair_style`,"
|
||||
" bd.`beard`,"
|
||||
" bd.`beard_color`,"
|
||||
" bd.`eye_color_1`,"
|
||||
" bd.`eye_color_2`,"
|
||||
" bd.`drakkin_heritage`,"
|
||||
" bd.`drakkin_tattoo`,"
|
||||
" bd.`drakkin_details`,"
|
||||
" bd.`ac`,"
|
||||
" bd.`atk`,"
|
||||
" bd.`hp`,"
|
||||
" bd.`mana`,"
|
||||
" bd.`str`,"
|
||||
" bd.`sta`,"
|
||||
" bd.`cha`,"
|
||||
" bd.`dex`,"
|
||||
" bd.`int`,"
|
||||
" bd.`agi`,"
|
||||
" bd.`wis`,"
|
||||
" bd.`fire`,"
|
||||
" bd.`cold`,"
|
||||
" bd.`magic`,"
|
||||
" bd.`poison`,"
|
||||
" bd.`disease`,"
|
||||
" bd.`corruption`,"
|
||||
" bd.`show_helm`,"
|
||||
" bd.`follow_distance`"
|
||||
" FROM `bot_data` bd"
|
||||
" WHERE"
|
||||
" bd.`owner_id` = '%u'"
|
||||
" AND"
|
||||
" bd.`bot_id` = '%u'",
|
||||
clone_name,
|
||||
owner_id,
|
||||
bot_id
|
||||
);
|
||||
auto results = QueryDatabase(data_query);
|
||||
if (!results.Success())
|
||||
return 0;
|
||||
|
||||
return results.LastInsertedID();
|
||||
}
|
||||
|
||||
bool BotDatabase::CloneInventory(uint32 owner_id, uint32 bot_id, uint32 clone_id)
|
||||
{
|
||||
if (!owner_id || !bot_id || !clone_id)
|
||||
return false;
|
||||
|
||||
std::string inv_query = StringFormat(
|
||||
"INSERT INTO `bot_inventories`"
|
||||
" ("
|
||||
"bot_id,"
|
||||
" `slot_id`,"
|
||||
" `item_id`,"
|
||||
" `inst_charges`,"
|
||||
" `inst_color`,"
|
||||
" `inst_no_drop`,"
|
||||
" `inst_custom_data`,"
|
||||
" `ornament_icon`,"
|
||||
" `ornament_id_file`,"
|
||||
" `ornament_hero_model`,"
|
||||
" `augment_1`,"
|
||||
" `augment_2`,"
|
||||
" `augment_3`,"
|
||||
" `augment_4`,"
|
||||
" `augment_5`,"
|
||||
" `augment_6`"
|
||||
")"
|
||||
" SELECT"
|
||||
" '%u' bot_id,"
|
||||
" bi.`slot_id`,"
|
||||
" bi.`item_id`,"
|
||||
" bi.`inst_charges`,"
|
||||
" bi.`inst_color`,"
|
||||
" bi.`inst_no_drop`,"
|
||||
" bi.`inst_custom_data`,"
|
||||
" bi.`ornament_icon`,"
|
||||
" bi.`ornament_id_file`,"
|
||||
" bi.`ornament_hero_model`,"
|
||||
" bi.`augment_1`,"
|
||||
" bi.`augment_2`,"
|
||||
" bi.`augment_3`,"
|
||||
" bi.`augment_4`,"
|
||||
" bi.`augment_5`,"
|
||||
" bi.`augment_6`"
|
||||
" FROM `bot_inventories` bi"
|
||||
" WHERE"
|
||||
" bi.`bot_id` = '%u'"
|
||||
" AND"
|
||||
" '%u' = (SELECT `owner_id` FROM `bot_data` WHERE `bot_id` = '%u')",
|
||||
clone_id,
|
||||
bot_id,
|
||||
owner_id,
|
||||
bot_id
|
||||
);
|
||||
auto results = QueryDatabase(inv_query);
|
||||
|
||||
return results.Success();
|
||||
}
|
||||
|
||||
|
||||
// Bot-group functions
|
||||
bool BotDatabase::DoesBotGroupExist(std::string& group_name)
|
||||
{
|
||||
if (group_name.empty())
|
||||
return false;
|
||||
|
||||
std::string query = StringFormat("SELECT `group_name` FROM `vw_bot_groups` WHERE `group_name` LIKE '%s' LIMIT 1", group_name.c_str());
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success() || results.RowCount() == 0)
|
||||
return false;
|
||||
|
||||
auto row = results.begin();
|
||||
if (!group_name.compare(row[0]))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 BotDatabase::GetGroupIDByGroupName(std::string& group_name, std::string& error_message)
|
||||
{
|
||||
if (group_name.empty())
|
||||
return 0;
|
||||
|
||||
std::string query = StringFormat("SELECT `groups_index` FROM `bot_groups` WHERE `group_name` = '%s'", group_name.c_str());
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success() || !results.RowCount()) {
|
||||
error_message = results.ErrorMessage();
|
||||
return 0;
|
||||
}
|
||||
auto row = results.begin();
|
||||
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
uint32 BotDatabase::GetLeaderIDByGroupName(std::string& group_name, std::string& error_message)
|
||||
{
|
||||
if (group_name.empty())
|
||||
return 0;
|
||||
|
||||
std::string query = StringFormat("SELECT `group_leader_id` FROM `bot_groups` WHERE `group_name` = '%s'", group_name.c_str());
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success() || !results.RowCount()) {
|
||||
error_message = results.ErrorMessage();
|
||||
return 0;
|
||||
}
|
||||
auto row = results.begin();
|
||||
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
std::string BotDatabase::GetGroupNameByGroupID(uint32 group_id, std::string& error_message)
|
||||
{
|
||||
if (!group_id)
|
||||
return std::string();
|
||||
|
||||
std::string query = StringFormat("SELECT `group_name` FROM `bot_groups` WHERE `groups_index` = '%u'", group_id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success() || !results.RowCount()) {
|
||||
error_message = results.ErrorMessage();
|
||||
return std::string();
|
||||
}
|
||||
auto row = results.begin();
|
||||
|
||||
return std::string(row[0]);
|
||||
}
|
||||
|
||||
std::string BotDatabase::GetGroupNameByLeaderID(uint32 leader_id, std::string& error_message)
|
||||
{
|
||||
if (!leader_id)
|
||||
return std::string();
|
||||
|
||||
std::string query = StringFormat("SELECT `group_name` FROM `bot_groups` WHERE `group_leader_id` = '%u'", leader_id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success() || !results.RowCount()) {
|
||||
error_message = results.ErrorMessage();
|
||||
return std::string();
|
||||
}
|
||||
auto row = results.begin();
|
||||
|
||||
return std::string(row[0]);
|
||||
}
|
||||
|
||||
uint32 BotDatabase::GetGroupIDByLeaderID(uint32 leader_id, std::string& error_message)
|
||||
{
|
||||
if (!leader_id)
|
||||
return 0;
|
||||
|
||||
std::string query = StringFormat("SELECT `groups_index` FROM `bot_groups` WHERE `group_leader_id` = '%u'", leader_id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success() || !results.RowCount()) {
|
||||
error_message = results.ErrorMessage();
|
||||
return 0;
|
||||
}
|
||||
auto row = results.begin();
|
||||
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
uint32 BotDatabase::GetLeaderIDByGroupID(uint32 group_id, std::string& error_message)
|
||||
{
|
||||
if (!group_id)
|
||||
return 0;
|
||||
|
||||
std::string query = StringFormat("SELECT `group_leader_id` FROM `bot_groups` WHERE `groups_index` = '%u'", group_id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success() || !results.RowCount()) {
|
||||
error_message = results.ErrorMessage();
|
||||
return 0;
|
||||
}
|
||||
auto row = results.begin();
|
||||
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
uint32 BotDatabase::GetGroupIDByMemberID(uint32 member_id, std::string& error_message)
|
||||
{
|
||||
if (!member_id)
|
||||
return 0;
|
||||
|
||||
std::string query = StringFormat("SELECT `groups_index` FROM `bot_group_members` WHERE `bot_id` = '%u'", member_id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success() || !results.RowCount()) {
|
||||
error_message = results.ErrorMessage();
|
||||
return 0;
|
||||
}
|
||||
auto row = results.begin();
|
||||
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
bool BotDatabase::CreateBotGroup(std::string& group_name, uint32 leader_id, std::string& error_message)
|
||||
{
|
||||
if (group_name.empty() || !leader_id)
|
||||
return false;
|
||||
|
||||
if (DoesBotGroupExist(group_name))
|
||||
return false;
|
||||
|
||||
std::string query = StringFormat("INSERT INTO `bot_groups` (`group_leader_id`, `group_name`) VALUES ('%u', '%s')", leader_id, group_name.c_str());
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
error_message = results.ErrorMessage();
|
||||
return false;
|
||||
}
|
||||
|
||||
auto group_id = results.LastInsertedID();
|
||||
if (!group_id)
|
||||
return false;
|
||||
|
||||
query = StringFormat("INSERT INTO `bot_group_members` (`groups_index`, `bot_id`) VALUES ('%u', '%u')", group_id, leader_id);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
error_message = results.ErrorMessage();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BotDatabase::DeleteBotGroup(uint32 leader_id, std::string& error_message)
|
||||
{
|
||||
if (!leader_id)
|
||||
return false;
|
||||
|
||||
uint32 group_id = GetGroupIDByLeaderID(leader_id, error_message);
|
||||
if (!group_id || !error_message.empty())
|
||||
return false;
|
||||
|
||||
std::string query = StringFormat("DELETE FROM `bot_group_members` WHERE `groups_index` = '%u'", group_id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
error_message = results.ErrorMessage();
|
||||
return false;
|
||||
}
|
||||
|
||||
query = StringFormat("DELETE FROM `bot_groups` WHERE `groups_index` = '%u'", group_id);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
error_message = results.ErrorMessage();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BotDatabase::AddMemberToBotGroup(uint32 leader_id, uint32 member_id, std::string& error_message)
|
||||
{
|
||||
if (!leader_id || !member_id)
|
||||
return false;
|
||||
|
||||
uint32 group_id = GetGroupIDByLeaderID(leader_id, error_message);
|
||||
if (!group_id || !error_message.empty())
|
||||
return false;
|
||||
|
||||
std::string query = StringFormat("INSERT INTO `bot_group_members` (`groups_index`, `bot_id`) VALUES ('%u', '%u')", group_id, member_id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
error_message = results.ErrorMessage();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BotDatabase::RemoveMemberFromBotGroup(uint32 member_id, std::string& error_message)
|
||||
{
|
||||
if (!member_id)
|
||||
return false;
|
||||
|
||||
if (GetGroupIDByLeaderID(member_id, error_message))
|
||||
return DeleteBotGroup(member_id, error_message);
|
||||
|
||||
if (!error_message.empty())
|
||||
return false;
|
||||
|
||||
std::string query = StringFormat("DELETE FROM `bot_group_members` WHERE `bot_id` = '%u'", member_id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
error_message = results.ErrorMessage();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 BotDatabase::GetGroupIDForLoadGroup(uint32 owner_id, std::string& group_name, std::string& error_message)
|
||||
{
|
||||
if (!owner_id || group_name.empty())
|
||||
return 0;
|
||||
|
||||
std::string query = StringFormat("SELECT `groups_index`, `group_name` FROM `vw_bot_groups` WHERE `owner_id` = '%u'", owner_id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success() || !results.RowCount()) {
|
||||
error_message = results.ErrorMessage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
if (!group_name.compare(row[1]))
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::map<uint32, std::list<uint32>> BotDatabase::LoadGroup(std::string& group_name, std::string& error_message)
|
||||
{
|
||||
std::map<uint32, std::list<uint32>> group_list;
|
||||
if (group_name.empty())
|
||||
return group_list;
|
||||
|
||||
uint32 group_id = GetGroupIDByGroupName(group_name, error_message);
|
||||
if (!group_id || !error_message.empty())
|
||||
return group_list;
|
||||
|
||||
std::string query = StringFormat("SELECT `bot_id` FROM `bot_group_members` WHERE `groups_index` = '%u'", group_id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
error_message = results.ErrorMessage();
|
||||
return group_list;
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
group_list[group_id].push_back(atoi(row[0]));
|
||||
|
||||
return group_list;
|
||||
}
|
||||
|
||||
std::list<std::pair<std::string, std::string>> BotDatabase::GetGroupsListByOwnerID(uint32 owner_id, std::string& error_message)
|
||||
{
|
||||
std::list<std::pair<std::string, std::string>> groups_list;
|
||||
if (!owner_id)
|
||||
return groups_list;
|
||||
|
||||
std::string query = StringFormat("SELECT `group_name`, `group_leader_name` FROM `vw_bot_groups` WHERE `owner_id` = '%u'", owner_id);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
error_message = results.ErrorMessage();
|
||||
return groups_list;
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
groups_list.push_back(std::pair<std::string, std::string>(row[0], row[1]));
|
||||
|
||||
return groups_list;
|
||||
}
|
||||
87
zone/bot_database.h
Normal file
87
zone/bot_database.h
Normal file
@ -0,0 +1,87 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BOT_DATABASE_H
|
||||
#define BOT_DATABASE_H
|
||||
|
||||
#include "../common/dbcore.h"
|
||||
#include "../common/eq_packet_structs.h"
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
class BotDatabase : public DBcore
|
||||
{
|
||||
|
||||
public:
|
||||
BotDatabase();
|
||||
BotDatabase(const char* host, const char* user, const char* passwd, const char* database, uint32 port);
|
||||
virtual ~BotDatabase();
|
||||
|
||||
bool Connect(const char* host, const char* user, const char* passwd, const char* database, uint32 port);
|
||||
|
||||
bool GetCommandSettings(std::map<std::string, std::pair<uint8, std::vector<std::string>>> &bot_command_settings);
|
||||
|
||||
// Bot command functions
|
||||
bool GetInspectMessage(uint32 bot_id, InspectMessage_Struct* message);
|
||||
bool SetInspectMessage(uint32 bot_id, const InspectMessage_Struct* message);
|
||||
bool SetAllInspectMessages(uint32 owner_id, const InspectMessage_Struct* message);
|
||||
|
||||
bool SetAllArmorColorBySlot(uint32 owner_id, int16 slot_id, uint32 rgb_value);
|
||||
bool SetAllArmorColors(uint32 owner_id, uint32 rgb_value);
|
||||
|
||||
bool SetHelmAppearance(uint32 owner_id, uint32 bot_id, bool show_flag = true);
|
||||
bool SetAllHelmAppearances(uint32 owner_id, bool show_flag = true);
|
||||
|
||||
bool ToggleHelmAppearance(uint32 owner_id, uint32 bot_id);
|
||||
bool ToggleAllHelmAppearances(uint32 owner_id);
|
||||
|
||||
bool SetFollowDistance(uint32 owner_id, uint32 bot_id, uint32 follow_distance);
|
||||
bool SetAllFollowDistances(uint32 owner_id, uint32 follow_distance);
|
||||
|
||||
uint32 Clone(uint32 owner_id, uint32 bot_id, const char* clone_name);
|
||||
bool CloneInventory(uint32 owner_id, uint32 bot_id, uint32 clone_id);
|
||||
|
||||
// Bot-group functions
|
||||
bool DoesBotGroupExist(std::string& group_name);
|
||||
|
||||
uint32 GetGroupIDByGroupName(std::string& group_name, std::string& error_message);
|
||||
uint32 GetLeaderIDByGroupName(std::string& group_name, std::string& error_message);
|
||||
std::string GetGroupNameByGroupID(uint32 group_id, std::string& error_message);
|
||||
std::string GetGroupNameByLeaderID(uint32 leader_id, std::string& error_message);
|
||||
uint32 GetGroupIDByLeaderID(uint32 leader_id, std::string& error_message);
|
||||
uint32 GetLeaderIDByGroupID(uint32 group_id, std::string& error_message);
|
||||
|
||||
uint32 GetGroupIDByMemberID(uint32 member_id, std::string& error_message);
|
||||
|
||||
bool CreateBotGroup(std::string& group_name, uint32 leader_id, std::string& error_message);
|
||||
bool DeleteBotGroup(uint32 leader_id, std::string& error_message);
|
||||
bool AddMemberToBotGroup(uint32 leader_id, uint32 member_id, std::string& error_message);
|
||||
bool RemoveMemberFromBotGroup(uint32 member_id, std::string& error_message);
|
||||
|
||||
uint32 GetGroupIDForLoadGroup(uint32 owner_id, std::string& group_name, std::string& error_message);
|
||||
std::map<uint32, std::list<uint32>> LoadGroup(std::string& group_name, std::string& error_message);
|
||||
|
||||
std::list<std::pair<std::string, std::string>> GetGroupsListByOwnerID(uint32 owner_id, std::string& error_message);
|
||||
};
|
||||
|
||||
extern BotDatabase botdb;
|
||||
|
||||
#endif
|
||||
@ -1,3 +1,21 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef BOT_STRUCTS
|
||||
#define BOT_STRUCTS
|
||||
|
||||
@ -13,6 +31,7 @@ struct BotsAvailableList {
|
||||
uint16 BotClass;
|
||||
uint8 BotLevel;
|
||||
uint16 BotRace;
|
||||
uint8 BotGender;
|
||||
};
|
||||
|
||||
struct BotGroup {
|
||||
|
||||
@ -1,3 +1,21 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef BOTS
|
||||
|
||||
#include "bot.h"
|
||||
@ -1025,7 +1043,7 @@ bool Bot::AI_IdleCastCheck() {
|
||||
// bard bots
|
||||
if(!AICastSpell(this, 100, SpellType_Cure)) {
|
||||
if(!AICastSpell(this, 100, SpellType_Heal)) {
|
||||
if((!RuleB(Bots, BotBardUseOutOfCombatSongs) || !GetBardUseOutOfCombatSongs()) || !AICastSpell(this, 100, SpellType_Buff)) { // skips if rule is false
|
||||
if((!RuleB(Bots, BotBardUseOutOfCombatSongs) || !GetAltOutOfCombatBehavior()) || !AICastSpell(this, 100, SpellType_Buff)) { // skips if rule is false
|
||||
if(!AICastSpell(this, 100, SpellType_InCombatBuff)) { // this tries to keep some combat buffs on the group until engaged code can pick up the buffing
|
||||
//
|
||||
}
|
||||
@ -1261,7 +1279,7 @@ bool Bot::AIHealRotation(Mob* tar, bool useFastHeals) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!AI_HasSpells())
|
||||
if (!AI_HasSpells())
|
||||
return false;
|
||||
|
||||
if(tar->GetAppearance() == eaDead) {
|
||||
@ -1303,11 +1321,11 @@ bool Bot::AIHealRotation(Mob* tar, bool useFastHeals) {
|
||||
}
|
||||
|
||||
// If there is still no spell id, then there isn't going to be one so we are done
|
||||
if(botSpell.SpellId == 0)
|
||||
if (botSpell.SpellId == 0)
|
||||
return false;
|
||||
|
||||
// Can we cast this spell on this target?
|
||||
if(!(spells[botSpell.SpellId].targettype==ST_GroupTeleport || spells[botSpell.SpellId].targettype == ST_Target || tar == this)
|
||||
if (!(spells[botSpell.SpellId].targettype == ST_GroupTeleport || spells[botSpell.SpellId].targettype == ST_Target || tar == this)
|
||||
&& !(tar->CanBuffStack(botSpell.SpellId, botLevel, true) >= 0))
|
||||
return false;
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.org)
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -44,6 +44,9 @@ extern volatile bool RunLoops;
|
||||
#include "zonedb.h"
|
||||
#include "petitions.h"
|
||||
#include "command.h"
|
||||
#ifdef BOTS
|
||||
#include "bot_command.h"
|
||||
#endif
|
||||
#include "string_ids.h"
|
||||
|
||||
#include "guild_mgr.h"
|
||||
@ -1046,6 +1049,24 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef BOTS
|
||||
if (message[0] == BOT_COMMAND_CHAR) {
|
||||
if (bot_command_dispatch(this, message) == -2) {
|
||||
if (parse->PlayerHasQuestSub(EVENT_COMMAND)) {
|
||||
int i = parse->EventPlayer(EVENT_COMMAND, this, message, 0);
|
||||
if (i == 0 && !RuleB(Chat, SuppressCommandErrors)) {
|
||||
Message(13, "Bot command '%s' not recognized.", message);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!RuleB(Chat, SuppressCommandErrors))
|
||||
Message(13, "Bot command '%s' not recognized.", message);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
Mob* sender = this;
|
||||
if (GetPet() && GetPet()->FindType(SE_VoiceGraft))
|
||||
sender = GetPet();
|
||||
@ -3561,7 +3582,7 @@ void Client::Insight(uint32 t_id)
|
||||
}
|
||||
strcat(resists," to disease.");
|
||||
|
||||
Message(0,"Your target is a level %i %s. It appears %s and %s for its level. It seems %s",who->GetLevel(),GetEQClassName(who->GetClass(),1),dmg,hitpoints,resists);
|
||||
Message(0,"Your target is a level %i %s. It appears %s and %s for its level. It seems %s",who->GetLevel(),GetClassIDName(who->GetClass(),1),dmg,hitpoints,resists);
|
||||
}
|
||||
|
||||
void Client::GetGroupAAs(GroupLeadershipAA_Struct *into) const {
|
||||
@ -7546,9 +7567,14 @@ void Client::GarbleMessage(char *message, uint8 variance)
|
||||
int delimiter_count = 0;
|
||||
|
||||
// Don't garble # commands
|
||||
if (message[0] == '#')
|
||||
if (message[0] == COMMAND_CHAR)
|
||||
return;
|
||||
|
||||
#ifdef BOTS
|
||||
if (message[0] == BOT_COMMAND_CHAR)
|
||||
return;
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i < strlen(message); i++) {
|
||||
// Client expects hex values inside of a text link body
|
||||
if (message[i] == delimiter) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.net)
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -160,7 +160,7 @@ int32 Client::LevelRegen()
|
||||
bool sitting = IsSitting();
|
||||
bool feigned = GetFeigned();
|
||||
int level = GetLevel();
|
||||
bool bonus = GetRaceBitmask(GetBaseRace()) & RuleI(Character, BaseHPRegenBonusRaces);
|
||||
bool bonus = GetPlayerRaceBit(GetBaseRace()) & RuleI(Character, BaseHPRegenBonusRaces);
|
||||
uint8 multiplier1 = bonus ? 2 : 1;
|
||||
int32 hp = 0;
|
||||
//these calculations should match up with the info from Monkly Business, which was last updated ~05/2008: http://www.monkly-business.net/index.php?pageid=abilities
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2009 EQEMu Development Team (http://eqemulator.net)
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -3896,7 +3896,6 @@ 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::BotHealRotationsClear(this);
|
||||
Bot::BotOrderCampAll(this);
|
||||
#endif
|
||||
if (IsLFP())
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemulator.org)
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -86,7 +86,7 @@ void command_pf(Client *c, const Seperator *message);
|
||||
std::map<std::string, CommandRecord *> commandlist;
|
||||
std::map<std::string, std::string> commandaliases;
|
||||
|
||||
//All allocated CommandRecords get put in here so they get deleted on shutdown
|
||||
// All allocated CommandRecords get put in here so they get deleted on shutdown
|
||||
LinkedList<CommandRecord *> cleanup_commandlist;
|
||||
|
||||
/*
|
||||
@ -103,9 +103,9 @@ int command_notavail(Client *c, const char *message)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* the rest below here could be in a dynamically loaded module eventually */
|
||||
/*****************************************************************************/
|
||||
/**************************************************************************
|
||||
/* the rest below here could be in a dynamically loaded module eventually *
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
|
||||
@ -163,7 +163,7 @@ int command_init(void)
|
||||
command_add("bind", "- Sets your targets bind spot to their current location", 200, command_bind) ||
|
||||
|
||||
#ifdef BOTS
|
||||
command_add("bot", "- Type \"#bot help\" to the see the list of available commands for bots.", 0, command_bot) ||
|
||||
command_add("bot", "- Type \"#bot help\" or \"^help\" to the see the list of available commands for bots.", 0, command_bot) ||
|
||||
#endif
|
||||
|
||||
command_add("camerashake", "Shakes the camera on everyone's screen globally.", 80, command_camerashake) ||
|
||||
@ -9665,14 +9665,6 @@ void command_showspellslist(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
|
||||
// All new code added to command.cpp ought to be BEFORE this comment line. Do no append code to this file below the BOTS code block.
|
||||
#ifdef BOTS
|
||||
// Function delegate to support the command interface for Bots with the client.
|
||||
void command_bot(Client *c, const Seperator *sep) {
|
||||
Bot::ProcessBotCommands(c, sep);
|
||||
}
|
||||
#endif
|
||||
|
||||
void command_raidloot(Client *c, const Seperator *sep)
|
||||
{
|
||||
if(!sep->arg[1][0]) {
|
||||
@ -10842,4 +10834,30 @@ void command_reloadperlexportsettings(Client *c, const Seperator *sep)
|
||||
safe_delete(pack);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// All new code added to command.cpp should be BEFORE this comment line. Do no append code to this file below the BOTS code block.
|
||||
#ifdef BOTS
|
||||
#include "bot_command.h"
|
||||
// Function delegate to support the command interface for Bots with the client.
|
||||
void command_bot(Client *c, const Seperator *sep)
|
||||
{
|
||||
std::string bot_message = sep->msg;
|
||||
bot_message = bot_message.substr(bot_message.find_first_not_of("#bot"));
|
||||
bot_message[0] = BOT_COMMAND_CHAR;
|
||||
|
||||
if (bot_command_dispatch(c, bot_message.c_str()) == -2) {
|
||||
if (parse->PlayerHasQuestSub(EVENT_COMMAND)) {
|
||||
int i = parse->EventPlayer(EVENT_COMMAND, c, bot_message, 0);
|
||||
if (i == 0 && !RuleB(Chat, SuppressCommandErrors)) {
|
||||
c->Message(13, "Bot command '%s' not recognized.", bot_message.c_str());
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!RuleB(Chat, SuppressCommandErrors))
|
||||
c->Message(13, "Bot command '%s' not recognized.", bot_message.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -9,11 +9,11 @@
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef EMBPERL
|
||||
@ -1052,8 +1052,8 @@ void PerlembParser::ExportMobVariables(bool isPlayerQuest, bool isGlobalPlayerQu
|
||||
|
||||
if(mob) {
|
||||
ExportVar(package_name.c_str(), "name", mob->GetName());
|
||||
ExportVar(package_name.c_str(), "race", GetRaceName(mob->GetRace()));
|
||||
ExportVar(package_name.c_str(), "class", GetEQClassName(mob->GetClass()));
|
||||
ExportVar(package_name.c_str(), "race", GetRaceIDName(mob->GetRace()));
|
||||
ExportVar(package_name.c_str(), "class", GetClassIDName(mob->GetClass()));
|
||||
ExportVar(package_name.c_str(), "ulevel", mob->GetLevel());
|
||||
ExportVar(package_name.c_str(), "userid", mob->GetID());
|
||||
}
|
||||
|
||||
@ -1,26 +1,30 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.net)
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef EMBPERL
|
||||
|
||||
#include "../common/global_define.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "masterentity.h"
|
||||
#include "command.h"
|
||||
#ifdef BOTS
|
||||
#include "bot_command.h"
|
||||
#endif
|
||||
|
||||
#include "embperl.h"
|
||||
#include "embxs.h"
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.net)
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -466,7 +466,6 @@ private:
|
||||
#ifdef BOTS
|
||||
public:
|
||||
void AddBot(Bot* newBot, bool SendSpawnPacket = true, bool dontqueue = false);
|
||||
void BotPickLock(Bot* rogue);
|
||||
bool RemoveBot(uint16 entityID);
|
||||
Mob* GetMobByBotID(uint32 botID);
|
||||
Bot* GetBotByBotID(uint32 botID);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemu.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -15,6 +15,7 @@
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "../common/global_define.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "masterentity.h"
|
||||
@ -938,6 +939,41 @@ void Group::DisbandGroup() {
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Group::GetMemberList(std::list<Mob*>& member_list, bool clear_list)
|
||||
{
|
||||
if (clear_list)
|
||||
member_list.clear();
|
||||
|
||||
for (auto member_iter : members) {
|
||||
if (member_iter)
|
||||
member_list.push_back(member_iter);
|
||||
}
|
||||
}
|
||||
|
||||
void Group::GetClientList(std::list<Client*>& client_list, bool clear_list)
|
||||
{
|
||||
if (clear_list)
|
||||
client_list.clear();
|
||||
|
||||
for (auto client_iter : members) {
|
||||
if (client_iter && client_iter->IsClient())
|
||||
client_list.push_back(client_iter->CastToClient());
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BOTS
|
||||
void Group::GetBotList(std::list<Bot*>& bot_list, bool clear_list)
|
||||
{
|
||||
if (clear_list)
|
||||
bot_list.clear();
|
||||
|
||||
for (auto bot_iter : members) {
|
||||
if (bot_iter && bot_iter->IsBot())
|
||||
bot_list.push_back(bot_iter->CastToBot());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool Group::Process() {
|
||||
if(disbandcheck && !GroupCount())
|
||||
return false;
|
||||
@ -2294,6 +2330,30 @@ void Group::SetPuller(const char *NewPullerName)
|
||||
}
|
||||
}
|
||||
|
||||
bool Group::AmIMainTank(const char *mob_name)
|
||||
{
|
||||
if (!mob_name)
|
||||
return false;
|
||||
|
||||
return !((bool)MainTankName.compare(mob_name));
|
||||
}
|
||||
|
||||
bool Group::AmIMainAssist(const char *mob_name)
|
||||
{
|
||||
if (!mob_name)
|
||||
return false;
|
||||
|
||||
return !((bool)MainTankName.compare(mob_name));
|
||||
}
|
||||
|
||||
bool Group::AmIPuller(const char *mob_name)
|
||||
{
|
||||
if (!mob_name)
|
||||
return false;
|
||||
|
||||
return !((bool)PullerName.compare(mob_name));
|
||||
}
|
||||
|
||||
bool Group::HasRole(Mob *m, uint8 Role)
|
||||
{
|
||||
if(!m)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemu.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -59,6 +59,11 @@ public:
|
||||
bool DelMemberOOZ(const char *Name);
|
||||
bool DelMember(Mob* oldmember,bool ignoresender = false);
|
||||
void DisbandGroup();
|
||||
void GetMemberList(std::list<Mob*>& member_list, bool clear_list = true);
|
||||
void GetClientList(std::list<Client*>& client_list, bool clear_list = true);
|
||||
#ifdef BOTS
|
||||
void GetBotList(std::list<Bot*>& bot_list, bool clear_list = true);
|
||||
#endif
|
||||
bool IsGroupMember(Mob* client);
|
||||
bool IsGroupMember(const char *Name);
|
||||
bool Process();
|
||||
@ -123,6 +128,9 @@ public:
|
||||
const char *GetMainTankName() { return MainTankName.c_str(); }
|
||||
const char *GetMainAssistName() { return MainAssistName.c_str(); }
|
||||
const char *GetPullerName() { return PullerName.c_str(); }
|
||||
bool AmIMainTank(const char *mob_name);
|
||||
bool AmIMainAssist(const char *mob_name);
|
||||
bool AmIPuller(const char *mob_name);
|
||||
void SetNPCMarker(const char *NewNPCMarkerName);
|
||||
void UnMarkNPC(uint16 ID);
|
||||
void SendMarkedNPCsToMember(Client *c, bool Clear = false);
|
||||
|
||||
882
zone/heal_rotation.cpp
Normal file
882
zone/heal_rotation.cpp
Normal file
@ -0,0 +1,882 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "bot.h"
|
||||
|
||||
#define SAFE_HP_RATIO_CLOTH 95.0f
|
||||
#define SAFE_HP_RATIO_LEATHER 90.0f
|
||||
#define SAFE_HP_RATIO_CHAIN 80.0f
|
||||
#define SAFE_HP_RATIO_PLATE 75.0f
|
||||
|
||||
#define CRITICAL_HP_RATIO_CLOTH 30.0f
|
||||
#define CRITICAL_HP_RATIO_LEATHER 25.0f
|
||||
#define CRITICAL_HP_RATIO_CHAIN 15.0f
|
||||
#define CRITICAL_HP_RATIO_PLATE 10.0f
|
||||
|
||||
HealRotation::HealRotation(Bot* hr_creator, uint32 interval_ms, bool fast_heals, bool adaptive_targeting, bool casting_override)
|
||||
{
|
||||
m_member_pool.push_back(hr_creator);
|
||||
|
||||
m_creation_time_ms = Timer::GetCurrentTime();
|
||||
m_last_heal_time_ms = m_creation_time_ms;
|
||||
m_interval_ms = ((interval_ms >= CASTING_CYCLE_MINIMUM_INTERVAL) ? (interval_ms) : (CASTING_CYCLE_MINIMUM_INTERVAL));
|
||||
m_next_cast_time_ms = m_creation_time_ms;
|
||||
m_next_poke_time_ms = m_creation_time_ms;
|
||||
m_healing_stats_begin_ms = m_creation_time_ms;
|
||||
m_fast_heals = fast_heals;
|
||||
m_adaptive_targeting = adaptive_targeting;
|
||||
m_casting_override = casting_override;
|
||||
m_casting_target_poke = true;
|
||||
m_active_heal_target = false;
|
||||
|
||||
ResetArmorTypeHPLimits();
|
||||
|
||||
m_is_active = false;
|
||||
}
|
||||
|
||||
void HealRotation::SetIntervalMS(uint32 interval_ms)
|
||||
{
|
||||
if (interval_ms > CASTING_CYCLE_MAXIMUM_INTERVAL)
|
||||
interval_ms = CASTING_CYCLE_MAXIMUM_INTERVAL;
|
||||
else if (interval_ms < CASTING_CYCLE_MINIMUM_INTERVAL)
|
||||
interval_ms = CASTING_CYCLE_MINIMUM_INTERVAL;
|
||||
|
||||
m_interval_ms = interval_ms;
|
||||
}
|
||||
|
||||
void HealRotation::SetIntervalS(uint32 interval_s)
|
||||
{
|
||||
interval_s *= 1000;
|
||||
if (interval_s > CASTING_CYCLE_MAXIMUM_INTERVAL)
|
||||
interval_s = CASTING_CYCLE_MAXIMUM_INTERVAL;
|
||||
else if (interval_s < CASTING_CYCLE_MINIMUM_INTERVAL)
|
||||
interval_s = CASTING_CYCLE_MINIMUM_INTERVAL;
|
||||
|
||||
m_interval_ms = interval_s;
|
||||
}
|
||||
|
||||
bool HealRotation::AddMemberToPool(Bot* hr_member)
|
||||
{
|
||||
if (!hr_member)
|
||||
return false;
|
||||
if (!IsMemberClass(hr_member->GetClass()))
|
||||
return false;
|
||||
if (m_member_pool.size() >= RuleI(Bots, HealRotationMaxMembers))
|
||||
return false;
|
||||
|
||||
for (auto find_iter : m_member_pool) {
|
||||
if (find_iter == hr_member)
|
||||
return false;
|
||||
}
|
||||
|
||||
m_member_pool.push_back(hr_member);
|
||||
valid_state();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HealRotation::AddTargetToPool(Mob* hr_target)
|
||||
{
|
||||
if (!hr_target)
|
||||
return false;
|
||||
if (!valid_state())
|
||||
return false;
|
||||
if (!IsTargetMobType(hr_target))
|
||||
return false;
|
||||
if (m_target_pool.size() >= RuleI(Bots, HealRotationMaxTargets))
|
||||
return false;
|
||||
|
||||
for (auto find_iter : m_target_pool) {
|
||||
if (find_iter == hr_target)
|
||||
return false;
|
||||
}
|
||||
|
||||
m_target_pool.push_back(hr_target);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HealRotation::RemoveMemberFromPool(Bot* hr_member)
|
||||
{
|
||||
if (!hr_member)
|
||||
return true;
|
||||
|
||||
for (auto member_iter : m_member_pool) {
|
||||
if (member_iter != hr_member)
|
||||
continue;
|
||||
|
||||
m_member_is_casting.erase(hr_member);
|
||||
m_member_pool.remove(hr_member);
|
||||
valid_state();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HealRotation::RemoveTargetFromPool(Mob* hr_target)
|
||||
{
|
||||
if (!hr_target)
|
||||
return true;
|
||||
if (!valid_state())
|
||||
return true;
|
||||
|
||||
for (auto target_iter : m_target_pool) {
|
||||
if (target_iter != hr_target)
|
||||
continue;
|
||||
|
||||
m_target_healing_stats_2.erase(hr_target);
|
||||
m_target_healing_stats_1.erase(hr_target);
|
||||
m_target_pool.remove(hr_target);
|
||||
m_casting_target_poke = false;
|
||||
bias_targets();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HealRotation::ClearMemberPool()
|
||||
{
|
||||
m_is_active = false;
|
||||
m_cycle_pool.clear();
|
||||
m_casting_target_poke = false;
|
||||
m_active_heal_target = false;
|
||||
|
||||
ClearTargetPool();
|
||||
|
||||
auto clear_list = m_member_pool;
|
||||
for (auto member_iter : clear_list)
|
||||
member_iter->LeaveHealRotationMemberPool();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HealRotation::ClearTargetPool()
|
||||
{
|
||||
m_is_active = false;
|
||||
|
||||
auto clear_list = m_target_pool;
|
||||
for (auto target_iter : clear_list)
|
||||
target_iter->LeaveHealRotationTargetPool();
|
||||
|
||||
m_casting_target_poke = false;
|
||||
bias_targets();
|
||||
|
||||
return m_target_pool.empty();
|
||||
}
|
||||
|
||||
bool HealRotation::Start()
|
||||
{
|
||||
m_is_active = false;
|
||||
if (m_member_pool.empty() || m_target_pool.empty())
|
||||
return false;
|
||||
|
||||
m_cycle_pool = m_member_pool;
|
||||
m_is_active = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HealRotation::Stop()
|
||||
{
|
||||
m_is_active = false;
|
||||
m_active_heal_target = false;
|
||||
m_cycle_pool.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Bot* HealRotation::CastingMember()
|
||||
{
|
||||
if (!m_is_active)
|
||||
return nullptr;
|
||||
|
||||
if (m_cycle_pool.empty()) {
|
||||
cycle_refresh();
|
||||
|
||||
if (m_cycle_pool.empty())
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return m_cycle_pool.front();
|
||||
}
|
||||
|
||||
bool HealRotation::PokeCastingTarget()
|
||||
{
|
||||
if (!m_is_active)
|
||||
return false;
|
||||
|
||||
uint32 current_time = Timer::GetCurrentTime();
|
||||
|
||||
if (current_time < m_next_poke_time_ms) {
|
||||
auto hr_target = CastingTarget();
|
||||
if (hr_target && hr_target->DontHealMeBefore() > current_time)
|
||||
m_next_poke_time_ms = current_time;
|
||||
else
|
||||
return m_active_heal_target;
|
||||
}
|
||||
|
||||
m_next_poke_time_ms = (current_time + POKE_PROPAGATION_DELAY);
|
||||
|
||||
if (m_healing_stats_begin_ms + HEALING_STATS_RESET_INTERVAL <= current_time)
|
||||
StartNewTargetHealingStatsCycle(current_time);
|
||||
|
||||
m_casting_target_poke = false;
|
||||
bias_targets();
|
||||
|
||||
return m_active_heal_target;
|
||||
}
|
||||
|
||||
Mob* HealRotation::CastingTarget()
|
||||
{
|
||||
if (!m_is_active)
|
||||
return nullptr;
|
||||
if (!m_active_heal_target)
|
||||
return nullptr;
|
||||
|
||||
return m_target_pool.front();
|
||||
}
|
||||
|
||||
bool HealRotation::AdvanceRotation(bool use_interval)
|
||||
{
|
||||
m_cycle_pool.pop_front();
|
||||
m_next_cast_time_ms = Timer::GetCurrentTime();
|
||||
if (use_interval) {
|
||||
m_next_poke_time_ms = m_next_cast_time_ms;
|
||||
m_next_cast_time_ms += m_interval_ms;
|
||||
}
|
||||
else {
|
||||
m_next_cast_time_ms += ADVANCE_ROTATION_MINIMUM_INTERVAL;
|
||||
}
|
||||
|
||||
if (m_cycle_pool.empty())
|
||||
cycle_refresh();
|
||||
|
||||
return (!m_cycle_pool.empty());
|
||||
}
|
||||
|
||||
bool HealRotation::IsMemberInPool(Bot* hr_member)
|
||||
{
|
||||
if (!hr_member)
|
||||
return false;
|
||||
if (m_member_pool.empty())
|
||||
return false;
|
||||
|
||||
for (auto find_iter : m_member_pool) {
|
||||
if (find_iter == hr_member)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HealRotation::IsTargetInPool(Mob* hr_target)
|
||||
{
|
||||
if (!hr_target)
|
||||
return false;
|
||||
if (m_target_pool.empty())
|
||||
return false;
|
||||
|
||||
for (auto find_iter : m_target_pool) {
|
||||
if (find_iter == hr_target)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void HealRotation::SetMemberIsCasting(Bot* hr_member, bool flag)
|
||||
{
|
||||
if (!hr_member)
|
||||
return;
|
||||
if (!IsMemberInPool(hr_member))
|
||||
return;
|
||||
|
||||
m_member_is_casting[hr_member] = flag;
|
||||
}
|
||||
|
||||
bool HealRotation::MemberIsCasting(Bot* hr_member)
|
||||
{
|
||||
if (!hr_member)
|
||||
return false;
|
||||
if (m_member_is_casting.find(hr_member) == m_member_is_casting.end())
|
||||
return false;
|
||||
|
||||
return m_member_is_casting[hr_member];
|
||||
}
|
||||
|
||||
void HealRotation::UpdateTargetHealingStats(Mob* hr_target)
|
||||
{
|
||||
if (!hr_target)
|
||||
return;
|
||||
if (!IsTargetInPool(hr_target))
|
||||
return;
|
||||
|
||||
m_last_heal_time_ms = Timer::GetCurrentTime();
|
||||
|
||||
m_target_healing_stats_1[hr_target].last_heal_time_ms = m_last_heal_time_ms;
|
||||
++m_target_healing_stats_1[hr_target].heal_count;
|
||||
}
|
||||
|
||||
void HealRotation::StartNewTargetHealingStatsCycle(uint32 current_time)
|
||||
{
|
||||
m_target_healing_stats_2 = m_target_healing_stats_1;
|
||||
m_target_healing_stats_1.clear();
|
||||
|
||||
m_healing_stats_begin_ms = current_time;
|
||||
}
|
||||
|
||||
uint32 HealRotation::HealCount(Mob* hr_target)
|
||||
{
|
||||
if (!hr_target)
|
||||
return 0;
|
||||
|
||||
uint32 heal_count = 0;
|
||||
if (m_target_healing_stats_1.find(hr_target) != m_target_healing_stats_1.end())
|
||||
heal_count += m_target_healing_stats_1[hr_target].heal_count;
|
||||
|
||||
return heal_count;
|
||||
}
|
||||
|
||||
uint32 HealRotation::ExtendedHealCount(Mob* hr_target)
|
||||
{
|
||||
if (!hr_target)
|
||||
return 0;
|
||||
|
||||
uint32 heal_count = 0;
|
||||
if (m_target_healing_stats_1.find(hr_target) != m_target_healing_stats_1.end())
|
||||
heal_count += m_target_healing_stats_1[hr_target].heal_count;
|
||||
if (m_target_healing_stats_2.find(hr_target) != m_target_healing_stats_2.end())
|
||||
heal_count += m_target_healing_stats_2[hr_target].heal_count;
|
||||
|
||||
return heal_count;
|
||||
}
|
||||
|
||||
float HealRotation::HealFrequency(Mob* hr_target)
|
||||
{
|
||||
if (!hr_target)
|
||||
return 0.0f;
|
||||
|
||||
float time_base = 0;
|
||||
uint32 heal_count = 0;
|
||||
if (m_target_healing_stats_1.find(hr_target) != m_target_healing_stats_1.end()) {
|
||||
heal_count += m_target_healing_stats_1[hr_target].heal_count;
|
||||
time_base = (Timer::GetCurrentTime() - m_target_healing_stats_1[hr_target].last_heal_time_ms);
|
||||
}
|
||||
|
||||
time_base /= 1000;
|
||||
if (!time_base)
|
||||
time_base = HEALING_STATS_RESET_INTERVAL_S;
|
||||
|
||||
if (heal_count)
|
||||
return ((float)1 / (time_base / heal_count));
|
||||
else
|
||||
return ((float)1 / time_base);
|
||||
}
|
||||
|
||||
float HealRotation::ExtendedHealFrequency(Mob* hr_target)
|
||||
{
|
||||
if (!hr_target)
|
||||
return 0.0f;
|
||||
|
||||
uint32 current_time = Timer::GetCurrentTime();
|
||||
uint32 heal_count = 0;
|
||||
float time_base = 0;
|
||||
if (m_target_healing_stats_1.find(hr_target) != m_target_healing_stats_1.end()) {
|
||||
heal_count += m_target_healing_stats_1[hr_target].heal_count;
|
||||
time_base = (current_time - m_target_healing_stats_1[hr_target].last_heal_time_ms + HEALING_STATS_RESET_INTERVAL);
|
||||
}
|
||||
if (m_target_healing_stats_2.find(hr_target) != m_target_healing_stats_2.end()) {
|
||||
heal_count += m_target_healing_stats_2[hr_target].heal_count;
|
||||
time_base = (current_time - m_target_healing_stats_2[hr_target].last_heal_time_ms);
|
||||
}
|
||||
|
||||
time_base /= 1000;
|
||||
if (!time_base)
|
||||
time_base = (HEALING_STATS_RESET_INTERVAL_S * 2);
|
||||
|
||||
if (heal_count)
|
||||
return ((float)1 / (time_base / heal_count));
|
||||
else
|
||||
return ((float)1 / time_base);
|
||||
}
|
||||
|
||||
HealingStats* HealRotation::TargetHealingStats1(Mob* hr_target)
|
||||
{
|
||||
if (!hr_target)
|
||||
return nullptr;
|
||||
if (m_target_healing_stats_1.find(hr_target) == m_target_healing_stats_1.end())
|
||||
return nullptr;
|
||||
|
||||
return &m_target_healing_stats_1[hr_target];
|
||||
}
|
||||
|
||||
HealingStats* HealRotation::TargetHealingStats2(Mob* hr_target)
|
||||
{
|
||||
if (!hr_target)
|
||||
return nullptr;
|
||||
if (m_target_healing_stats_2.find(hr_target) == m_target_healing_stats_2.end())
|
||||
return nullptr;
|
||||
|
||||
return &m_target_healing_stats_2[hr_target];
|
||||
}
|
||||
|
||||
bool HealRotation::SetArmorTypeSafeHPRatio(uint8 armor_type, float hp_ratio)
|
||||
{
|
||||
if (armor_type >= ARMOR_TYPE_COUNT)
|
||||
return false;
|
||||
if (hp_ratio < CRITICAL_HP_RATIO_BASE || hp_ratio > SAFE_HP_RATIO_BASE)
|
||||
return false;
|
||||
if (hp_ratio < m_critical_hp_ratio[armor_type])
|
||||
return false;
|
||||
|
||||
m_safe_hp_ratio[armor_type] = hp_ratio;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HealRotation::SetArmorTypeCriticalHPRatio(uint8 armor_type, float hp_ratio)
|
||||
{
|
||||
if (armor_type >= ARMOR_TYPE_COUNT)
|
||||
return false;
|
||||
if (hp_ratio < CRITICAL_HP_RATIO_BASE || hp_ratio > SAFE_HP_RATIO_BASE)
|
||||
return false;
|
||||
if (hp_ratio > m_safe_hp_ratio[armor_type])
|
||||
return false;
|
||||
|
||||
m_critical_hp_ratio[armor_type] = hp_ratio;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float HealRotation::ArmorTypeSafeHPRatio(uint8 armor_type)
|
||||
{
|
||||
if (armor_type < ARMOR_TYPE_COUNT)
|
||||
return m_safe_hp_ratio[armor_type];
|
||||
else
|
||||
return m_safe_hp_ratio[ARMOR_TYPE_UNKNOWN];
|
||||
}
|
||||
|
||||
float HealRotation::ArmorTypeCriticalHPRatio(uint8 armor_type)
|
||||
{
|
||||
if (armor_type < ARMOR_TYPE_COUNT)
|
||||
return m_critical_hp_ratio[armor_type];
|
||||
else
|
||||
return m_critical_hp_ratio[ARMOR_TYPE_UNKNOWN];
|
||||
}
|
||||
|
||||
void HealRotation::ResetArmorTypeHPLimits()
|
||||
{
|
||||
m_safe_hp_ratio[ARMOR_TYPE_UNKNOWN] = SAFE_HP_RATIO_BASE;
|
||||
m_safe_hp_ratio[ARMOR_TYPE_CLOTH] = SAFE_HP_RATIO_CLOTH;
|
||||
m_safe_hp_ratio[ARMOR_TYPE_LEATHER] = SAFE_HP_RATIO_LEATHER;
|
||||
m_safe_hp_ratio[ARMOR_TYPE_CHAIN] = SAFE_HP_RATIO_CHAIN;
|
||||
m_safe_hp_ratio[ARMOR_TYPE_PLATE] = SAFE_HP_RATIO_PLATE;
|
||||
|
||||
m_critical_hp_ratio[ARMOR_TYPE_UNKNOWN] = CRITICAL_HP_RATIO_BASE;
|
||||
m_critical_hp_ratio[ARMOR_TYPE_CLOTH] = CRITICAL_HP_RATIO_CLOTH;
|
||||
m_critical_hp_ratio[ARMOR_TYPE_LEATHER] = CRITICAL_HP_RATIO_LEATHER;
|
||||
m_critical_hp_ratio[ARMOR_TYPE_CHAIN] = CRITICAL_HP_RATIO_CHAIN;
|
||||
m_critical_hp_ratio[ARMOR_TYPE_PLATE] = CRITICAL_HP_RATIO_PLATE;
|
||||
}
|
||||
|
||||
bool HealRotation::valid_state()
|
||||
{
|
||||
m_member_pool.remove(nullptr);
|
||||
m_member_pool.remove_if([](Mob* l) {return (!IsMemberClass(l->GetClass())); });
|
||||
|
||||
cycle_refresh();
|
||||
|
||||
if (m_member_pool.empty())
|
||||
ClearTargetPool(); // Consumes HealRotation at this point
|
||||
|
||||
return (!m_member_pool.empty());
|
||||
}
|
||||
|
||||
void HealRotation::cycle_refresh()
|
||||
{
|
||||
m_is_active = false;
|
||||
m_cycle_pool.clear();
|
||||
if (m_member_pool.empty())
|
||||
return;
|
||||
|
||||
m_cycle_pool = m_member_pool;
|
||||
|
||||
m_is_active = true;
|
||||
}
|
||||
|
||||
bool HealRotation::healable_target(bool use_class_at, bool critical_only)
|
||||
{
|
||||
if (m_target_pool.empty())
|
||||
return false;
|
||||
|
||||
auto healable_target = m_target_pool.front();
|
||||
if (!healable_target)
|
||||
return false;
|
||||
if (healable_target->DontHealMeBefore() > Timer::GetCurrentTime())
|
||||
return false;
|
||||
if (healable_target->GetAppearance() == eaDead)
|
||||
return false;
|
||||
|
||||
if (use_class_at) {
|
||||
if (critical_only && healable_target->GetHPRatio() > m_critical_hp_ratio[ClassArmorType(healable_target->GetClass())])
|
||||
return false;
|
||||
if (healable_target->GetHPRatio() > m_safe_hp_ratio[ClassArmorType(healable_target->GetClass())])
|
||||
return false;
|
||||
if (healable_target->IsBerserk() && (healable_target->GetClass() == WARRIOR || healable_target->GetClass() == BERSERKER)) {
|
||||
if (healable_target->GetHPRatio() <= RuleI(Combat, BerserkerFrenzyEnd) && healable_target->GetHPRatio() > m_critical_hp_ratio[ClassArmorType(healable_target->GetClass())])
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (critical_only && healable_target->GetHPRatio() > CRITICAL_HP_RATIO_BASE)
|
||||
return false;
|
||||
if (healable_target->GetHPRatio() > SAFE_HP_RATIO_BASE)
|
||||
return false;
|
||||
if (healable_target->IsBerserk() && (healable_target->GetClass() == WARRIOR || healable_target->GetClass() == BERSERKER)) {
|
||||
if (healable_target->GetHPRatio() <= RuleI(Combat, BerserkerFrenzyEnd) && healable_target->GetHPRatio() > CRITICAL_HP_RATIO_BASE)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void HealRotation::bias_targets()
|
||||
{
|
||||
#define LT_HPRATIO(l, r) (l->GetHPRatio() < r->GetHPRatio())
|
||||
#define LT_ARMTYPE(l, r) (ClassArmorType(l->GetClass()) < ClassArmorType(r->GetClass()))
|
||||
|
||||
#define EQ_ALIVE(l, r) (l->GetAppearance() != eaDead && r->GetAppearance() != eaDead)
|
||||
#define EQ_READY(l, r, ct) (l->DontHealMeBefore() <= ct && r->DontHealMeBefore() <= ct)
|
||||
#define EQ_TANK(l, r) ((l->HasGroup() && l->GetGroup()->AmIMainTank(l->GetCleanName())) && (r->HasGroup() && r->GetGroup()->AmIMainTank(r->GetCleanName())))
|
||||
#define EQ_HEALER(l, r) (IsMemberClass(l->GetClass()) && IsMemberClass(r->GetClass()))
|
||||
#define EQ_ARMTYPE(l, r) (ClassArmorType(l->GetClass()) == ClassArmorType(r->GetClass()))
|
||||
#define EQ_ATCRIT(l, r) (l->GetHPRatio() <= (*l->TargetOfHealRotation())->ArmorTypeCriticalHPRatio(ClassArmorType(l->GetClass())) && \
|
||||
r->GetHPRatio() <= (*r->TargetOfHealRotation())->ArmorTypeCriticalHPRatio(ClassArmorType(r->GetClass())))
|
||||
#define EQ_ATWOUND(l, r) (l->GetHPRatio() <= (*l->TargetOfHealRotation())->ArmorTypeSafeHPRatio(ClassArmorType(l->GetClass())) && \
|
||||
r->GetHPRatio() <= (*r->TargetOfHealRotation())->ArmorTypeSafeHPRatio(ClassArmorType(r->GetClass())))
|
||||
|
||||
#define GT_ALIVE(l, r) (l->GetAppearance() != eaDead && r->GetAppearance() == eaDead)
|
||||
#define GT_READY(l, r, ct) (l->DontHealMeBefore() <= ct && r->DontHealMeBefore() > ct)
|
||||
#define GT_TANK(l, r) ((l->HasGroup() && l->GetGroup()->AmIMainTank(l->GetCleanName())) && (!r->HasGroup() || !r->GetGroup()->AmIMainTank(r->GetCleanName())))
|
||||
#define GT_HEALER(l, r) (IsMemberClass(l->GetClass()) && !IsMemberClass(r->GetClass()))
|
||||
#define GT_HEALFREQ(l, r) (l->HealRotationHealFrequency() > r->HealRotationHealFrequency())
|
||||
#define GT_HEALCNT(l, r) (l->HealRotationHealCount() > r->HealRotationHealCount())
|
||||
#define GT_ATCRIT(l, r) (l->GetHPRatio() <= (*l->TargetOfHealRotation())->ArmorTypeCriticalHPRatio(ClassArmorType(l->GetClass())) && \
|
||||
r->GetHPRatio() > (*r->TargetOfHealRotation())->ArmorTypeCriticalHPRatio(ClassArmorType(r->GetClass())))
|
||||
#define GT_XHEALFREQ(l, r) (l->HealRotationExtendedHealFrequency() > r->HealRotationExtendedHealFrequency())
|
||||
#define GT_XHEALCNT(l, r) (l->HealRotationExtendedHealCount() > r->HealRotationExtendedHealCount())
|
||||
#define GT_ATWOUND(l, r) (l->GetHPRatio() <= (*l->TargetOfHealRotation())->ArmorTypeSafeHPRatio(ClassArmorType(l->GetClass())) && \
|
||||
r->GetHPRatio() > (*r->TargetOfHealRotation())->ArmorTypeSafeHPRatio(ClassArmorType(r->GetClass())))
|
||||
|
||||
if (m_target_pool.empty()) {
|
||||
m_casting_target_poke = true;
|
||||
m_active_heal_target = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// attempt to clear invalid target pool entries
|
||||
m_target_pool.remove(nullptr);
|
||||
m_target_pool.remove_if([](Mob* l) { return (!IsTargetMobType(l)); });
|
||||
|
||||
uint32 sort_type = 0; // debug
|
||||
|
||||
while (m_target_pool.size() > 1 && !m_casting_target_poke && !m_adaptive_targeting) { // standard behavior
|
||||
sort_type = 1;
|
||||
m_target_pool.sort([](Mob* l, Mob* r) {
|
||||
if (GT_ALIVE(l, r))
|
||||
return true;
|
||||
uint32 current_time = Timer::GetCurrentTime();
|
||||
if (EQ_ALIVE(l, r) && GT_READY(l, r, current_time))
|
||||
return true;
|
||||
if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && GT_TANK(l, r))
|
||||
return true;
|
||||
if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && EQ_TANK(l, r) && LT_HPRATIO(l, r))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
});
|
||||
if (m_target_pool.front()->HasGroup() && m_target_pool.front()->GetGroup()->AmIMainTank(m_target_pool.front()->GetCleanName()) && healable_target(false))
|
||||
break;
|
||||
|
||||
sort_type = 2;
|
||||
m_target_pool.sort([](Mob* l, Mob* r) {
|
||||
if (GT_ALIVE(l, r))
|
||||
return true;
|
||||
uint32 current_time = Timer::GetCurrentTime();
|
||||
if (EQ_ALIVE(l, r) && GT_READY(l, r, current_time))
|
||||
return true;
|
||||
if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && GT_HEALER(l, r))
|
||||
return true;
|
||||
if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && EQ_HEALER(l, r) && LT_HPRATIO(l, r))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
});
|
||||
if (IsMemberClass(m_target_pool.front()->GetClass()) && healable_target(false))
|
||||
break;
|
||||
|
||||
sort_type = 3; // default
|
||||
m_target_pool.sort([](const Mob* l, const Mob* r) {
|
||||
if (GT_ALIVE(l, r))
|
||||
return true;
|
||||
uint32 current_time = Timer::GetCurrentTime();
|
||||
if (EQ_ALIVE(l, r) && GT_READY(l, r, current_time))
|
||||
return true;
|
||||
if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && LT_HPRATIO(l, r))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
while (m_target_pool.size() > 1 && !m_casting_target_poke && m_adaptive_targeting) { // adaptive targeting behavior
|
||||
sort_type = 101;
|
||||
m_target_pool.sort([](Mob* l, Mob* r) {
|
||||
if (GT_ALIVE(l, r))
|
||||
return true;
|
||||
uint32 current_time = Timer::GetCurrentTime();
|
||||
if (EQ_ALIVE(l, r) && GT_READY(l, r, current_time))
|
||||
return true;
|
||||
if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && GT_HEALFREQ(l, r))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
});
|
||||
if (healable_target(true, true))
|
||||
break;
|
||||
|
||||
sort_type = 102;
|
||||
m_target_pool.sort([](Mob* l, Mob* r) {
|
||||
if (GT_ALIVE(l, r))
|
||||
return true;
|
||||
uint32 current_time = Timer::GetCurrentTime();
|
||||
if (EQ_ALIVE(l, r) && GT_READY(l, r, current_time))
|
||||
return true;
|
||||
if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && GT_HEALCNT(l, r))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
});
|
||||
if (healable_target(true, true))
|
||||
break;
|
||||
|
||||
sort_type = 103;
|
||||
m_target_pool.sort([](Mob* l, Mob* r) {
|
||||
if (GT_ALIVE(l, r))
|
||||
return true;
|
||||
uint32 current_time = Timer::GetCurrentTime();
|
||||
if (EQ_ALIVE(l, r) && GT_READY(l, r, current_time))
|
||||
return true;
|
||||
if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && GT_TANK(l, r))
|
||||
return true;
|
||||
if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && EQ_TANK(l, r) && LT_HPRATIO(l, r))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
});
|
||||
if (m_target_pool.front()->HasGroup() && m_target_pool.front()->GetGroup()->AmIMainTank(m_target_pool.front()->GetCleanName()) && healable_target(true, true))
|
||||
break;
|
||||
|
||||
sort_type = 104;
|
||||
m_target_pool.sort([](const Mob* l, const Mob* r) {
|
||||
if (GT_ALIVE(l, r))
|
||||
return true;
|
||||
uint32 current_time = Timer::GetCurrentTime();
|
||||
if (EQ_ALIVE(l, r) && GT_READY(l, r, current_time))
|
||||
return true;
|
||||
if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && GT_HEALER(l, r))
|
||||
return true;
|
||||
if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && EQ_HEALER(l, r) && LT_HPRATIO(l, r))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
});
|
||||
if (IsMemberClass(m_target_pool.front()->GetClass()) && healable_target(true, true))
|
||||
break;
|
||||
|
||||
sort_type = 105;
|
||||
m_target_pool.sort([](const Mob* l, const Mob* r) {
|
||||
if (GT_ALIVE(l, r))
|
||||
return true;
|
||||
uint32 current_time = Timer::GetCurrentTime();
|
||||
if (EQ_ALIVE(l, r) && GT_READY(l, r, current_time))
|
||||
return true;
|
||||
if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && GT_ATCRIT(l, r))
|
||||
return true;
|
||||
if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && EQ_ATCRIT(l, r) && LT_ARMTYPE(l, r))
|
||||
return true;
|
||||
if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && EQ_ATCRIT(l, r) && EQ_ARMTYPE(l, r) && LT_HPRATIO(l, r))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
});
|
||||
if (healable_target(true, true))
|
||||
break;
|
||||
|
||||
sort_type = 106;
|
||||
m_target_pool.sort([](Mob* l, Mob* r) {
|
||||
if (GT_ALIVE(l, r))
|
||||
return true;
|
||||
uint32 current_time = Timer::GetCurrentTime();
|
||||
if (EQ_ALIVE(l, r) && GT_READY(l, r, current_time))
|
||||
return true;
|
||||
if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && GT_XHEALFREQ(l, r))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
});
|
||||
if (healable_target(true))
|
||||
break;
|
||||
|
||||
sort_type = 107;
|
||||
m_target_pool.sort([](Mob* l, Mob* r) {
|
||||
if (GT_ALIVE(l, r))
|
||||
return true;
|
||||
uint32 current_time = Timer::GetCurrentTime();
|
||||
if (EQ_ALIVE(l, r) && GT_READY(l, r, current_time))
|
||||
return true;
|
||||
if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && GT_XHEALCNT(l, r))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
});
|
||||
if (healable_target(true))
|
||||
break;
|
||||
|
||||
sort_type = 108;
|
||||
m_target_pool.sort([](const Mob* l, const Mob* r) {
|
||||
if (GT_ALIVE(l, r))
|
||||
return true;
|
||||
uint32 current_time = Timer::GetCurrentTime();
|
||||
if (EQ_ALIVE(l, r) && GT_READY(l, r, current_time))
|
||||
return true;
|
||||
if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && GT_ATWOUND(l, r))
|
||||
return true;
|
||||
if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && EQ_ATWOUND(l, r) && LT_ARMTYPE(l, r))
|
||||
return true;
|
||||
if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && EQ_ATWOUND(l, r) && EQ_ARMTYPE(l, r) && LT_HPRATIO(l, r))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
});
|
||||
if (healable_target())
|
||||
break;
|
||||
|
||||
sort_type = 109; // default
|
||||
m_target_pool.sort([](const Mob* l, const Mob* r) {
|
||||
if (GT_ALIVE(l, r))
|
||||
return true;
|
||||
uint32 current_time = Timer::GetCurrentTime();
|
||||
if (EQ_ALIVE(l, r) && GT_READY(l, r, current_time))
|
||||
return true;
|
||||
if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && LT_HPRATIO(l, r))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
m_active_heal_target = healable_target(false);
|
||||
if (!m_active_heal_target)
|
||||
m_active_heal_target = healable_target();
|
||||
|
||||
m_casting_target_poke = true;
|
||||
|
||||
#if (EQDEBUG >= 12)
|
||||
Log.Out(Logs::General, Logs::Error, "HealRotation::bias_targets() - *** Post-processing state ***");
|
||||
Log.Out(Logs::General, Logs::Error, "HealRotation Settings:");
|
||||
Log.Out(Logs::General, Logs::Error, "HealRotation::m_interval_ms = %u", m_interval_ms);
|
||||
Log.Out(Logs::General, Logs::Error, "HealRotation::m_next_cast_time_ms = %u (current_time: %u, time_diff: %i)", m_next_cast_time_ms, Timer::GetCurrentTime(), ((int32)Timer::GetCurrentTime() - (int32)m_next_cast_time_ms));
|
||||
Log.Out(Logs::General, Logs::Error, "HealRotation::m_next_poke_time_ms = %u (current_time: %u, time_diff: %i)", m_next_poke_time_ms, Timer::GetCurrentTime(), ((int32)Timer::GetCurrentTime() - (int32)m_next_poke_time_ms));
|
||||
Log.Out(Logs::General, Logs::Error, "HealRotation::m_fast_heals = %s", ((m_fast_heals) ? ("true") : ("false")));
|
||||
Log.Out(Logs::General, Logs::Error, "HealRotation::m_adaptive_targeting = %s", ((m_adaptive_targeting) ? ("true") : ("false")));
|
||||
Log.Out(Logs::General, Logs::Error, "HealRotation::m_casting_override = %s", ((m_casting_override) ? ("true") : ("false")));
|
||||
Log.Out(Logs::General, Logs::Error, "HealRotation::m_casting_target_poke = %s", ((m_casting_target_poke) ? ("true") : ("false")));
|
||||
Log.Out(Logs::General, Logs::Error, "HealRotation::m_active_heal_target = %s", ((m_active_heal_target) ? ("true") : ("false")));
|
||||
Log.Out(Logs::General, Logs::Error, "HealRotation::m_is_active = %s", ((m_is_active) ? ("true") : ("false")));
|
||||
Log.Out(Logs::General, Logs::Error, "HealRotation::m_member_list.size() = %i", m_member_pool.size());
|
||||
Log.Out(Logs::General, Logs::Error, "HealRotation::m_cycle_list.size() = %i", m_cycle_pool.size());
|
||||
Log.Out(Logs::General, Logs::Error, "HealRotation::m_target_list.size() = %i", m_target_pool.size());
|
||||
if (m_member_pool.size()) { Log.Out(Logs::General, Logs::Error, "(std::shared_ptr<HealRotation>::use_count() = %i", m_member_pool.front()->MemberOfHealRotation()->use_count()); }
|
||||
else { Log.Out(Logs::General, Logs::Error, "(std::shared_ptr<HealRotation>::use_count() = unknown (0)"); }
|
||||
Log.Out(Logs::General, Logs::Error, "HealRotation Members:");
|
||||
int member_index = 0;
|
||||
for (auto mlist_iter : m_member_pool) {
|
||||
if (!mlist_iter) { continue; }
|
||||
Log.Out(Logs::General, Logs::Error, "(%i) %s (hrcast: %c)", (++member_index), mlist_iter->GetCleanName(), ((mlist_iter->AmICastingForHealRotation())?('T'):('F')));
|
||||
}
|
||||
if (!member_index) { Log.Out(Logs::General, Logs::Error, "(0) None"); }
|
||||
Log.Out(Logs::General, Logs::Error, "HealRotation Cycle:");
|
||||
int cycle_index = 0;
|
||||
for (auto clist_iter : m_cycle_pool) {
|
||||
if (!clist_iter) { continue; }
|
||||
Log.Out(Logs::General, Logs::Error, "(%i) %s", (++cycle_index), clist_iter->GetCleanName());
|
||||
}
|
||||
if (!cycle_index) { Log.Out(Logs::General, Logs::Error, "(0) None"); }
|
||||
Log.Out(Logs::General, Logs::Error, "HealRotation Targets: (sort type: %u)", sort_type);
|
||||
int target_index = 0;
|
||||
|
||||
for (auto tlist_iter : m_target_pool) {
|
||||
if (!tlist_iter) { continue; }
|
||||
Log.Out(Logs::General, Logs::Error, "(%i) %s (hp: %3.1f%%, at: %u, dontheal: %c, crit(base): %c(%c), safe(base): %c(%c), hcnt(ext): %u(%u), hfreq(ext): %f(%f))",
|
||||
(++target_index), tlist_iter->GetCleanName(),
|
||||
tlist_iter->GetHPRatio(),
|
||||
ClassArmorType(tlist_iter->GetClass()),
|
||||
((tlist_iter->DontHealMeBefore() > Timer::GetCurrentTime()) ? ('T') : ('F')),
|
||||
((tlist_iter->GetHPRatio()>m_critical_hp_ratio[ClassArmorType(tlist_iter->GetClass())]) ? ('F') : ('T')),
|
||||
((tlist_iter->GetHPRatio()>m_critical_hp_ratio[ARMOR_TYPE_UNKNOWN]) ? ('F') : ('T')),
|
||||
((tlist_iter->GetHPRatio()>m_safe_hp_ratio[ClassArmorType(tlist_iter->GetClass())]) ? ('T') : ('F')),
|
||||
((tlist_iter->GetHPRatio()>m_safe_hp_ratio[ARMOR_TYPE_UNKNOWN]) ? ('T') : ('F')),
|
||||
tlist_iter->HealRotationHealCount(),
|
||||
tlist_iter->HealRotationExtendedHealCount(),
|
||||
tlist_iter->HealRotationHealFrequency(),
|
||||
tlist_iter->HealRotationExtendedHealFrequency());
|
||||
}
|
||||
if (!target_index) { Log.Out(Logs::General, Logs::Error, "(0) None (hp: 0.0\%, at: 0, dontheal: F, crit(base): F(F), safe(base): F(F), hcnt(ext): 0(0), hfreq(ext): 0.0(0.0))"); }
|
||||
#endif
|
||||
}
|
||||
|
||||
bool HealRotation::IsMemberClass(uint8 class_id)
|
||||
{
|
||||
switch (class_id) {
|
||||
case CLERIC:
|
||||
case DRUID:
|
||||
case SHAMAN:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool HealRotation::IsTargetMobType(Mob* target_mob)
|
||||
{
|
||||
if (!target_mob)
|
||||
return false;
|
||||
if (!target_mob->IsClient() && !target_mob->IsBot() && !target_mob->IsPet())
|
||||
return false;
|
||||
if (target_mob->IsPet() && (!target_mob->GetOwner() || (!target_mob->GetOwner()->IsClient() && !target_mob->GetOwner()->IsBot())))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
148
zone/heal_rotation.h
Normal file
148
zone/heal_rotation.h
Normal file
@ -0,0 +1,148 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HEAL_ROTATION_H
|
||||
#define HEAL_ROTATION_H
|
||||
|
||||
#include "mob.h"
|
||||
|
||||
#define CASTING_CYCLE_MINIMUM_INTERVAL 1000
|
||||
#define CASTING_CYCLE_MINIMUM_INTERVAL_S 1
|
||||
#define CASTING_CYCLE_MAXIMUM_INTERVAL 30000
|
||||
#define CASTING_CYCLE_MAXIMUM_INTERVAL_S 30
|
||||
#define CASTING_CYCLE_DEFAULT_INTERVAL 5000
|
||||
#define CASTING_CYCLE_DEFAULT_INTERVAL_S 5
|
||||
#define POKE_PROPAGATION_DELAY 250
|
||||
#define ADVANCE_ROTATION_MINIMUM_INTERVAL 100
|
||||
#define HEALING_STATS_RESET_INTERVAL 60000
|
||||
#define HEALING_STATS_RESET_INTERVAL_S 60
|
||||
|
||||
#define SAFE_HP_RATIO_BASE 95.0f
|
||||
#define CRITICAL_HP_RATIO_BASE 10.0f
|
||||
|
||||
struct HealingStats
|
||||
{
|
||||
uint32 last_heal_time_ms;
|
||||
uint32 heal_count;
|
||||
};
|
||||
|
||||
// Both members and targets use a shared_ptr to keep track of their HealRotation instance
|
||||
class HealRotation
|
||||
{
|
||||
public:
|
||||
HealRotation(Bot* hr_creator, uint32 interval_ms = CASTING_CYCLE_DEFAULT_INTERVAL, bool fast_heals = false, bool adaptive_targeting = false, bool casting_override = false);
|
||||
|
||||
void SetIntervalMS(uint32 interval_ms);
|
||||
void SetIntervalS(uint32 interval_s);
|
||||
void SetFastHeals(bool flag) { m_fast_heals = flag; }
|
||||
void SetAdaptiveTargeting(bool flag) { m_adaptive_targeting = flag; }
|
||||
void SetCastingOverride(bool flag) { m_casting_override = flag; }
|
||||
bool AddMemberToPool(Bot* hr_member);
|
||||
bool AddTargetToPool(Mob* hr_target);
|
||||
|
||||
uint32 CreationTimeMS() { return m_creation_time_ms; }
|
||||
uint32 LastHealTimeMS() { return m_last_heal_time_ms; }
|
||||
uint32 IntervalMS() { return m_interval_ms; }
|
||||
uint32 IntervalS() { return (m_interval_ms / 1000); }
|
||||
bool FastHeals() { return m_fast_heals; }
|
||||
bool AdaptiveTargeting() { return m_adaptive_targeting; }
|
||||
bool CastingOverride() { return m_casting_override; }
|
||||
bool RemoveMemberFromPool(Bot* hr_member);
|
||||
bool RemoveTargetFromPool(Mob* hr_target);
|
||||
|
||||
bool ClearMemberPool();
|
||||
bool ClearTargetPool();
|
||||
|
||||
bool Start();
|
||||
bool Stop();
|
||||
|
||||
bool IsActive() { return m_is_active; }
|
||||
bool CastingReady() { return (Timer::GetCurrentTime() >= m_next_cast_time_ms); }
|
||||
Bot* CastingMember();
|
||||
bool PokeCastingTarget();
|
||||
Mob* CastingTarget();
|
||||
bool AdvanceRotation(bool use_interval = true);
|
||||
|
||||
std::list<Bot*>* MemberList() { return &m_member_pool; }
|
||||
std::list<Bot*>* CycleList() { return &m_cycle_pool; }
|
||||
std::list<Mob*>* TargetList() { return &m_target_pool; }
|
||||
|
||||
bool IsMemberInPool(Bot* hr_member);
|
||||
bool IsTargetInPool(Mob* hr_target);
|
||||
|
||||
void SetMemberIsCasting(Bot* hr_member, bool flag = true);
|
||||
bool MemberIsCasting(Bot* hr_member);
|
||||
|
||||
void UpdateTargetHealingStats(Mob* hr_target);
|
||||
void StartNewTargetHealingStatsCycle(uint32 current_time);
|
||||
uint32 HealCount(Mob* hr_target);
|
||||
uint32 ExtendedHealCount(Mob* hr_target);
|
||||
float HealFrequency(Mob* hr_target);
|
||||
float ExtendedHealFrequency(Mob* hr_target);
|
||||
HealingStats* TargetHealingStats1(Mob* hr_target);
|
||||
HealingStats* TargetHealingStats2(Mob* hr_target);
|
||||
|
||||
bool SetArmorTypeSafeHPRatio(uint8 armor_type, float hp_ratio);
|
||||
bool SetArmorTypeCriticalHPRatio(uint8 armor_type, float hp_ratio);
|
||||
|
||||
float ArmorTypeSafeHPRatio(uint8 armor_type);
|
||||
float ArmorTypeCriticalHPRatio(uint8 armor_type);
|
||||
|
||||
void ResetArmorTypeHPLimits();
|
||||
|
||||
static bool IsMemberClass(uint8 class_id);
|
||||
static bool IsTargetMobType(Mob* target_mob);
|
||||
|
||||
private:
|
||||
bool valid_state();
|
||||
void cycle_refresh();
|
||||
bool healable_target(bool use_class_at = true, bool critical_only = false);
|
||||
void bias_targets();
|
||||
|
||||
uint32 m_creation_time_ms;
|
||||
uint32 m_last_heal_time_ms;
|
||||
uint32 m_interval_ms;
|
||||
uint32 m_next_cast_time_ms;
|
||||
uint32 m_next_poke_time_ms;
|
||||
uint32 m_healing_stats_begin_ms;
|
||||
bool m_fast_heals;
|
||||
bool m_adaptive_targeting;
|
||||
bool m_casting_override;
|
||||
bool m_casting_target_poke;
|
||||
bool m_active_heal_target;
|
||||
|
||||
bool m_is_active;
|
||||
|
||||
std::list<Bot*> m_member_pool;
|
||||
std::list<Bot*> m_cycle_pool;
|
||||
std::list<Mob*> m_target_pool;
|
||||
|
||||
std::map<Bot*, bool> m_member_is_casting;
|
||||
|
||||
std::map<Mob*, HealingStats> m_target_healing_stats_1;
|
||||
std::map<Mob*, HealingStats> m_target_healing_stats_2;
|
||||
|
||||
float m_safe_hp_ratio[ARMOR_TYPE_COUNT];
|
||||
float m_critical_hp_ratio[ARMOR_TYPE_COUNT];
|
||||
|
||||
friend class std::_Ref_count_obj<HealRotation>;
|
||||
HealRotation(HealRotation* allocator_shunt) {};
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.net)
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -2020,10 +2020,7 @@ void Client::QSSwapItemAuditor(MoveItem_Struct* move_in, bool postaction_call) {
|
||||
void Client::DyeArmor(DyeStruct* dye){
|
||||
int16 slot=0;
|
||||
for (int i = EmuConstants::MATERIAL_BEGIN; i <= EmuConstants::MATERIAL_TINT_END; i++) {
|
||||
if (m_pp.item_tint[i].RGB.Blue != dye->dye[i].RGB.Blue ||
|
||||
m_pp.item_tint[i].RGB.Red != dye->dye[i].RGB.Red ||
|
||||
m_pp.item_tint[i].RGB.Green != dye->dye[i].RGB.Green
|
||||
) {
|
||||
if ((m_pp.item_tint[i].Color & 0x00FFFFFF) != (dye->dye[i].Color & 0x00FFFFFF)) {
|
||||
slot = m_inv.HasItem(32557, 1, invWherePersonal);
|
||||
if (slot != INVALID_INDEX){
|
||||
DeleteItemInInventory(slot,1,true);
|
||||
|
||||
374
zone/mob.cpp
374
zone/mob.cpp
@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemu.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -473,6 +473,10 @@ Mob::~Mob()
|
||||
safe_delete(PathingRouteUpdateTimerShort);
|
||||
safe_delete(PathingRouteUpdateTimerLong);
|
||||
UninitializeBuffSlots();
|
||||
|
||||
#ifdef BOTS
|
||||
LeaveHealRotationTargetPool();
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32 Mob::GetAppearanceValue(EmuAppearance iAppearance) {
|
||||
@ -1766,8 +1770,7 @@ void Mob::SendIllusionPacket(uint16 in_race, uint8 in_gender, uint8 in_texture,
|
||||
|
||||
bool Mob::RandomizeFeatures(bool send_illusion, bool set_variables)
|
||||
{
|
||||
if (IsPlayerRace(GetRace()))
|
||||
{
|
||||
if (IsPlayerRace(GetRace())) {
|
||||
uint8 Gender = GetGender();
|
||||
uint8 Texture = 0xFF;
|
||||
uint8 HelmTexture = 0xFF;
|
||||
@ -1788,160 +1791,158 @@ bool Mob::RandomizeFeatures(bool send_illusion, bool set_variables)
|
||||
LuclinFace = zone->random.Int(0, 7);
|
||||
|
||||
// Adjust all settings based on the min and max for each feature of each race and gender
|
||||
switch (GetRace())
|
||||
{
|
||||
case 1: // Human
|
||||
HairColor = zone->random.Int(0, 19);
|
||||
if (Gender == 0) {
|
||||
BeardColor = HairColor;
|
||||
HairStyle = zone->random.Int(0, 3);
|
||||
Beard = zone->random.Int(0, 5);
|
||||
}
|
||||
if (Gender == 1) {
|
||||
HairStyle = zone->random.Int(0, 2);
|
||||
}
|
||||
break;
|
||||
case 2: // Barbarian
|
||||
HairColor = zone->random.Int(0, 19);
|
||||
switch (GetRace()) {
|
||||
case HUMAN:
|
||||
HairColor = zone->random.Int(0, 19);
|
||||
if (Gender == MALE) {
|
||||
BeardColor = HairColor;
|
||||
HairStyle = zone->random.Int(0, 3);
|
||||
Beard = zone->random.Int(0, 5);
|
||||
}
|
||||
if (Gender == FEMALE) {
|
||||
HairStyle = zone->random.Int(0, 2);
|
||||
}
|
||||
break;
|
||||
case BARBARIAN:
|
||||
HairColor = zone->random.Int(0, 19);
|
||||
LuclinFace = zone->random.Int(0, 87);
|
||||
if (Gender == MALE) {
|
||||
BeardColor = HairColor;
|
||||
HairStyle = zone->random.Int(0, 3);
|
||||
Beard = zone->random.Int(0, 5);
|
||||
}
|
||||
if (Gender == FEMALE) {
|
||||
HairStyle = zone->random.Int(0, 2);
|
||||
}
|
||||
break;
|
||||
case ERUDITE:
|
||||
if (Gender == MALE) {
|
||||
BeardColor = zone->random.Int(0, 19);
|
||||
Beard = zone->random.Int(0, 5);
|
||||
LuclinFace = zone->random.Int(0, 57);
|
||||
}
|
||||
if (Gender == FEMALE) {
|
||||
LuclinFace = zone->random.Int(0, 87);
|
||||
if (Gender == 0) {
|
||||
BeardColor = HairColor;
|
||||
HairStyle = zone->random.Int(0, 3);
|
||||
Beard = zone->random.Int(0, 5);
|
||||
}
|
||||
if (Gender == 1) {
|
||||
HairStyle = zone->random.Int(0, 2);
|
||||
}
|
||||
break;
|
||||
case 3: // Erudite
|
||||
if (Gender == 0) {
|
||||
BeardColor = zone->random.Int(0, 19);
|
||||
Beard = zone->random.Int(0, 5);
|
||||
LuclinFace = zone->random.Int(0, 57);
|
||||
}
|
||||
if (Gender == 1) {
|
||||
LuclinFace = zone->random.Int(0, 87);
|
||||
}
|
||||
break;
|
||||
case 4: // WoodElf
|
||||
HairColor = zone->random.Int(0, 19);
|
||||
if (Gender == 0) {
|
||||
HairStyle = zone->random.Int(0, 3);
|
||||
}
|
||||
if (Gender == 1) {
|
||||
HairStyle = zone->random.Int(0, 2);
|
||||
}
|
||||
break;
|
||||
case 5: // HighElf
|
||||
HairColor = zone->random.Int(0, 14);
|
||||
if (Gender == 0) {
|
||||
HairStyle = zone->random.Int(0, 3);
|
||||
LuclinFace = zone->random.Int(0, 37);
|
||||
BeardColor = HairColor;
|
||||
}
|
||||
if (Gender == 1) {
|
||||
HairStyle = zone->random.Int(0, 2);
|
||||
}
|
||||
break;
|
||||
case 6: // DarkElf
|
||||
HairColor = zone->random.Int(13, 18);
|
||||
if (Gender == 0) {
|
||||
HairStyle = zone->random.Int(0, 3);
|
||||
LuclinFace = zone->random.Int(0, 37);
|
||||
BeardColor = HairColor;
|
||||
}
|
||||
if (Gender == 1) {
|
||||
HairStyle = zone->random.Int(0, 2);
|
||||
}
|
||||
break;
|
||||
case 7: // HalfElf
|
||||
HairColor = zone->random.Int(0, 19);
|
||||
if (Gender == 0) {
|
||||
HairStyle = zone->random.Int(0, 3);
|
||||
LuclinFace = zone->random.Int(0, 37);
|
||||
BeardColor = HairColor;
|
||||
}
|
||||
if (Gender == 1) {
|
||||
HairStyle = zone->random.Int(0, 2);
|
||||
}
|
||||
break;
|
||||
case 8: // Dwarf
|
||||
HairColor = zone->random.Int(0, 19);
|
||||
}
|
||||
break;
|
||||
case WOOD_ELF:
|
||||
HairColor = zone->random.Int(0, 19);
|
||||
if (Gender == MALE) {
|
||||
HairStyle = zone->random.Int(0, 3);
|
||||
}
|
||||
if (Gender == FEMALE) {
|
||||
HairStyle = zone->random.Int(0, 2);
|
||||
}
|
||||
break;
|
||||
case HIGH_ELF:
|
||||
HairColor = zone->random.Int(0, 14);
|
||||
if (Gender == MALE) {
|
||||
HairStyle = zone->random.Int(0, 3);
|
||||
LuclinFace = zone->random.Int(0, 37);
|
||||
BeardColor = HairColor;
|
||||
if (Gender == 0) {
|
||||
HairStyle = zone->random.Int(0, 3);
|
||||
Beard = zone->random.Int(0, 5);
|
||||
}
|
||||
if (Gender == 1) {
|
||||
HairStyle = zone->random.Int(0, 2);
|
||||
LuclinFace = zone->random.Int(0, 17);
|
||||
}
|
||||
break;
|
||||
case 9: // Troll
|
||||
EyeColor1 = zone->random.Int(0, 10);
|
||||
EyeColor2 = zone->random.Int(0, 10);
|
||||
if (Gender == 1) {
|
||||
HairStyle = zone->random.Int(0, 3);
|
||||
HairColor = zone->random.Int(0, 23);
|
||||
}
|
||||
break;
|
||||
case 10: // Ogre
|
||||
if (Gender == 1) {
|
||||
HairStyle = zone->random.Int(0, 3);
|
||||
HairColor = zone->random.Int(0, 23);
|
||||
}
|
||||
break;
|
||||
case 11: // Halfling
|
||||
HairColor = zone->random.Int(0, 19);
|
||||
if (Gender == 0) {
|
||||
BeardColor = HairColor;
|
||||
HairStyle = zone->random.Int(0, 3);
|
||||
Beard = zone->random.Int(0, 5);
|
||||
}
|
||||
if (Gender == 1) {
|
||||
HairStyle = zone->random.Int(0, 2);
|
||||
}
|
||||
break;
|
||||
case 12: // Gnome
|
||||
HairColor = zone->random.Int(0, 24);
|
||||
if (Gender == 0) {
|
||||
BeardColor = HairColor;
|
||||
HairStyle = zone->random.Int(0, 3);
|
||||
Beard = zone->random.Int(0, 5);
|
||||
}
|
||||
if (Gender == 1) {
|
||||
HairStyle = zone->random.Int(0, 2);
|
||||
}
|
||||
break;
|
||||
case 128: // Iksar
|
||||
case 130: // VahShir
|
||||
break;
|
||||
case 330: // Froglok
|
||||
LuclinFace = zone->random.Int(0, 9);
|
||||
case 522: // Drakkin
|
||||
HairColor = zone->random.Int(0, 3);
|
||||
}
|
||||
if (Gender == FEMALE) {
|
||||
HairStyle = zone->random.Int(0, 2);
|
||||
}
|
||||
break;
|
||||
case DARK_ELF:
|
||||
HairColor = zone->random.Int(13, 18);
|
||||
if (Gender == MALE) {
|
||||
HairStyle = zone->random.Int(0, 3);
|
||||
LuclinFace = zone->random.Int(0, 37);
|
||||
BeardColor = HairColor;
|
||||
EyeColor1 = zone->random.Int(0, 11);
|
||||
EyeColor2 = zone->random.Int(0, 11);
|
||||
LuclinFace = zone->random.Int(0, 6);
|
||||
DrakkinHeritage = zone->random.Int(0, 6);
|
||||
DrakkinTattoo = zone->random.Int(0, 7);
|
||||
DrakkinDetails = zone->random.Int(0, 7);
|
||||
if (Gender == 0) {
|
||||
Beard = zone->random.Int(0, 12);
|
||||
HairStyle = zone->random.Int(0, 8);
|
||||
}
|
||||
if (Gender == 1) {
|
||||
Beard = zone->random.Int(0, 3);
|
||||
HairStyle = zone->random.Int(0, 7);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (Gender == FEMALE) {
|
||||
HairStyle = zone->random.Int(0, 2);
|
||||
}
|
||||
break;
|
||||
case HALF_ELF:
|
||||
HairColor = zone->random.Int(0, 19);
|
||||
if (Gender == MALE) {
|
||||
HairStyle = zone->random.Int(0, 3);
|
||||
LuclinFace = zone->random.Int(0, 37);
|
||||
BeardColor = HairColor;
|
||||
}
|
||||
if (Gender == FEMALE) {
|
||||
HairStyle = zone->random.Int(0, 2);
|
||||
}
|
||||
break;
|
||||
case DWARF:
|
||||
HairColor = zone->random.Int(0, 19);
|
||||
BeardColor = HairColor;
|
||||
if (Gender == MALE) {
|
||||
HairStyle = zone->random.Int(0, 3);
|
||||
Beard = zone->random.Int(0, 5);
|
||||
}
|
||||
if (Gender == FEMALE) {
|
||||
HairStyle = zone->random.Int(0, 2);
|
||||
LuclinFace = zone->random.Int(0, 17);
|
||||
}
|
||||
break;
|
||||
case TROLL:
|
||||
EyeColor1 = zone->random.Int(0, 10);
|
||||
EyeColor2 = zone->random.Int(0, 10);
|
||||
if (Gender == FEMALE) {
|
||||
HairStyle = zone->random.Int(0, 3);
|
||||
HairColor = zone->random.Int(0, 23);
|
||||
}
|
||||
break;
|
||||
case OGRE:
|
||||
if (Gender == FEMALE) {
|
||||
HairStyle = zone->random.Int(0, 3);
|
||||
HairColor = zone->random.Int(0, 23);
|
||||
}
|
||||
break;
|
||||
case HALFLING:
|
||||
HairColor = zone->random.Int(0, 19);
|
||||
if (Gender == MALE) {
|
||||
BeardColor = HairColor;
|
||||
HairStyle = zone->random.Int(0, 3);
|
||||
Beard = zone->random.Int(0, 5);
|
||||
}
|
||||
if (Gender == FEMALE) {
|
||||
HairStyle = zone->random.Int(0, 2);
|
||||
}
|
||||
break;
|
||||
case GNOME:
|
||||
HairColor = zone->random.Int(0, 24);
|
||||
if (Gender == MALE) {
|
||||
BeardColor = HairColor;
|
||||
HairStyle = zone->random.Int(0, 3);
|
||||
Beard = zone->random.Int(0, 5);
|
||||
}
|
||||
if (Gender == FEMALE) {
|
||||
HairStyle = zone->random.Int(0, 2);
|
||||
}
|
||||
break;
|
||||
case IKSAR:
|
||||
case VAHSHIR:
|
||||
break;
|
||||
case FROGLOK:
|
||||
LuclinFace = zone->random.Int(0, 9);
|
||||
case DRAKKIN:
|
||||
HairColor = zone->random.Int(0, 3);
|
||||
BeardColor = HairColor;
|
||||
EyeColor1 = zone->random.Int(0, 11);
|
||||
EyeColor2 = zone->random.Int(0, 11);
|
||||
LuclinFace = zone->random.Int(0, 6);
|
||||
DrakkinHeritage = zone->random.Int(0, 6);
|
||||
DrakkinTattoo = zone->random.Int(0, 7);
|
||||
DrakkinDetails = zone->random.Int(0, 7);
|
||||
if (Gender == MALE) {
|
||||
Beard = zone->random.Int(0, 12);
|
||||
HairStyle = zone->random.Int(0, 8);
|
||||
}
|
||||
if (Gender == FEMALE) {
|
||||
Beard = zone->random.Int(0, 3);
|
||||
HairStyle = zone->random.Int(0, 7);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (set_variables)
|
||||
{
|
||||
if (set_variables) {
|
||||
haircolor = HairColor;
|
||||
beardcolor = BeardColor;
|
||||
eyecolor1 = EyeColor1;
|
||||
@ -1954,8 +1955,7 @@ bool Mob::RandomizeFeatures(bool send_illusion, bool set_variables)
|
||||
drakkin_details = DrakkinDetails;
|
||||
}
|
||||
|
||||
if (send_illusion)
|
||||
{
|
||||
if (send_illusion) {
|
||||
SendIllusionPacket(GetRace(), Gender, Texture, HelmTexture, HairColor, BeardColor,
|
||||
EyeColor1, EyeColor2, HairStyle, LuclinFace, Beard, 0xFF, DrakkinHeritage,
|
||||
DrakkinTattoo, DrakkinDetails);
|
||||
@ -5861,3 +5861,69 @@ int Mob::CheckBaneDamage(const ItemInst *item)
|
||||
|
||||
return damage;
|
||||
}
|
||||
|
||||
#ifdef BOTS
|
||||
bool Mob::JoinHealRotationTargetPool(std::shared_ptr<HealRotation>* heal_rotation)
|
||||
{
|
||||
if (IsHealRotationTarget())
|
||||
return false;
|
||||
if (!heal_rotation->use_count())
|
||||
return false;
|
||||
if (!(*heal_rotation))
|
||||
return false;
|
||||
if (!HealRotation::IsTargetMobType(this))
|
||||
return false;
|
||||
|
||||
if (!(*heal_rotation)->AddTargetToPool(this))
|
||||
return false;
|
||||
|
||||
m_target_of_heal_rotation = *heal_rotation;
|
||||
|
||||
return IsHealRotationTarget();
|
||||
}
|
||||
|
||||
bool Mob::LeaveHealRotationTargetPool()
|
||||
{
|
||||
if (!IsHealRotationTarget()) {
|
||||
m_target_of_heal_rotation.reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
m_target_of_heal_rotation->RemoveTargetFromPool(this);
|
||||
m_target_of_heal_rotation.reset();
|
||||
|
||||
return !IsHealRotationTarget();
|
||||
}
|
||||
|
||||
uint32 Mob::HealRotationHealCount()
|
||||
{
|
||||
if (!IsHealRotationTarget())
|
||||
return 0;
|
||||
|
||||
return m_target_of_heal_rotation->HealCount(this);
|
||||
}
|
||||
|
||||
uint32 Mob::HealRotationExtendedHealCount()
|
||||
{
|
||||
if (!IsHealRotationTarget())
|
||||
return 0;
|
||||
|
||||
return m_target_of_heal_rotation->ExtendedHealCount(this);
|
||||
}
|
||||
|
||||
float Mob::HealRotationHealFrequency()
|
||||
{
|
||||
if (!IsHealRotationTarget())
|
||||
return 0.0f;
|
||||
|
||||
return m_target_of_heal_rotation->HealFrequency(this);
|
||||
}
|
||||
|
||||
float Mob::HealRotationExtendedHealFrequency()
|
||||
{
|
||||
if (!IsHealRotationTarget())
|
||||
return 0.0f;
|
||||
|
||||
return m_target_of_heal_rotation->ExtendedHealFrequency(this);
|
||||
}
|
||||
#endif
|
||||
|
||||
25
zone/mob.h
25
zone/mob.h
@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemu.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -29,6 +29,10 @@
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#ifdef BOTS
|
||||
#include "heal_rotation.h"
|
||||
#endif
|
||||
|
||||
char* strn0cpy(char* dest, const char* source, uint32 size);
|
||||
|
||||
#define MAX_SPECIAL_ATTACK_PARAMS 8
|
||||
@ -1005,6 +1009,20 @@ public:
|
||||
void DelAssistCap() { --npc_assist_cap; }
|
||||
void ResetAssistCap() { npc_assist_cap = 0; }
|
||||
|
||||
// Bots HealRotation methods
|
||||
#ifdef BOTS
|
||||
bool IsHealRotationTarget() { return (m_target_of_heal_rotation.use_count() && m_target_of_heal_rotation.get()); }
|
||||
bool JoinHealRotationTargetPool(std::shared_ptr<HealRotation>* heal_rotation);
|
||||
bool LeaveHealRotationTargetPool();
|
||||
|
||||
uint32 HealRotationHealCount();
|
||||
uint32 HealRotationExtendedHealCount();
|
||||
float HealRotationHealFrequency();
|
||||
float HealRotationExtendedHealFrequency();
|
||||
|
||||
const std::shared_ptr<HealRotation>* TargetOfHealRotation() const { return &m_target_of_heal_rotation; }
|
||||
#endif
|
||||
|
||||
protected:
|
||||
void CommonDamage(Mob* other, int32 &damage, const uint16 spell_id, const SkillUseTypes attack_skill, bool &avoidable, const int8 buffslot, const bool iBuffTic, int special = 0);
|
||||
static uint16 GetProcID(uint16 spell_id, uint8 effect_index);
|
||||
@ -1373,6 +1391,11 @@ protected:
|
||||
private:
|
||||
void _StopSong(); //this is not what you think it is
|
||||
Mob* target;
|
||||
|
||||
#ifdef BOTS
|
||||
std::shared_ptr<HealRotation> m_target_of_heal_rotation;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
30
zone/net.cpp
30
zone/net.cpp
@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemu.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -52,6 +52,10 @@
|
||||
#include "zone.h"
|
||||
#include "queryserv.h"
|
||||
#include "command.h"
|
||||
#ifdef BOTS
|
||||
#include "bot_command.h"
|
||||
#include "bot_database.h"
|
||||
#endif
|
||||
#include "zone_config.h"
|
||||
#include "titles.h"
|
||||
#include "guild_mgr.h"
|
||||
@ -203,6 +207,18 @@ int main(int argc, char** argv) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef BOTS
|
||||
if (!botdb.Connect(
|
||||
Config->DatabaseHost.c_str(),
|
||||
Config->DatabaseUsername.c_str(),
|
||||
Config->DatabasePassword.c_str(),
|
||||
Config->DatabaseDB.c_str(),
|
||||
Config->DatabasePort)) {
|
||||
Log.Out(Logs::General, Logs::Error, "Cannot continue without a bots database connection.");
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Register Log System and Settings */
|
||||
Log.OnLogHookCallBackZone(&Zone::GMSayHookCallBackProcess);
|
||||
database.LoadLogSettings(Log.log_settings);
|
||||
@ -325,6 +341,15 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BOTS
|
||||
Log.Out(Logs::General, Logs::Zone_Server, "Loading bot commands");
|
||||
int botretval = bot_command_init();
|
||||
if (botretval<0)
|
||||
Log.Out(Logs::General, Logs::Error, "Bot command loading FAILED");
|
||||
else
|
||||
Log.Out(Logs::General, Logs::Zone_Server, "%d bot commands loaded", botretval);
|
||||
#endif
|
||||
|
||||
if(RuleB(TaskSystem, EnableTaskSystem)) {
|
||||
Log.Out(Logs::General, Logs::Tasks, "[INIT] Loading Tasks");
|
||||
taskmanager = new TaskManager;
|
||||
@ -524,6 +549,9 @@ int main(int argc, char** argv) {
|
||||
worldserver.Disconnect();
|
||||
safe_delete(taskmanager);
|
||||
command_deinit();
|
||||
#ifdef BOTS
|
||||
bot_command_deinit();
|
||||
#endif
|
||||
safe_delete(parse);
|
||||
Log.Out(Logs::General, Logs::Zone_Server, "Proper zone shutdown complete.");
|
||||
Log.CloseFileLogs();
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemu.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -1994,7 +1994,7 @@ bool WorldServer::SendVoiceMacro(Client* From, uint32 Type, char* Target, uint32
|
||||
|
||||
svm->Type = Type;
|
||||
|
||||
svm->Voice = (GetArrayRace(From->GetRace()) * 2) + From->GetGender();
|
||||
svm->Voice = (GetPlayerRaceValue(From->GetRace()) * 2) + From->GetGender();
|
||||
|
||||
svm->MacroNumber = MacroNumber;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user