[GM Commands] Split GM Commands Into Separate Files (#1766)

* Split GM commands into their own files

* Code cleanup
This commit is contained in:
Chris Miles 2021-11-14 22:48:47 -06:00 committed by GitHub
parent 293361a1f7
commit 0550fcfd3f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
291 changed files with 19224 additions and 15798 deletions

2
.gitignore vendored
View File

@ -54,3 +54,5 @@ bin/
/Win32
/x64
/client_files/**/CMakeFiles/
.idea

View File

@ -64,4 +64,9 @@ void FileUtil::mkdir(const std::string& directory_name)
}
::mkdir(directory_name.c_str(), 0755);
#endif
}
}
bool file_exists(const std::string& name) {
std::ifstream f(name.c_str());
return f.good();
}

View File

@ -28,5 +28,6 @@ public:
static void mkdir(const std::string& directory_name);
};
bool file_exists(const std::string& name);
#endif //EQEMU_FILE_UTIL_H

View File

@ -1239,10 +1239,10 @@ bool IsEffectIgnoredInStacking(int spa)
case SE_GravityEffect:
case 425:
//Spell effects implemented after ROF2, following same pattern, lets assume these should go here.
case SE_Fc_Spell_Damage_Pct_IncomingPC:
case SE_Fc_Spell_Damage_Pct_IncomingPC:
case SE_Fc_Spell_Damage_Amt_IncomingPC:
case SE_Ff_CasterClass:
case SE_Ff_Same_Caster:
case SE_Ff_Same_Caster:
case SE_Proc_Timer_Modifier:
case SE_Weapon_Stance:
case SE_TwinCastBlocker:
@ -1417,8 +1417,8 @@ bool IsInstrumentModAppliedToSpellEffect(int32 spell_id, int effect)
case SE_MinDamageModifier:
case SE_ProcChance:
case SE_PetFlurry: // ? Need verified
case SE_DiseaseCounter:
case SE_PoisonCounter:
case SE_DiseaseCounter:
case SE_PoisonCounter:
case SE_CurseCounter:
case SE_CorruptionCounter:
return true;
@ -1576,7 +1576,7 @@ int GetSpellStatValue(uint32 spell_id, const char* stat_identifier, uint8 slot)
return 0;
}
bool IsVirusSpell(int32 spell_id)
bool IsVirusSpell(int32 spell_id)
{
if (GetViralMinSpreadTime(spell_id) && GetViralMaxSpreadTime(spell_id) && GetViralSpreadRange(spell_id)){
return true;
@ -1584,17 +1584,17 @@ bool IsVirusSpell(int32 spell_id)
return false;
}
int32 GetViralMinSpreadTime(int32 spell_id)
int32 GetViralMinSpreadTime(int32 spell_id)
{
return spells[spell_id].viral_targets;
}
int32 GetViralMaxSpreadTime(int32 spell_id)
int32 GetViralMaxSpreadTime(int32 spell_id)
{
return spells[spell_id].viral_timer;
}
int32 GetViralSpreadRange(int32 spell_id)
int32 GetViralSpreadRange(int32 spell_id)
{
return spells[spell_id].viral_range;
}
@ -1605,7 +1605,7 @@ uint32 GetProcLimitTimer(int32 spell_id, int proc_type) {
if (!IsValidSpell(spell_id)) {
return 0;
}
bool use_next_timer = false;
for (int i = 0; i < EFFECT_COUNT; ++i) {
@ -1633,3 +1633,41 @@ uint32 GetProcLimitTimer(int32 spell_id, int proc_type) {
}
return 0;
}
bool CastRestrictedSpell(int spellid)
{
switch (spellid) {
case SPELL_TOUCH_OF_VINITRAS:
case SPELL_DESPERATE_HOPE:
case SPELL_CHARM:
case SPELL_METAMORPHOSIS65:
case SPELL_JT_BUFF:
case SPELL_CAN_O_WHOOP_ASS:
case SPELL_PHOENIX_CHARM:
case SPELL_CAZIC_TOUCH:
case SPELL_AVATAR_KNOCKBACK:
case SPELL_SHAPECHANGE65:
case SPELL_SUNSET_HOME1218:
case SPELL_SUNSET_HOME819:
case SPELL_SHAPECHANGE75:
case SPELL_SHAPECHANGE80:
case SPELL_SHAPECHANGE85:
case SPELL_SHAPECHANGE90:
case SPELL_SHAPECHANGE95:
case SPELL_SHAPECHANGE100:
case SPELL_SHAPECHANGE25:
case SPELL_SHAPECHANGE30:
case SPELL_SHAPECHANGE35:
case SPELL_SHAPECHANGE40:
case SPELL_SHAPECHANGE45:
case SPELL_SHAPECHANGE50:
case SPELL_NPC_AEGOLISM:
case SPELL_SHAPECHANGE55:
case SPELL_SHAPECHANGE60:
case SPELL_COMMAND_OF_DRUZZIL:
case SPELL_SHAPECHANGE70:
return true;
default:
return false;
}
}

View File

@ -219,292 +219,292 @@ enum SpellRestriction
{
UNKNOWN_3 = 3, // | caster restriction | seen in spell 30183 Mind Spiral
IS_NOT_ON_HORSE = 5, // | caster restriction |
IS_ANIMAL_OR_HUMANOID = 100, // This spell will only work on animals or humanoid creatures.
IS_DRAGON = 101, // This spell will only work on dragons.
IS_ANIMAL_OR_INSECT = 102, // This spell will only work on animals or insects.
IS_BODY_TYPE_MISC = 103, // This spell will only work on humanoids, lycanthropes, giants, Kael Drakkel giants, Coldain, animals, insects, constructs, dragons, Skyshrine dragons, Muramites, or creatures constructed from magic.
IS_BODY_TYPE_MISC2 = 104, // This spell will only work on humanoids, lycanthropes, giants, Kael Drakkel giants, Coldain, animals, or insects.
IS_PLANT = 105, // This spell will only work on plants.
IS_ANIMAL_OR_HUMANOID = 100, // This spell will only work on animals or humanoid creatures.
IS_DRAGON = 101, // This spell will only work on dragons.
IS_ANIMAL_OR_INSECT = 102, // This spell will only work on animals or insects.
IS_BODY_TYPE_MISC = 103, // This spell will only work on humanoids, lycanthropes, giants, Kael Drakkel giants, Coldain, animals, insects, constructs, dragons, Skyshrine dragons, Muramites, or creatures constructed from magic.
IS_BODY_TYPE_MISC2 = 104, // This spell will only work on humanoids, lycanthropes, giants, Kael Drakkel giants, Coldain, animals, or insects.
IS_PLANT = 105, // This spell will only work on plants.
IS_GIANT = 106, // This spell will only work on animals. | Live used to have this on spells restricted to Giants, but those spells were removed... We still have them
IS_NOT_ANIMAL_OR_HUMANOID = 108, // This spell will only work on targets that are neither animals or humanoid.
IS_BIXIE = 109, // This spell will only work on bixies.
IS_HARPY = 110, // This spell will only work on harpies.
IS_GNOLL = 111, // This spell will only work on gnolls.
IS_SPORALI = 112, // This spell will only work on fungusoids.
IS_KOBOLD = 113, // This spell will only work on kobolds.
IS_FROSTCRYPT_SHADE = 114, // This spell will only work on undead creatures or the Shades of Frostcrypt.
IS_DRAKKIN = 115, // This spell will only work on Drakkin.
IS_UNDEAD_OR_VALDEHOLM_GIANT = 116, // This spell will only work on undead creatures or the inhabitants of Valdeholm.
IS_ANIMAL_OR_PLANT = 117, // This spell will only work on plants or animals.
IS_SUMMONED = 118, // This spell will only work on constructs, elementals, or summoned elemental minions.
IS_WIZARD_USED_ON_MAGE_FIRE_PET = 119, // This spell will only work on wizards. | Live uses this on high level mage fire pets, which are wizard class
IS_UNDEAD = 120, //
IS_NOT_UNDEAD_OR_SUMMONED_OR_VAMPIRE = 121, // This spell will only work on creatures that are not undead, constructs, elementals, or vampires.
IS_FAE_OR_PIXIE = 122, // This spell will only work on Fae or pixies.
IS_HUMANOID = 123, //
IS_UNDEAD_AND_HP_LESS_THAN_10_PCT = 124, // The Essence Extractor whirrs but does not light up.
IS_CLOCKWORK_AND_HP_LESS_THAN_45_PCT = 125, // This spell will only work on clockwork gnomes.
IS_WISP_AND_HP_LESS_THAN_10_PCT = 126, // This spell will only work on wisps at or below 10% of their maximum HP.
IS_CLASS_MELEE_THAT_CAN_BASH_OR_KICK_EXCEPT_BARD = 127, // This spell will only work on non-bard targets that can bash or kick.
IS_CLASS_PURE_MELEE = 128, // This spell will only affect melee classes (warriors, monks, rogues, and berserkers).
IS_CLASS_PURE_CASTER = 129, // This spell will only affect pure caster classes (necromancers, wizards, magicians, and enchanters).
IS_CLASS_HYBRID_CLASS = 130, // This spell will only affect hybrid classes (paladins, rangers, shadow knights, bards, and beastlords).
IS_CLASS_WARRIOR = 131, // This spell will only affect Warriors.
IS_CLASS_CLERIC = 132, // This spell will only affect Clerics.
IS_CLASS_PALADIN = 133, // This spell will only affect Paladins.
IS_CLASS_RANGER = 134, // This spell will only affect Rangers.
IS_CLASS_SHADOWKNIGHT = 135, // This spell will only affect Shadow Knights.
IS_CLASS_DRUID = 136, // This spell will only affect Druids.
IS_CLASS_MONK = 137, // This spell will only affect Monks.
IS_CLASS_BARD = 138, // This spell will only affect Bards.
IS_CLASS_ROGUE = 139, // This spell will only affect Rogues.
IS_CLASS_SHAMAN = 140, // This spell will only affect Shamans.
IS_CLASS_NECRO = 141, // This spell will only affect Necromancers.
IS_CLASS_WIZARD = 142, // This spell will only affect Wizards.
IS_CLASS_MAGE = 143, // This spell will only affect Magicians.
IS_CLASS_ENCHANTER = 144, // This spell will only affect Enchanters.
IS_CLASS_BEASTLORD = 145, // This spell will only affect Beastlords.
IS_CLASS_BERSERKER = 146, // This spell will only affect Berserkers.
IS_CLASS_CLR_SHM_DRU = 147, // This spell will only affect priest classes (clerics, druids, and shaman).
IS_CLASS_NOT_WAR_PAL_SK = 148, // This spell will not affect Warriors, Paladins, or Shadow Knights.
IS_LEVEL_UNDER_100 = 150, // This spell will not affect any target over level 100.
IS_NOT_RAID_BOSS = 190, // This spell will not affect raid bosses.
IS_RAID_BOSS = 191, // This spell will only affect raid bosses.
FRENZIED_BURNOUT_ACTIVE = 192, // This spell will only cast if you have Frenzied Burnout active.
FRENZIED_BURNOUT_NOT_ACTIVE = 193, // This spell will only cast if you do not have Frenzied Burnout active.
IS_NOT_ANIMAL_OR_HUMANOID = 108, // This spell will only work on targets that are neither animals or humanoid.
IS_BIXIE = 109, // This spell will only work on bixies.
IS_HARPY = 110, // This spell will only work on harpies.
IS_GNOLL = 111, // This spell will only work on gnolls.
IS_SPORALI = 112, // This spell will only work on fungusoids.
IS_KOBOLD = 113, // This spell will only work on kobolds.
IS_FROSTCRYPT_SHADE = 114, // This spell will only work on undead creatures or the Shades of Frostcrypt.
IS_DRAKKIN = 115, // This spell will only work on Drakkin.
IS_UNDEAD_OR_VALDEHOLM_GIANT = 116, // This spell will only work on undead creatures or the inhabitants of Valdeholm.
IS_ANIMAL_OR_PLANT = 117, // This spell will only work on plants or animals.
IS_SUMMONED = 118, // This spell will only work on constructs, elementals, or summoned elemental minions.
IS_WIZARD_USED_ON_MAGE_FIRE_PET = 119, // This spell will only work on wizards. | Live uses this on high level mage fire pets, which are wizard class
IS_UNDEAD = 120, //
IS_NOT_UNDEAD_OR_SUMMONED_OR_VAMPIRE = 121, // This spell will only work on creatures that are not undead, constructs, elementals, or vampires.
IS_FAE_OR_PIXIE = 122, // This spell will only work on Fae or pixies.
IS_HUMANOID = 123, //
IS_UNDEAD_AND_HP_LESS_THAN_10_PCT = 124, // The Essence Extractor whirrs but does not light up.
IS_CLOCKWORK_AND_HP_LESS_THAN_45_PCT = 125, // This spell will only work on clockwork gnomes.
IS_WISP_AND_HP_LESS_THAN_10_PCT = 126, // This spell will only work on wisps at or below 10% of their maximum HP.
IS_CLASS_MELEE_THAT_CAN_BASH_OR_KICK_EXCEPT_BARD = 127, // This spell will only work on non-bard targets that can bash or kick.
IS_CLASS_PURE_MELEE = 128, // This spell will only affect melee classes (warriors, monks, rogues, and berserkers).
IS_CLASS_PURE_CASTER = 129, // This spell will only affect pure caster classes (necromancers, wizards, magicians, and enchanters).
IS_CLASS_HYBRID_CLASS = 130, // This spell will only affect hybrid classes (paladins, rangers, shadow knights, bards, and beastlords).
IS_CLASS_WARRIOR = 131, // This spell will only affect Warriors.
IS_CLASS_CLERIC = 132, // This spell will only affect Clerics.
IS_CLASS_PALADIN = 133, // This spell will only affect Paladins.
IS_CLASS_RANGER = 134, // This spell will only affect Rangers.
IS_CLASS_SHADOWKNIGHT = 135, // This spell will only affect Shadow Knights.
IS_CLASS_DRUID = 136, // This spell will only affect Druids.
IS_CLASS_MONK = 137, // This spell will only affect Monks.
IS_CLASS_BARD = 138, // This spell will only affect Bards.
IS_CLASS_ROGUE = 139, // This spell will only affect Rogues.
IS_CLASS_SHAMAN = 140, // This spell will only affect Shamans.
IS_CLASS_NECRO = 141, // This spell will only affect Necromancers.
IS_CLASS_WIZARD = 142, // This spell will only affect Wizards.
IS_CLASS_MAGE = 143, // This spell will only affect Magicians.
IS_CLASS_ENCHANTER = 144, // This spell will only affect Enchanters.
IS_CLASS_BEASTLORD = 145, // This spell will only affect Beastlords.
IS_CLASS_BERSERKER = 146, // This spell will only affect Berserkers.
IS_CLASS_CLR_SHM_DRU = 147, // This spell will only affect priest classes (clerics, druids, and shaman).
IS_CLASS_NOT_WAR_PAL_SK = 148, // This spell will not affect Warriors, Paladins, or Shadow Knights.
IS_LEVEL_UNDER_100 = 150, // This spell will not affect any target over level 100.
IS_NOT_RAID_BOSS = 190, // This spell will not affect raid bosses.
IS_RAID_BOSS = 191, // This spell will only affect raid bosses.
FRENZIED_BURNOUT_ACTIVE = 192, // This spell will only cast if you have Frenzied Burnout active.
FRENZIED_BURNOUT_NOT_ACTIVE = 193, // This spell will only cast if you do not have Frenzied Burnout active.
UNKNOWN_199 = 199, //
IS_HP_ABOVE_75_PCT = 201, //
IS_HP_ABOVE_75_PCT = 201, //
IS_HP_LESS_THAN_20_PCT = 203, // Your target's HP must be at 20% of its maximum or below. | caster restriction |
IS_HP_LESS_THAN_50_PCT = 204, // Your target's HP must be at 50% of its maximum or below. | caster restriction |
IS_HP_LESS_THAN_75_PCT = 205, // Your target's HP must be at 75% of its maximum or below.
IS_NOT_IN_COMBAT = 216, // This spell will only affect creatures that are not in combat.
HAS_AT_LEAST_1_PET_ON_HATELIST = 221, //
HAS_AT_LEAST_2_PETS_ON_HATELIST = 222, //
HAS_AT_LEAST_3_PETS_ON_HATELIST = 223, //
HAS_AT_LEAST_4_PETS_ON_HATELIST = 224, //
HAS_AT_LEAST_5_PETS_ON_HATELIST = 225, //
HAS_AT_LEAST_6_PETS_ON_HATELIST = 226, //
HAS_AT_LEAST_7_PETS_ON_HATELIST = 227, //
HAS_AT_LEAST_8_PETS_ON_HATELIST = 228, //
HAS_AT_LEAST_9_PETS_ON_HATELIST = 229, //
HAS_AT_LEAST_10_PETS_ON_HATELIST = 230, //
HAS_AT_LEAST_11_PETS_ON_HATELIST = 231, //
HAS_AT_LEAST_12_PETS_ON_HATELIST = 232, //
HAS_AT_LEAST_13_PETS_ON_HATELIST = 233, //
HAS_AT_LEAST_14_PETS_ON_HATELIST = 234, //
HAS_AT_LEAST_15_PETS_ON_HATELIST = 235, //
HAS_AT_LEAST_16_PETS_ON_HATELIST = 236, //
HAS_AT_LEAST_17_PETS_ON_HATELIST = 237, //
HAS_AT_LEAST_18_PETS_ON_HATELIST = 238, //
HAS_AT_LEAST_19_PETS_ON_HATELIST = 239, //
HAS_AT_LEAST_20_PETS_ON_HATELIST = 240, //
IS_HP_LESS_THAN_75_PCT = 205, // Your target's HP must be at 75% of its maximum or below.
IS_NOT_IN_COMBAT = 216, // This spell will only affect creatures that are not in combat.
HAS_AT_LEAST_1_PET_ON_HATELIST = 221, //
HAS_AT_LEAST_2_PETS_ON_HATELIST = 222, //
HAS_AT_LEAST_3_PETS_ON_HATELIST = 223, //
HAS_AT_LEAST_4_PETS_ON_HATELIST = 224, //
HAS_AT_LEAST_5_PETS_ON_HATELIST = 225, //
HAS_AT_LEAST_6_PETS_ON_HATELIST = 226, //
HAS_AT_LEAST_7_PETS_ON_HATELIST = 227, //
HAS_AT_LEAST_8_PETS_ON_HATELIST = 228, //
HAS_AT_LEAST_9_PETS_ON_HATELIST = 229, //
HAS_AT_LEAST_10_PETS_ON_HATELIST = 230, //
HAS_AT_LEAST_11_PETS_ON_HATELIST = 231, //
HAS_AT_LEAST_12_PETS_ON_HATELIST = 232, //
HAS_AT_LEAST_13_PETS_ON_HATELIST = 233, //
HAS_AT_LEAST_14_PETS_ON_HATELIST = 234, //
HAS_AT_LEAST_15_PETS_ON_HATELIST = 235, //
HAS_AT_LEAST_16_PETS_ON_HATELIST = 236, //
HAS_AT_LEAST_17_PETS_ON_HATELIST = 237, //
HAS_AT_LEAST_18_PETS_ON_HATELIST = 238, //
HAS_AT_LEAST_19_PETS_ON_HATELIST = 239, //
HAS_AT_LEAST_20_PETS_ON_HATELIST = 240, //
IS_HP_LESS_THAN_35_PCT = 250, // Your target's HP must be at 35% of its maximum or below.
HAS_BETWEEN_1_TO_2_PETS_ON_HATELIST = 260, // between 1 and 2 pets
HAS_BETWEEN_3_TO_5_PETS_ON_HATELIST = 261, // between 3 and 5 pets
HAS_BETWEEN_6_TO_9_PETS_ON_HATELIST = 262, // between 6 and 9 pets
HAS_BETWEEN_10_TO_14_PETS_ON_HATELIST = 263, // between 10 and 14 pets
HAS_MORE_THAN_14_PETS_ON_HATELIST = 264, // 15 or more pets
IS_CLASS_CHAIN_OR_PLATE = 304, // This spell will only affect plate or chain wearing classes.
IS_HP_BETWEEN_5_AND_9_PCT = 350, // Your target's HP must be between 5% and 9% of its maximum.
IS_HP_BETWEEN_10_AND_14_PCT = 351, // Your target's HP must be between 10% and 14% of its maximum.
IS_HP_BETWEEN_15_AND_19_PCT = 352, // Your target's HP must be between 15% and 19% of its maximum.
IS_HP_BETWEEN_20_AND_24_PCT = 353, // Your target's HP must be between 20% and 24% of its maximum.
IS_HP_BETWEEN_25_AND_29_PCT = 354, // Your target's HP must be between 25% and 29% of its maximum.
IS_HP_BETWEEN_30_AND_34_PCT = 355, // Your target's HP must be between 30% and 34% of its maximum.
IS_HP_BETWEEN_35_AND_39_PCT = 356, // Your target's HP must be between 35% and 39% of its maximum.
IS_HP_BETWEEN_40_AND_44_PCT = 357, // Your target's HP must be between 40% and 44% of its maximum.
IS_HP_BETWEEN_45_AND_49_PCT = 358, // Your target's HP must be between 45% and 49% of its maximum.
IS_HP_BETWEEN_50_AND_54_PCT = 359, // Your target's HP must be between 50% and 54% of its maximum.
IS_HP_BETWEEN_55_AND_59_PCT = 360, // Your target's HP must be between 55% and 59% of its maximum.
IS_HP_BETWEEN_5_AND_15_PCT = 398, // Your target's HP must be between 5% and 15% of its maximum.
IS_HP_BETWEEN_15_AND_25_PCT = 399, // Your target's HP must be between 15% and 25% of its maximum.
IS_HP_BETWEEN_1_AND_25_PCT = 400, // Your target's HP must be at 25% of its maximum or below.
IS_HP_BETWEEN_25_AND_35_PCT = 401, // Your target's HP must be between 25% and 35% of its maximum.
IS_HP_BETWEEN_35_AND_45_PCT = 402, // Your target's HP must be between 35% and 45% of its maximum.
IS_HP_BETWEEN_45_AND_55_PCT = 403, // Your target's HP must be between 45% and 55% of its maximum.
IS_HP_BETWEEN_55_AND_65_PCT = 404, // Your target's HP must be between 55% and 65% of its maximum.
IS_HP_BETWEEN_65_AND_75_PCT = 405, // Your target's HP must be between 65% and 75% of its maximum.
IS_HP_BETWEEN_75_AND_85_PCT = 406, // Your target's HP must be between 75% and 85% of its maximum.
IS_HP_BETWEEN_85_AND_95_PCT = 407, // Your target's HP must be between 85% and 95% of its maximum.
IS_HP_ABOVE_45_PCT = 408, // Your target's HP must be at least 45% of its maximum.
IS_HP_ABOVE_55_PCT = 409, // Your target's HP must be at least 55% of its maximum.
UNKNOWN_TOO_MUCH_HP_410 = 410, // Your target has too much HP to be affected by this spell.
UNKNOWN_TOO_MUCH_HP_411 = 411, // Your target has too much HP to be affected by this spell.
IS_HP_ABOVE_99_PCT = 412, //
IS_MANA_ABOVE_10_PCT = 429, // You must have at least 10% of your maximum mana available to cast this spell. | caster restriction |
IS_HP_BELOW_5_PCT = 501, //
IS_HP_BELOW_10_PCT = 502, //
IS_HP_BELOW_15_PCT = 503, //
IS_HP_BELOW_20_PCT = 504, // Your target's HP must be at 20% of its maximum or below.
IS_HP_BELOW_25_PCT = 505, //
IS_HP_BELOW_30_PCT = 506, //
IS_HP_BELOW_35_PCT = 507, //
IS_HP_BELOW_40_PCT = 508, //
IS_HP_BELOW_45_PCT = 509, // Your target's HP must be at 45% of its maximum or below.
IS_HP_BELOW_50_PCT = 510, //
IS_HP_BELOW_55_PCT = 511, //
IS_HP_BELOW_60_PCT = 512, //
IS_HP_BELOW_65_PCT = 513, //
IS_HP_BELOW_70_PCT = 514, //
IS_HP_BELOW_75_PCT = 515, //
IS_HP_BELOW_80_PCT = 516, //
IS_HP_BELOW_85_PCT = 517, //
HAS_BETWEEN_1_TO_2_PETS_ON_HATELIST = 260, // between 1 and 2 pets
HAS_BETWEEN_3_TO_5_PETS_ON_HATELIST = 261, // between 3 and 5 pets
HAS_BETWEEN_6_TO_9_PETS_ON_HATELIST = 262, // between 6 and 9 pets
HAS_BETWEEN_10_TO_14_PETS_ON_HATELIST = 263, // between 10 and 14 pets
HAS_MORE_THAN_14_PETS_ON_HATELIST = 264, // 15 or more pets
IS_CLASS_CHAIN_OR_PLATE = 304, // This spell will only affect plate or chain wearing classes.
IS_HP_BETWEEN_5_AND_9_PCT = 350, // Your target's HP must be between 5% and 9% of its maximum.
IS_HP_BETWEEN_10_AND_14_PCT = 351, // Your target's HP must be between 10% and 14% of its maximum.
IS_HP_BETWEEN_15_AND_19_PCT = 352, // Your target's HP must be between 15% and 19% of its maximum.
IS_HP_BETWEEN_20_AND_24_PCT = 353, // Your target's HP must be between 20% and 24% of its maximum.
IS_HP_BETWEEN_25_AND_29_PCT = 354, // Your target's HP must be between 25% and 29% of its maximum.
IS_HP_BETWEEN_30_AND_34_PCT = 355, // Your target's HP must be between 30% and 34% of its maximum.
IS_HP_BETWEEN_35_AND_39_PCT = 356, // Your target's HP must be between 35% and 39% of its maximum.
IS_HP_BETWEEN_40_AND_44_PCT = 357, // Your target's HP must be between 40% and 44% of its maximum.
IS_HP_BETWEEN_45_AND_49_PCT = 358, // Your target's HP must be between 45% and 49% of its maximum.
IS_HP_BETWEEN_50_AND_54_PCT = 359, // Your target's HP must be between 50% and 54% of its maximum.
IS_HP_BETWEEN_55_AND_59_PCT = 360, // Your target's HP must be between 55% and 59% of its maximum.
IS_HP_BETWEEN_5_AND_15_PCT = 398, // Your target's HP must be between 5% and 15% of its maximum.
IS_HP_BETWEEN_15_AND_25_PCT = 399, // Your target's HP must be between 15% and 25% of its maximum.
IS_HP_BETWEEN_1_AND_25_PCT = 400, // Your target's HP must be at 25% of its maximum or below.
IS_HP_BETWEEN_25_AND_35_PCT = 401, // Your target's HP must be between 25% and 35% of its maximum.
IS_HP_BETWEEN_35_AND_45_PCT = 402, // Your target's HP must be between 35% and 45% of its maximum.
IS_HP_BETWEEN_45_AND_55_PCT = 403, // Your target's HP must be between 45% and 55% of its maximum.
IS_HP_BETWEEN_55_AND_65_PCT = 404, // Your target's HP must be between 55% and 65% of its maximum.
IS_HP_BETWEEN_65_AND_75_PCT = 405, // Your target's HP must be between 65% and 75% of its maximum.
IS_HP_BETWEEN_75_AND_85_PCT = 406, // Your target's HP must be between 75% and 85% of its maximum.
IS_HP_BETWEEN_85_AND_95_PCT = 407, // Your target's HP must be between 85% and 95% of its maximum.
IS_HP_ABOVE_45_PCT = 408, // Your target's HP must be at least 45% of its maximum.
IS_HP_ABOVE_55_PCT = 409, // Your target's HP must be at least 55% of its maximum.
UNKNOWN_TOO_MUCH_HP_410 = 410, // Your target has too much HP to be affected by this spell.
UNKNOWN_TOO_MUCH_HP_411 = 411, // Your target has too much HP to be affected by this spell.
IS_HP_ABOVE_99_PCT = 412, //
IS_MANA_ABOVE_10_PCT = 429, // You must have at least 10% of your maximum mana available to cast this spell. | caster restriction |
IS_HP_BELOW_5_PCT = 501, //
IS_HP_BELOW_10_PCT = 502, //
IS_HP_BELOW_15_PCT = 503, //
IS_HP_BELOW_20_PCT = 504, // Your target's HP must be at 20% of its maximum or below.
IS_HP_BELOW_25_PCT = 505, //
IS_HP_BELOW_30_PCT = 506, //
IS_HP_BELOW_35_PCT = 507, //
IS_HP_BELOW_40_PCT = 508, //
IS_HP_BELOW_45_PCT = 509, // Your target's HP must be at 45% of its maximum or below.
IS_HP_BELOW_50_PCT = 510, //
IS_HP_BELOW_55_PCT = 511, //
IS_HP_BELOW_60_PCT = 512, //
IS_HP_BELOW_65_PCT = 513, //
IS_HP_BELOW_70_PCT = 514, //
IS_HP_BELOW_75_PCT = 515, //
IS_HP_BELOW_80_PCT = 516, //
IS_HP_BELOW_85_PCT = 517, //
IS_HP_BELOW_90_PCT = 518, // This ability requires you to be at or below 90% of your maximum HP. | caster restriction |
IS_HP_BELOW_95_PCT = 519, //
IS_HP_BELOW_95_PCT = 519, //
IS_MANA_BELOW_UNKNOWN_PCT = 521, //
IS_ENDURANCE_BELOW_40_PCT = 522, //
IS_MANA_BELOW_40_PCT = 523, //
IS_HP_ABOVE_20_PCT = 524, // Your target's HP must be at least 21% of its maximum.
IS_ENDURANCE_BELOW_40_PCT = 522, //
IS_MANA_BELOW_40_PCT = 523, //
IS_HP_ABOVE_20_PCT = 524, // Your target's HP must be at least 21% of its maximum.
IS_BODY_TYPE_UNDEFINED = 600, // This spell will only work on creatures with an undefined body type.
IS_BODY_TYPE_HUMANOID = 601, // This spell will only work on humanoid creatures.
IS_BODY_TYPE_WEREWOLF = 602, // This spell will only work on lycanthrope creatures.
IS_BODY_TYPE_UNDEAD = 603, // This spell will only work on undead creatures.
IS_BODY_TYPE_GIANTS = 604, // This spell will only work on giants.
IS_BODY_TYPE_CONSTRUCTS = 605, // This spell will only work on constructs.
IS_BODY_TYPE_EXTRAPLANAR = 606, // This spell will only work on extraplanar creatures.
IS_BODY_TYPE_MAGICAL_CREATURE = 607, // This spell will only work on creatures constructed from magic.
IS_BODY_TYPE_UNDEADPET = 608, // This spell will only work on animated undead servants.
IS_BODY_TYPE_KAELGIANT = 609, // This spell will only work on the Giants of Kael Drakkal.
IS_BODY_TYPE_COLDAIN = 610, // This spell will only work on Coldain Dwarves.
IS_BODY_TYPE_VAMPIRE = 612, // This spell will only work on vampires.
IS_BODY_TYPE_ATEN_HA_RA = 613, // This spell will only work on Aten Ha Ra.
IS_BODY_TYPE_GREATER_AHKEVANS = 614, // This spell will only work on Greater Ahkevans.
IS_BODY_TYPE_KHATI_SHA = 615, // This spell will only work on Khati Sha.
IS_BODY_TYPE_LORD_INQUISITOR_SERU = 616, // This spell will only work on Lord Inquisitor Seru.
IS_BODY_TYPE_GRIEG_VENEFICUS = 617, // This spell will only work on Grieg Veneficus.
IS_BODY_TYPE_HUMANOID = 601, // This spell will only work on humanoid creatures.
IS_BODY_TYPE_WEREWOLF = 602, // This spell will only work on lycanthrope creatures.
IS_BODY_TYPE_UNDEAD = 603, // This spell will only work on undead creatures.
IS_BODY_TYPE_GIANTS = 604, // This spell will only work on giants.
IS_BODY_TYPE_CONSTRUCTS = 605, // This spell will only work on constructs.
IS_BODY_TYPE_EXTRAPLANAR = 606, // This spell will only work on extraplanar creatures.
IS_BODY_TYPE_MAGICAL_CREATURE = 607, // This spell will only work on creatures constructed from magic.
IS_BODY_TYPE_UNDEADPET = 608, // This spell will only work on animated undead servants.
IS_BODY_TYPE_KAELGIANT = 609, // This spell will only work on the Giants of Kael Drakkal.
IS_BODY_TYPE_COLDAIN = 610, // This spell will only work on Coldain Dwarves.
IS_BODY_TYPE_VAMPIRE = 612, // This spell will only work on vampires.
IS_BODY_TYPE_ATEN_HA_RA = 613, // This spell will only work on Aten Ha Ra.
IS_BODY_TYPE_GREATER_AHKEVANS = 614, // This spell will only work on Greater Ahkevans.
IS_BODY_TYPE_KHATI_SHA = 615, // This spell will only work on Khati Sha.
IS_BODY_TYPE_LORD_INQUISITOR_SERU = 616, // This spell will only work on Lord Inquisitor Seru.
IS_BODY_TYPE_GRIEG_VENEFICUS = 617, // This spell will only work on Grieg Veneficus.
IS_BODY_TYPE_FROM_PLANE_OF_WAR = 619, // This spell will only work on creatures from the Plane of War.
IS_BODY_TYPE_LUGGALD = 620, // This spell will only work on Luggalds.
IS_BODY_TYPE_ANIMAL = 621, // This spell will only work on animals.
IS_BODY_TYPE_INSECT = 622, // This spell will only work on insects.
IS_BODY_TYPE_MONSTER = 623, // This spell will only work on monsters.
IS_BODY_TYPE_ELEMENTAL = 624, // This spell will only work on elemental creatures.
IS_BODY_TYPE_PLANT = 625, // This spell will only work on plants.
IS_BODY_TYPE_DRAGON2 = 626, // This spell will only work on dragons.
IS_BODY_TYPE_SUMMONED_ELEMENTAL = 627, // This spell will only work on summoned elementals.
IS_BODY_TYPE_WARDER = 628, //
IS_BODY_TYPE_DRAGON_OF_TOV = 630, // This spell will only work on Dragons of Veeshan's Temple.
IS_BODY_TYPE_FAMILIAR = 631, // This spell will only work on familiars.
IS_BODY_TYPE_MURAMITE = 634, // This spell will only work on Muramites.
IS_NOT_UNDEAD_OR_SUMMONED = 635, //
IS_NOT_PLANT = 636, // This spell will not affect plants.
IS_NOT_CLIENT = 700, // This spell will not work on adventurers.
IS_CLIENT = 701, // This spell will only work on adventurers.
IS_BODY_TYPE_LUGGALD = 620, // This spell will only work on Luggalds.
IS_BODY_TYPE_ANIMAL = 621, // This spell will only work on animals.
IS_BODY_TYPE_INSECT = 622, // This spell will only work on insects.
IS_BODY_TYPE_MONSTER = 623, // This spell will only work on monsters.
IS_BODY_TYPE_ELEMENTAL = 624, // This spell will only work on elemental creatures.
IS_BODY_TYPE_PLANT = 625, // This spell will only work on plants.
IS_BODY_TYPE_DRAGON2 = 626, // This spell will only work on dragons.
IS_BODY_TYPE_SUMMONED_ELEMENTAL = 627, // This spell will only work on summoned elementals.
IS_BODY_TYPE_WARDER = 628, //
IS_BODY_TYPE_DRAGON_OF_TOV = 630, // This spell will only work on Dragons of Veeshan's Temple.
IS_BODY_TYPE_FAMILIAR = 631, // This spell will only work on familiars.
IS_BODY_TYPE_MURAMITE = 634, // This spell will only work on Muramites.
IS_NOT_UNDEAD_OR_SUMMONED = 635, //
IS_NOT_PLANT = 636, // This spell will not affect plants.
IS_NOT_CLIENT = 700, // This spell will not work on adventurers.
IS_CLIENT = 701, // This spell will only work on adventurers.
IS_LEVEL_ABOVE_42_AND_IS_CLIENT = 800, // This spell will only work on level 43 or higher adventurers.
UNKNOWN_812 = 812, // | seen in spell 22616 Thaumatize Pet Mana Regen Base |
UNKNOWN_814 = 814, // | seen in spell 22704 Vegetentacles I |
IS_TREANT = 815, // This spell will only work on treants.
IS_BIXIE2 = 816, // This spell will only work on bixies.
IS_SCARECROW = 817, // This spell will only work on scarecrows.
IS_VAMPIRE_OR_UNDEAD_OR_UNDEADPET = 818, // This spell will only work on vampires, undead, or animated undead creatures.
IS_NOT_VAMPIRE_OR_UNDEAD = 819, // This spell will not work on vampires or undead creatures.
IS_CLASS_KNIGHT_HYBRID_MELEE = 820, // This spell will only work on knights, hybrids, or melee classes.
IS_CLASS_WARRIOR_CASTER_PRIEST = 821, // This spell will only work on warriors, casters, or priests.
IS_TREANT = 815, // This spell will only work on treants.
IS_BIXIE2 = 816, // This spell will only work on bixies.
IS_SCARECROW = 817, // This spell will only work on scarecrows.
IS_VAMPIRE_OR_UNDEAD_OR_UNDEADPET = 818, // This spell will only work on vampires, undead, or animated undead creatures.
IS_NOT_VAMPIRE_OR_UNDEAD = 819, // This spell will not work on vampires or undead creatures.
IS_CLASS_KNIGHT_HYBRID_MELEE = 820, // This spell will only work on knights, hybrids, or melee classes.
IS_CLASS_WARRIOR_CASTER_PRIEST = 821, // This spell will only work on warriors, casters, or priests.
UNKNOWN_822 = 822, // | seen in spell 22870 Morell's Distraction 822 |
IS_END_BELOW_21_PCT = 825, // This ability requires you to be at or below 21% of your maximum endurance.
IS_END_BELOW_25_PCT = 826, // This ability requires you to be at or below 25% of your maximum endurance.
IS_END_BELOW_29_PCT = 827, // This ability requires you to be at or below 29% of your maximum endurance.
IS_REGULAR_SERVER = 836, //
IS_PROGRESSION_SERVER = 837, //
IS_END_BELOW_21_PCT = 825, // This ability requires you to be at or below 21% of your maximum endurance.
IS_END_BELOW_25_PCT = 826, // This ability requires you to be at or below 25% of your maximum endurance.
IS_END_BELOW_29_PCT = 827, // This ability requires you to be at or below 29% of your maximum endurance.
IS_REGULAR_SERVER = 836, //
IS_PROGRESSION_SERVER = 837, //
IS_GOD_EXPANSION_UNLOCKED = 839, //
UNKNOWN_840 = 840, // | caster restriction | seen in spell 6883 Expedient Recovery
UNKNOWN_841 = 841, // | caster restriction | seen in spell 32192 Merciless Blow
IS_HUMANOID_LEVEL_84_MAX = 842, //
IS_HUMANOID_LEVEL_86_MAX = 843, //
IS_HUMANOID_LEVEL_88_MAX = 844, //
IS_HUMANOID_LEVEL_84_MAX = 842, //
IS_HUMANOID_LEVEL_86_MAX = 843, //
IS_HUMANOID_LEVEL_88_MAX = 844, //
HAS_CRYSTALLIZED_FLAME_BUFF = 845, // This spell will only work on targets afflicted by Crystallized Flame. | On live spell does not appear to be a buff
HAS_INCENDIARY_OOZE_BUFF = 847, // This spell will only work on targets afflicted by Incendiary Ooze.
IS_LEVEL_90_MAX = 860, //
IS_LEVEL_92_MAX = 861, //
IS_LEVEL_94_MAX = 862, //
IS_LEVEL_95_MAX = 863, //
IS_LEVEL_97_MAX = 864, //
IS_LEVEL_99_MAX = 865, //
HAS_INCENDIARY_OOZE_BUFF = 847, // This spell will only work on targets afflicted by Incendiary Ooze.
IS_LEVEL_90_MAX = 860, //
IS_LEVEL_92_MAX = 861, //
IS_LEVEL_94_MAX = 862, //
IS_LEVEL_95_MAX = 863, //
IS_LEVEL_97_MAX = 864, //
IS_LEVEL_99_MAX = 865, //
HAS_WEAPONSTANCE_DEFENSIVE_PROFICIENCY = 866, // | caster restriction |
HAS_WEAPONSTANCE_TWO_HAND_PROFICIENCY = 867, // | caster restriction |
HAS_WEAPONSTANCE_TWO_HAND_PROFICIENCY = 867, // | caster restriction |
HAS_WEAPONSTANCE_DUAL_WEILD_PROFICIENCY = 868, // | caster restriction |
IS_LEVEL_100_MAX = 869, //
IS_LEVEL_102_MAX = 870, //
IS_LEVEL_104_MAX = 871, //
IS_LEVEL_105_MAX = 872, //
IS_LEVEL_107_MAX = 873, //
IS_LEVEL_109_MAX = 874, //
IS_LEVEL_110_MAX = 875, //
IS_LEVEL_112_MAX = 876, //
IS_LEVEL_114_MAX = 877, //
IS_LEVEL_100_MAX = 869, //
IS_LEVEL_102_MAX = 870, //
IS_LEVEL_104_MAX = 871, //
IS_LEVEL_105_MAX = 872, //
IS_LEVEL_107_MAX = 873, //
IS_LEVEL_109_MAX = 874, //
IS_LEVEL_110_MAX = 875, //
IS_LEVEL_112_MAX = 876, //
IS_LEVEL_114_MAX = 877, //
HAS_TBL_ESIANTI_ACCESS = 997, // This spell will only transport adventurers who have gained access to Esianti: Palace of the Winds. | not implemented
HAS_ITEM_CLOCKWORK_SCRAPS = 999, //
IS_BETWEEN_LEVEL_1_AND_75 = 1000, //
IS_BETWEEN_LEVEL_76_AND_85 = 1001, //
IS_BETWEEN_LEVEL_86_AND_95 = 1002, //
IS_BETWEEN_LEVEL_96_AND_105 = 1003, //
IS_HP_LESS_THAN_80_PCT = 1004, //
IS_LEVEL_ABOVE_34 = 1474, // Your target must be level 35 or higher.
IN_TWO_HANDED_STANCE = 2000, // You must be in your two-handed stance to use this ability.
IN_DUAL_WIELD_HANDED_STANCE = 2001, // You must be in your dual-wielding stance to use this ability.
IN_SHIELD_STANCE = 2002, // You must be in your shield stance to use this ability.
NOT_IN_TWO_HANDED_STANCE = 2010, // You may not use this ability if you are in your two-handed stance.
NOT_IN_DUAL_WIELD_HANDED_STANCE = 2011, // You may not use this ability if you are in your dual-wielding stance.
NOT_IN_SHIELD_STANCE = 2012, // You may not use this ability if you are in your shield stance.
LEVEL_46_MAX = 2761, //
DISABLED_UNTIL_EXPANSION_ROK = 7000, // This ability is disabled until Ruins of Kunark.
DISABLED_UNTIL_EXPANSION_SOV = 7001, // This ability is disabled until Scars of Velious.
DISABLED_UNTIL_EXPANSION_SOL = 7002, // This ability is disabled until Shadows of Luclin.
DISABLED_UNTIL_EXPANSION_POP = 7003, // This ability is disabled until Planes of Power.
DISABLED_UNTIL_EXPANSION_LOY = 7004, // This ability is disabled until Legacy of Ykesha.
DISABLED_UNTIL_EXPANSION_LDON = 7005, // This ability is disabled until Lost Dungeons of Norrath.
DISABLED_UNTIL_EXPANSION_GOD = 7006, // This ability is disabled until Gates of Discord.
DISABLED_UNTIL_EXPANSION_OOW = 7007, // This ability is disabled until Omens of War.
DISABLED_UNTIL_EXPANSION_DON = 7008, // This ability is disabled until Dragons of Norrath.
DISABLED_UNTIL_EXPANSION_DOD = 7009, // This ability is disabled until Depths of Darkhollow.
DISABLED_UNTIL_EXPANSION_POR = 7010, // This ability is disabled until Prophecy of Ro.
DISABLED_UNTIL_EXPANSION_TSS = 7011, // This ability is disabled until Serpent's Spine.
DISABLED_UNTIL_EXPANSION_TBS = 7012, // This ability is disabled until Buried Sea.
DISABLED_UNTIL_EXPANSION_SOF = 7013, // This ability is disabled until Secrets of Faydwer.
DISABLED_UNTIL_EXPANSION_SOD = 7014, // This ability is disabled until Seeds of Destruction.
DISABLED_UNTIL_EXPANSION_UF = 7015, // This ability is disabled until Underfoot.
DISABLED_UNTIL_EXPANSION_HOT = 7016, // This ability is disabled until House of Thule.
DISABLED_UNTIL_EXPANSION_VOA = 7017, // This ability is disabled until Veil of Alaris.
DISABLED_UNTIL_EXPANSION_ROF = 7018, // This ability is disabled until Rain of Fear.
DISABLED_UNTIL_EXPANSION_COF = 7019, // This ability is disabled until Call of the Forsaken.
DISABLED_UNTIL_EXPANSION_TDS = 7020, // This ability is disabled until Darkened Sea.
DISABLED_UNTIL_EXPANSION_TBM = 7021, // This ability is disabled until Broken Mirror.
DISABLED_UNTIL_EXPANSION_EOK = 7022, // This ability is disabled until Empires of Kunark.
DISABLED_UNTIL_EXPANSION_ROS = 7023, // This ability is disabled until Ring of Scale.
DISABLED_UNTIL_EXPANSION_TBL = 7024, // This ability is disabled until The Burning Lands.
DISABLED_UNTIL_EXPANSION_TOV = 7025, // This ability is disabled until Torment of Velious.
DISABLED_UNTIL_EXPANSION_COV = 7026, // This ability is disabled until Claws of Veeshan.
HAS_NO_MANA_BURN_BUFF = 8450, // This spell will not take hold until the effects of the previous Mana Burn have expired.
HAS_ITEM_CLOCKWORK_SCRAPS = 999, //
IS_BETWEEN_LEVEL_1_AND_75 = 1000, //
IS_BETWEEN_LEVEL_76_AND_85 = 1001, //
IS_BETWEEN_LEVEL_86_AND_95 = 1002, //
IS_BETWEEN_LEVEL_96_AND_105 = 1003, //
IS_HP_LESS_THAN_80_PCT = 1004, //
IS_LEVEL_ABOVE_34 = 1474, // Your target must be level 35 or higher.
IN_TWO_HANDED_STANCE = 2000, // You must be in your two-handed stance to use this ability.
IN_DUAL_WIELD_HANDED_STANCE = 2001, // You must be in your dual-wielding stance to use this ability.
IN_SHIELD_STANCE = 2002, // You must be in your shield stance to use this ability.
NOT_IN_TWO_HANDED_STANCE = 2010, // You may not use this ability if you are in your two-handed stance.
NOT_IN_DUAL_WIELD_HANDED_STANCE = 2011, // You may not use this ability if you are in your dual-wielding stance.
NOT_IN_SHIELD_STANCE = 2012, // You may not use this ability if you are in your shield stance.
LEVEL_46_MAX = 2761, //
DISABLED_UNTIL_EXPANSION_ROK = 7000, // This ability is disabled until Ruins of Kunark.
DISABLED_UNTIL_EXPANSION_SOV = 7001, // This ability is disabled until Scars of Velious.
DISABLED_UNTIL_EXPANSION_SOL = 7002, // This ability is disabled until Shadows of Luclin.
DISABLED_UNTIL_EXPANSION_POP = 7003, // This ability is disabled until Planes of Power.
DISABLED_UNTIL_EXPANSION_LOY = 7004, // This ability is disabled until Legacy of Ykesha.
DISABLED_UNTIL_EXPANSION_LDON = 7005, // This ability is disabled until Lost Dungeons of Norrath.
DISABLED_UNTIL_EXPANSION_GOD = 7006, // This ability is disabled until Gates of Discord.
DISABLED_UNTIL_EXPANSION_OOW = 7007, // This ability is disabled until Omens of War.
DISABLED_UNTIL_EXPANSION_DON = 7008, // This ability is disabled until Dragons of Norrath.
DISABLED_UNTIL_EXPANSION_DOD = 7009, // This ability is disabled until Depths of Darkhollow.
DISABLED_UNTIL_EXPANSION_POR = 7010, // This ability is disabled until Prophecy of Ro.
DISABLED_UNTIL_EXPANSION_TSS = 7011, // This ability is disabled until Serpent's Spine.
DISABLED_UNTIL_EXPANSION_TBS = 7012, // This ability is disabled until Buried Sea.
DISABLED_UNTIL_EXPANSION_SOF = 7013, // This ability is disabled until Secrets of Faydwer.
DISABLED_UNTIL_EXPANSION_SOD = 7014, // This ability is disabled until Seeds of Destruction.
DISABLED_UNTIL_EXPANSION_UF = 7015, // This ability is disabled until Underfoot.
DISABLED_UNTIL_EXPANSION_HOT = 7016, // This ability is disabled until House of Thule.
DISABLED_UNTIL_EXPANSION_VOA = 7017, // This ability is disabled until Veil of Alaris.
DISABLED_UNTIL_EXPANSION_ROF = 7018, // This ability is disabled until Rain of Fear.
DISABLED_UNTIL_EXPANSION_COF = 7019, // This ability is disabled until Call of the Forsaken.
DISABLED_UNTIL_EXPANSION_TDS = 7020, // This ability is disabled until Darkened Sea.
DISABLED_UNTIL_EXPANSION_TBM = 7021, // This ability is disabled until Broken Mirror.
DISABLED_UNTIL_EXPANSION_EOK = 7022, // This ability is disabled until Empires of Kunark.
DISABLED_UNTIL_EXPANSION_ROS = 7023, // This ability is disabled until Ring of Scale.
DISABLED_UNTIL_EXPANSION_TBL = 7024, // This ability is disabled until The Burning Lands.
DISABLED_UNTIL_EXPANSION_TOV = 7025, // This ability is disabled until Torment of Velious.
DISABLED_UNTIL_EXPANSION_COV = 7026, // This ability is disabled until Claws of Veeshan.
HAS_NO_MANA_BURN_BUFF = 8450, // This spell will not take hold until the effects of the previous Mana Burn have expired.
IS_RACE_FIRST_CUSTOM = 10000, // | custom range to restrict targets or casters by race *not on live* |
IS_RACE_LAST_CUSTOM = 11000, // | custom range to restrict targets or casters by race *not on live* |
IS_CLIENT_AND_MALE_PLATE_USER = 11044, // Your target wouldn't look right as that Jann.
IS_CLEINT_AND_MALE_DRUID_ENCHANTER_MAGICIAN_NECROANCER_SHAMAN_OR_WIZARD = 11090, // Your target wouldn't look right as that Jann.
IS_CLIENT_AND_MALE_BEASTLORD_BERSERKER_MONK_RANGER_OR_ROGUE = 11209, // Your target wouldn't look right as that Jann.
IS_CLIENT_AND_FEMALE_PLATE_USER = 11210, // Your target wouldn't look right as that Jann.
IS_CLIENT_AND_FEMALE_DRUID_ENCHANTER_MAGICIAN_NECROANCER_SHAMAN_OR_WIZARD = 11211, // Your target wouldn't look right as that Jann.
IS_CLIENT_AND_FEMALE_BEASTLORD_BERSERKER_MONK_RANGER_OR_ROGUE = 11248, // Your target wouldn't look right as that Jann.
HAS_TRAVELED_TO_STRATOS = 11260, // You must travel to Stratos at least once before wishing to go there.
HAS_TRAVELED_TO_AALISHAI = 11261, // You must travel to Aalishai at least once before wishing to go there.
HAS_TRAVELED_TO_MEARATS = 11268, // You must travel to Mearatas at least once before wishing to go there.
HAS_NO_ILLUSIONS_OF_GRANDEUR_BUFF = 12519, //
IS_HP_ABOVE_50_PCT = 16010, //
IS_HP_UNDER_50_PCT = 16031, //
IS_OFF_HAND_EQUIPED = 27672, // You must be wielding a weapon or shield in your offhand to use this ability.
IS_CLIENT_AND_MALE_PLATE_USER = 11044, // Your target wouldn't look right as that Jann.
IS_CLEINT_AND_MALE_DRUID_ENCHANTER_MAGICIAN_NECROANCER_SHAMAN_OR_WIZARD = 11090, // Your target wouldn't look right as that Jann.
IS_CLIENT_AND_MALE_BEASTLORD_BERSERKER_MONK_RANGER_OR_ROGUE = 11209, // Your target wouldn't look right as that Jann.
IS_CLIENT_AND_FEMALE_PLATE_USER = 11210, // Your target wouldn't look right as that Jann.
IS_CLIENT_AND_FEMALE_DRUID_ENCHANTER_MAGICIAN_NECROANCER_SHAMAN_OR_WIZARD = 11211, // Your target wouldn't look right as that Jann.
IS_CLIENT_AND_FEMALE_BEASTLORD_BERSERKER_MONK_RANGER_OR_ROGUE = 11248, // Your target wouldn't look right as that Jann.
HAS_TRAVELED_TO_STRATOS = 11260, // You must travel to Stratos at least once before wishing to go there.
HAS_TRAVELED_TO_AALISHAI = 11261, // You must travel to Aalishai at least once before wishing to go there.
HAS_TRAVELED_TO_MEARATS = 11268, // You must travel to Mearatas at least once before wishing to go there.
HAS_NO_ILLUSIONS_OF_GRANDEUR_BUFF = 12519, //
IS_HP_ABOVE_50_PCT = 16010, //
IS_HP_UNDER_50_PCT = 16031, //
IS_OFF_HAND_EQUIPED = 27672, // You must be wielding a weapon or shield in your offhand to use this ability.
HAS_NO_PACT_OF_FATE_RECOURSE_BUFF = 29556, // This spell will not work while Pact of Fate Recourse is active. | caster restriction |
HAS_NO_SHROUD_OF_PRAYER_BUFF = 32339, // Your target cannot receive another Quiet Prayer this soon.
IS_MANA_BELOW_20_PCT = 38311, // This ability requires you to be at or below 20% of your maximum mana.
IS_MANA_ABOVE_50_PCT = 38312, // This ability requires you to be at or above 50% of your maximum mana.
COMPLETED_ACHIEVEMENT_LEGENDARY_ANSWERER = 39281, // You have completed Legendary Answerer.
HAS_NO_SHROUD_OF_PRAYER_BUFF = 32339, // Your target cannot receive another Quiet Prayer this soon.
IS_MANA_BELOW_20_PCT = 38311, // This ability requires you to be at or below 20% of your maximum mana.
IS_MANA_ABOVE_50_PCT = 38312, // This ability requires you to be at or above 50% of your maximum mana.
COMPLETED_ACHIEVEMENT_LEGENDARY_ANSWERER = 39281, // You have completed Legendary Answerer.
HAS_NO_ROGUES_FURY_BUFF = 40297, // This spell will not affect anyone that currently has Rogue's Fury active. | caster restriction |
NOT_COMPLETED_ACHIEVEMENT_LEGENDARY_ANSWERER = 42280, // You must complete Legendary Answerer.
IS_SUMMONED_OR_UNDEAD = 49326, //
IS_CLASS_CASTER_PRIEST = 49529, //
NOT_COMPLETED_ACHIEVEMENT_LEGENDARY_ANSWERER = 42280, // You must complete Legendary Answerer.
IS_SUMMONED_OR_UNDEAD = 49326, //
IS_CLASS_CASTER_PRIEST = 49529, //
IS_END_OR_MANA_ABOVE_20_PCT = 49543, // You must have at least 20% of your maximum mana and endurance to use this ability. //pure melee class check end, other check mana
IS_END_OR_MANA_BELOW_30_PCT = 49573, // Your target already has 30% or more of their maximum mana or endurance. //pure melee class check the, other check more
IS_CLASS_BARD2 = 49574, //
IS_NOT_CLASS_BARD = 49575, //
HAS_NO_FURIOUS_RAMPAGE_BUFF = 49612, // This ability cannot be activated while Furious Rampage is active.
IS_END_OR_MANA_BELOW_30_PCT2 = 49809, // You can only perform this solo if you have less than 30% mana or endurance.
HAS_NO_HARMONIOUS_PRECISION_BUFF = 50003, // This spell will not work if you have the Harmonious Precision line active.
IS_CLASS_BARD2 = 49574, //
IS_NOT_CLASS_BARD = 49575, //
HAS_NO_FURIOUS_RAMPAGE_BUFF = 49612, // This ability cannot be activated while Furious Rampage is active.
IS_END_OR_MANA_BELOW_30_PCT2 = 49809, // You can only perform this solo if you have less than 30% mana or endurance.
HAS_NO_HARMONIOUS_PRECISION_BUFF = 50003, // This spell will not work if you have the Harmonious Precision line active.
HAS_NO_HARMONIOUS_EXPANSE_BUFF = 50009, // This spell will not work if you have the Harmonious Expanse line active.
UNKNOWN_99999 = 99999, // | caster restriction | works will spell 27672 Strike of Ire
};
@ -912,7 +912,7 @@ typedef enum {
#define SE_FleshToBone 207 // implemented
//#define SE_PurgePoison 208 // not used
#define SE_DispelBeneficial 209 // implemented, @Dispel, removes only beneficial effects on a target, base: pct chance (950=95%), limit: none, max: none
#define SE_PetShield 210 // implmented, @ShieldAbility, allows pet to 'shield' owner for 50 pct of damage taken for a duration, base: Time multiplier 1=12 seconds, 2=24 ect, limit: mitigation on pet owner override (not on live), max: mitigation on pet overide (not on live)
#define SE_PetShield 210 // implmented, @ShieldAbility, allows pet to 'shield' owner for 50 pct of damage taken for a duration, base: Time multiplier 1=12 seconds, 2=24 ect, limit: mitigation on pet owner override (not on live), max: mitigation on pet overide (not on live)
#define SE_AEMelee 211 // implemented TO DO: Implement to allow NPC use (client only atm).
#define SE_FrenziedDevastation 212 // implemented - increase spell criticals + all DD spells cast 2x mana.
#define SE_PetMaxHP 213 // implemented[AA] - increases the maximum hit points of your pet
@ -993,7 +993,7 @@ typedef enum {
#define SE_SkillAttackProc 288 // implemented[AA] - Chance to proc spell on skill attack usage (ex. Dragon Punch)
#define SE_CastOnFadeEffect 289 // implemented - Triggers only if fades after natural duration.
#define SE_IncreaseRunSpeedCap 290 // implemented[AA] - increases run speed over the hard cap
#define SE_Purify 291 // implemented, @Dispel, remove up specified amount of detiremental spells, base: amt removed, limit: none, max: none, Note: excluding charm, fear, resurrection, and revival sickness
#define SE_Purify 291 // implemented, @Dispel, remove up specified amount of detiremental spells, base: amt removed, limit: none, max: none, Note: excluding charm, fear, resurrection, and revival sickness
#define SE_StrikeThrough2 292 // implemented[AA] - increasing chance of bypassing an opponent's special defenses, such as dodge, block, parry, and riposte.
#define SE_FrontalStunResist 293 // implemented[AA] - Reduce chance to be stunned from front. -- live descriptions sounds like this isn't limited to frontal anymore
#define SE_CriticalSpellChance 294 // implemented - increase chance to critical hit and critical damage modifier.
@ -1041,7 +1041,7 @@ typedef enum {
//#define SE_IllusionaryTarget 336 // not used
#define SE_PercentXPIncrease 337 // implemented
#define SE_SummonAndResAllCorpses 338 // implemented
#define SE_TriggerOnCast 339 // implemented, @Fc, On Caster, cast on spell use, base: chance pct limit: spellid
#define SE_TriggerOnCast 339 // implemented, @Fc, On Caster, cast on spell use, base: chance pct limit: spellid
#define SE_SpellTrigger 340 // implemented - chance to trigger spell [Share rolls with 469] All base2 spells share roll chance, only 1 cast.
#define SE_ItemAttackCapIncrease 341 // implemented[AA] - increases the maximum amount of attack you can gain from items.
#define SE_ImmuneFleeing 342 // implemented - stop mob from fleeing
@ -1186,14 +1186,14 @@ typedef enum {
#define SE_Fc_Cast_Spell_On_Land 481 // implemented, @Fc, On Target, cast spell if hit by spell, base: chance pct, limit: spellid
#define SE_Skill_Base_Damage_Mod 482 // implemented, @OffBonus, modify base melee damage by percent, base: pct, limit: skill(-1=ALL), max: none
#define SE_Fc_Spell_Damage_Pct_IncomingPC 483 // implemented, @Fc, On Target, spell damage taken mod pct, base: min pct, limit: max pct
#define SE_Fc_Spell_Damage_Amt_IncomingPC 484 // implemented, @Fc, On Target, damage taken flat amt, base: amt
#define SE_Fc_Spell_Damage_Amt_IncomingPC 484 // implemented, @Fc, On Target, damage taken flat amt, base: amt
#define SE_Ff_CasterClass 485 // implemented, @Ff, Caster of spell on target with a focus effect that is checked by incoming spells must be specified class(es). base1: class(es), Note: Set multiple classes same as would for items
#define SE_Ff_Same_Caster 486 // implemented, @Ff, Caster of spell on target with a focus effect that is checked by incoming spells, base1: 0=Must be different caster 1=Must be same caster
//#define SE_Extend_Tradeskill_Cap 487 //
//#define SE_Defender_Melee_Force_Pct_PC 488 //
#define SE_Worn_Endurance_Regen_Cap 489 // implemented, modify worn regen cap, base: amt, limit: none, max: none
#define SE_Ff_ReuseTimeMin 490 // implemented, @Ff, Minimum recast time of a spell that can be focused, base: recast time
#define SE_Ff_ReuseTimeMax 491 // implemented, @Ff, Max recast time of a spell that can be focused, base: recast time
#define SE_Ff_ReuseTimeMax 491 // implemented, @Ff, Max recast time of a spell that can be focused, base: recast time
#define SE_Ff_Endurance_Min 492 // implemented, @Ff, Minimum endurance cost of a spell that can be focused, base: endurance cost
#define SE_Ff_Endurance_Max 493 // implemented, @Ff, Max endurance cost of a spell that can be focused, base: endurance cost
#define SE_Pet_Add_Atk 494 // implemented - Bonus on pet owner which gives their pet increased attack stat
@ -1213,7 +1213,7 @@ typedef enum {
#define SE_Fc_Amplify_Amt 508 // implemented, @Fc, On Caster, damage-heal-dot mod flat amt, base: amt
#define SE_Health_Transfer 509 // implemented - exchange health for damage or healing on a target. ie Lifeburn/Act of Valor
#define SE_Fc_ResistIncoming 510 // implemented, @Fc, On Target, resist modifier, base: amt
#define SE_Ff_FocusTimerMin 511 // implemented, @Ff, sets a recast time until focus can be used again, base: 1, limit: time ms, Note: ie. limit to 1 trigger every 1.5 seconds
#define SE_Ff_FocusTimerMin 511 // implemented, @Ff, sets a recast time until focus can be used again, base: 1, limit: time ms, Note: ie. limit to 1 trigger every 1.5 seconds
#define SE_Proc_Timer_Modifier 512 // implemented - limits procs per amount of a time based on timer value, base: 1, limit: time ms, Note:, ie limit to 1 proc every 55 seconds)
//#define SE_Mana_Max_Percent 513 //
//#define SE_Endurance_Max_Percent 514 //
@ -1531,5 +1531,6 @@ bool IsShortDurationBuff(uint16 spell_id);
bool IsSpellUsableThisZoneType(uint16 spell_id, uint8 zone_type);
const char *GetSpellName(uint16 spell_id);
int GetSpellStatValue(uint32 spell_id, const char* stat_identifier, uint8 slot = 0);
bool CastRestrictedSpell(int spellid);
#endif

183
utils/gm_commands/main.go Normal file
View File

@ -0,0 +1,183 @@
package main
import (
"fmt"
"io/ioutil"
"log"
"os"
"sort"
"strings"
)
func main() {
// zone/command.cpp
commands, err := os.ReadFile("./zone/command.cpp")
if err != nil {
log.Fatal(err)
}
commandsString := string(commands)
s := strings.Split(commandsString, "void command_")
commandFiles := []string{}
if len(s) > 1 {
startListing := false
for i, chunk := range s {
if strings.Contains(chunk, "logcommand(Client *c") {
startListing = true
}
// get function name
functionName := ""
nameSplit := strings.Split(chunk, "(Client")
if len(nameSplit) > 0 {
functionName = strings.TrimSpace(nameSplit[0])
}
if startListing &&
len(s[i-1]) > 0 &&
!strings.Contains(s[i-1], "#ifdef") &&
!strings.Contains(chunk, "#ifdef") &&
!strings.Contains(chunk, "#ifdef BOTS") &&
!strings.Contains(chunk, "#ifdef EQPROFILE") &&
!strings.Contains(functionName, "bot") &&
!strings.Contains(functionName, "help") &&
!strings.Contains(functionName, "findaliases") {
fmt.Println(functionName)
// build command file name
commandFile := fmt.Sprintf("zone/gm_commands/%v.cpp", functionName)
// append command file nam eto list
commandFiles = append(commandFiles, commandFile)
includes := ""
if strings.Contains(chunk, "Client") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../client.h\"")
}
if strings.Contains(chunk, "parse->") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../quest_parser_collection.h\"")
}
if strings.Contains(chunk, "worldserver.") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../worldserver.h\"")
includes = fmt.Sprintf("%v%v\n", includes, "extern WorldServer worldserver;")
}
if strings.Contains(chunk, "RegionType") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../water_map.h\"")
}
if strings.Contains(chunk, "Corpse") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../corpse.h\"")
}
if strings.Contains(chunk, "Object") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../object.h\"")
}
if strings.Contains(chunk, "DoorManipulation") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"door_manipulation.h\"")
}
if strings.Contains(chunk, "Group") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../groups.h\"")
}
if strings.Contains(chunk, "httplib") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../../common/http/httplib.h\"")
}
if strings.Contains(chunk, "guild_mgr") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../guild_mgr.h\"")
}
if strings.Contains(chunk, "expedition") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../expedition.h\"")
}
if strings.Contains(chunk, "DataBucket::") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../data_bucket.h\"")
}
if strings.Contains(chunk, "file_exists") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../../common/file_util.h\"")
}
if strings.Contains(chunk, "std::thread") {
includes = fmt.Sprintf("%v%v\n", includes, "#include <thread>")
}
if strings.Contains(chunk, "Door") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../doors.h\"")
}
if strings.Contains(chunk, "NOW_INVISIBLE") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../string_ids.h\"")
}
if strings.Contains(chunk, "Expansion::") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../../common/content/world_content_service.h\"")
}
if strings.Contains(chunk, "MobMovementManager::") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../mob_movement_manager.h\"")
}
if strings.Contains(chunk, "MobStuckBehavior::") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../mob_movement_manager.h\"")
}
if strings.Contains(chunk, "ReloadAllPatches") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../../common/patches/patches.h\"")
}
if strings.Contains(chunk, "ProfanityManager") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../../common/profanity_manager.h\"")
}
if strings.Contains(chunk, "npc_scale_manager") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../npc_scale_manager.h\"")
}
if strings.Contains(chunk, "g_Math") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../fastmath.h\"")
includes = fmt.Sprintf("%v%v\n", includes, "extern FastMath g_Math;")
}
if strings.Contains(chunk, "raid") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../raids.h\"")
}
if strings.Contains(chunk, "Raid") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../raids.h\"")
}
if strings.Contains(chunk, "GetOS") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../../common/serverinfo.h\"")
}
if strings.Contains(chunk, "LANG_") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../../common/languages.h\"")
}
if strings.Contains(chunk, "ServerOP_Shared") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../../common/shared_tasks.h\"")
}
if strings.Contains(chunk, "title_manager") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../titles.h\"")
}
if strings.Contains(chunk, "CatchSignal") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../../world/main.h\"")
}
// build the contents of the command file
commandString := fmt.Sprintf("%v\nvoid command_%v", includes, chunk)
//write file contents
err := ioutil.WriteFile(commandFile, []byte(commandString), 0777)
if err != nil {
fmt.Println(err)
}
commandOnly := fmt.Sprintf("void command_%v", chunk)
commandsString = strings.ReplaceAll(commandsString, commandOnly, "")
}
}
// rewrite commands.cpp with functions removed
err := ioutil.WriteFile("zone/command.cpp", []byte(commandsString), 0777)
if err != nil {
fmt.Println(err)
}
fmt.Println("# CmakeLists")
// sort a-z
sort.Slice(commandFiles, func(i, j int) bool {
return commandFiles[i] < commandFiles[j]
})
for _, file := range commandFiles {
file = strings.ReplaceAll(file, "zone/", "")
fmt.Println(file)
}
}
//fmt.Print(string(commands))
}

View File

@ -1,293 +1,576 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.2)
SET(zone_sources
aa.cpp
aa_ability.cpp
aggro.cpp
aggromanager.cpp
api_service.cpp
attack.cpp
aura.cpp
beacon.cpp
bonuses.cpp
bot.cpp
bot_command.cpp
bot_database.cpp
botspellsai.cpp
cheat_manager.cpp
client.cpp
client_mods.cpp
client_packet.cpp
client_process.cpp
command.cpp
corpse.cpp
data_bucket.cpp
doors.cpp
dialogue_window.cpp
dynamic_zone.cpp
effects.cpp
embparser.cpp
embparser_api.cpp
embperl.cpp
embxs.cpp
encounter.cpp
entity.cpp
exp.cpp
expedition.cpp
expedition_database.cpp
expedition_request.cpp
fastmath.cpp
fearpath.cpp
forage.cpp
groups.cpp
guild.cpp
guild_mgr.cpp
hate_list.cpp
heal_rotation.cpp
horse.cpp
inventory.cpp
loottables.cpp
lua_bot.cpp
lua_bit.cpp
lua_corpse.cpp
lua_client.cpp
lua_door.cpp
lua_encounter.cpp
lua_entity.cpp
lua_entity_list.cpp
lua_expedition.cpp
lua_general.cpp
lua_group.cpp
lua_hate_list.cpp
lua_inventory.cpp
lua_item.cpp
lua_iteminst.cpp
lua_mob.cpp
lua_mod.cpp
lua_npc.cpp
lua_object.cpp
lua_packet.cpp
lua_parser.cpp
lua_parser_events.cpp
lua_raid.cpp
lua_spawn.cpp
lua_spell.cpp
lua_stat_bonuses.cpp
embperl.cpp
embxs.cpp
entity.cpp
exp.cpp
fearpath.cpp
forage.cpp
global_loot_manager.cpp
gm_commands/door_manipulation.cpp
groups.cpp
guild.cpp
guild_mgr.cpp
hate_list.cpp
horse.cpp
inventory.cpp
loottables.cpp
main.cpp
map.cpp
merc.cpp
mob.cpp
mob_ai.cpp
mob_appearance.cpp
mob_movement_manager.cpp
mob_info.cpp
mod_functions.cpp
npc.cpp
npc_ai.cpp
npc_scale_manager.cpp
object.cpp
oriented_bounding_box.cpp
pathfinder_interface.cpp
pathfinder_nav_mesh.cpp
pathfinder_null.cpp
pathing.cpp
perl_bot.cpp
perl_client.cpp
perl_doors.cpp
perl_entity.cpp
perl_expedition.cpp
perl_groups.cpp
perl_hateentry.cpp
perl_inventory.cpp
perl_mob.cpp
perl_npc.cpp
perl_object.cpp
perl_perlpacket.cpp
perl_player_corpse.cpp
perl_questitem.cpp
perl_raids.cpp
perl_spell.cpp
perlpacket.cpp
petitions.cpp
pets.cpp
position.cpp
qglobals.cpp
queryserv.cpp
questmgr.cpp
quest_parser_collection.cpp
raids.cpp
raycast_mesh.cpp
shared_task_zone_messaging.cpp
spawn2.cpp
spawn2.h
spawngroup.cpp
special_attacks.cpp
spell_effects.cpp
spells.cpp
task_client_state.cpp
task_goal_list_manager.cpp
task_manager.cpp
task_proximity_manager.cpp
tasks.cpp
titles.cpp
tradeskills.cpp
trading.cpp
trap.cpp
tribute.cpp
tune.cpp
water_map.cpp
water_map_v1.cpp
water_map_v2.cpp
waypoints.cpp
worldserver.cpp
xtargetautohaters.cpp
zone.cpp
zone_config.cpp
zonedb.cpp
zone_event_scheduler.cpp
zone_reload.cpp
zone_store.cpp
zoning.cpp
)
aa.cpp
aa_ability.cpp
aggro.cpp
aggromanager.cpp
api_service.cpp
attack.cpp
aura.cpp
beacon.cpp
bonuses.cpp
bot.cpp
bot_command.cpp
bot_database.cpp
botspellsai.cpp
cheat_manager.cpp
client.cpp
client_mods.cpp
client_packet.cpp
client_process.cpp
command.cpp
corpse.cpp
data_bucket.cpp
doors.cpp
dialogue_window.cpp
dynamic_zone.cpp
effects.cpp
embparser.cpp
embparser_api.cpp
embperl.cpp
embxs.cpp
encounter.cpp
entity.cpp
exp.cpp
expedition.cpp
expedition_database.cpp
expedition_request.cpp
fastmath.cpp
fearpath.cpp
forage.cpp
groups.cpp
guild.cpp
guild_mgr.cpp
hate_list.cpp
heal_rotation.cpp
horse.cpp
inventory.cpp
loottables.cpp
lua_bot.cpp
lua_bit.cpp
lua_corpse.cpp
lua_client.cpp
lua_door.cpp
lua_encounter.cpp
lua_entity.cpp
lua_entity_list.cpp
lua_expedition.cpp
lua_general.cpp
lua_group.cpp
lua_hate_list.cpp
lua_inventory.cpp
lua_item.cpp
lua_iteminst.cpp
lua_mob.cpp
lua_mod.cpp
lua_npc.cpp
lua_object.cpp
lua_packet.cpp
lua_parser.cpp
lua_parser_events.cpp
lua_raid.cpp
lua_spawn.cpp
lua_spell.cpp
lua_stat_bonuses.cpp
embperl.cpp
embxs.cpp
entity.cpp
exp.cpp
fearpath.cpp
forage.cpp
global_loot_manager.cpp
gm_commands/door_manipulation.cpp
groups.cpp
guild.cpp
guild_mgr.cpp
hate_list.cpp
horse.cpp
inventory.cpp
loottables.cpp
main.cpp
map.cpp
merc.cpp
mob.cpp
mob_ai.cpp
mob_appearance.cpp
mob_movement_manager.cpp
mob_info.cpp
mod_functions.cpp
npc.cpp
npc_ai.cpp
npc_scale_manager.cpp
object.cpp
oriented_bounding_box.cpp
pathfinder_interface.cpp
pathfinder_nav_mesh.cpp
pathfinder_null.cpp
pathing.cpp
perl_bot.cpp
perl_client.cpp
perl_doors.cpp
perl_entity.cpp
perl_expedition.cpp
perl_groups.cpp
perl_hateentry.cpp
perl_inventory.cpp
perl_mob.cpp
perl_npc.cpp
perl_object.cpp
perl_perlpacket.cpp
perl_player_corpse.cpp
perl_questitem.cpp
perl_raids.cpp
perl_spell.cpp
perlpacket.cpp
petitions.cpp
pets.cpp
position.cpp
qglobals.cpp
queryserv.cpp
questmgr.cpp
quest_parser_collection.cpp
raids.cpp
raycast_mesh.cpp
shared_task_zone_messaging.cpp
spawn2.cpp
spawn2.h
spawngroup.cpp
special_attacks.cpp
spell_effects.cpp
spells.cpp
task_client_state.cpp
task_goal_list_manager.cpp
task_manager.cpp
task_proximity_manager.cpp
tasks.cpp
titles.cpp
tradeskills.cpp
trading.cpp
trap.cpp
tribute.cpp
tune.cpp
water_map.cpp
water_map_v1.cpp
water_map_v2.cpp
waypoints.cpp
worldserver.cpp
xtargetautohaters.cpp
zone.cpp
zone_config.cpp
zonedb.cpp
zone_event_scheduler.cpp
zone_reload.cpp
zone_store.cpp
zoning.cpp
)
SET(zone_headers
aa.h
aa_ability.h
aggromanager.h
api_service.h
aura.h
basic_functions.h
beacon.h
bot.h
bot_command.h
bot_database.h
bot_structs.h
cheat_manager.h
client.h
client_packet.h
command.h
common.h
corpse.h
data_bucket.h
doors.h
dialogue_window.h
dynamic_zone.h
embparser.h
embperl.h
embxs.h
encounter.h
entity.h
errmsg.h
event_codes.h
expedition.h
expedition_database.h
expedition_request.h
fastmath.h
forage.h
global_loot_manager.h
gm_commands/door_manipulation.h
groups.h
guild_mgr.h
hate_list.h
heal_rotation.h
horse.h
lua_bot.h
lua_bit.h
lua_client.h
lua_corpse.h
lua_door.h
lua_encounter.h
lua_entity.h
lua_entity_list.h
lua_expedition.h
lua_general.h
lua_group.h
lua_hate_list.h
lua_inventory.h
lua_item.h
lua_iteminst.h
lua_mob.h
lua_mod.h
lua_npc.h
lua_object.h
lua_packet.h
lua_parser.h
lua_parser_events.h
lua_ptr.h
lua_raid.h
lua_spawn.h
lua_spell.h
lua_stat_bonuses.h
map.h
masterentity.h
maxskill.h
message.h
merc.h
mob.h
mob_movement_manager.h
npc.h
npc_ai.h
npc_scale_manager.h
object.h
oriented_bounding_box.h
pathfinder_interface.h
pathfinder_nav_mesh.h
pathfinder_null.h
perlpacket.h
petitions.h
pets.h
position.h
qglobals.h
quest_interface.h
queryserv.h
quest_interface.h
questmgr.h
quest_parser_collection.h
raids.h
raycast_mesh.h
skills.h
shared_task_zone_messaging.h
spawn2.cpp
spawn2.h
spawngroup.h
string_ids.h
task_client_state.h
task_goal_list_manager.h
task_manager.h
task_proximity_manager.h
tasks.h
titles.h
trap.h
water_map.h
water_map_v1.h
water_map_v2.h
worldserver.h
xtargetautohaters.h
zone.h
zone_event_scheduler.h
zone_config.h
zonedb.h
zonedump.h
zone_reload.h
zone_store.h
aa.h
aa_ability.h
aggromanager.h
api_service.h
aura.h
basic_functions.h
beacon.h
bot.h
bot_command.h
bot_database.h
bot_structs.h
cheat_manager.h
client.h
client_packet.h
command.h
common.h
corpse.h
data_bucket.h
doors.h
dialogue_window.h
dynamic_zone.h
embparser.h
embperl.h
embxs.h
encounter.h
entity.h
errmsg.h
event_codes.h
expedition.h
expedition_database.h
expedition_request.h
fastmath.h
forage.h
global_loot_manager.h
gm_commands/door_manipulation.h
groups.h
guild_mgr.h
hate_list.h
heal_rotation.h
horse.h
lua_bot.h
lua_bit.h
lua_client.h
lua_corpse.h
lua_door.h
lua_encounter.h
lua_entity.h
lua_entity_list.h
lua_expedition.h
lua_general.h
lua_group.h
lua_hate_list.h
lua_inventory.h
lua_item.h
lua_iteminst.h
lua_mob.h
lua_mod.h
lua_npc.h
lua_object.h
lua_packet.h
lua_parser.h
lua_parser_events.h
lua_ptr.h
lua_raid.h
lua_spawn.h
lua_spell.h
lua_stat_bonuses.h
map.h
masterentity.h
maxskill.h
message.h
merc.h
mob.h
mob_movement_manager.h
npc.h
npc_ai.h
npc_scale_manager.h
object.h
oriented_bounding_box.h
pathfinder_interface.h
pathfinder_nav_mesh.h
pathfinder_null.h
perlpacket.h
petitions.h
pets.h
position.h
qglobals.h
quest_interface.h
queryserv.h
quest_interface.h
questmgr.h
quest_parser_collection.h
raids.h
raycast_mesh.h
skills.h
shared_task_zone_messaging.h
spawn2.cpp
spawn2.h
spawngroup.h
string_ids.h
task_client_state.h
task_goal_list_manager.h
task_manager.h
task_proximity_manager.h
tasks.h
titles.h
trap.h
water_map.h
water_map_v1.h
water_map_v2.h
worldserver.h
xtargetautohaters.h
zone.h
zone_event_scheduler.h
zone_config.h
zonedb.h
zonedump.h
zone_reload.h
zone_store.h
)
SET(gm_commands
gm_commands/acceptrules.cpp
gm_commands/advnpcspawn.cpp
gm_commands/aggro.cpp
gm_commands/aggrozone.cpp
gm_commands/ai.cpp
gm_commands/appearance.cpp
gm_commands/attack.cpp
gm_commands/augmentitem.cpp
gm_commands/ban.cpp
gm_commands/beard.cpp
gm_commands/beardcolor.cpp
gm_commands/bestz.cpp
gm_commands/bind.cpp
gm_commands/camerashake.cpp
gm_commands/castspell.cpp
gm_commands/chat.cpp
gm_commands/checklos.cpp
gm_commands/copycharacter.cpp
gm_commands/corpse.cpp
gm_commands/corpsefix.cpp
gm_commands/cvs.cpp
gm_commands/damage.cpp
gm_commands/databuckets.cpp
gm_commands/date.cpp
gm_commands/dbspawn2.cpp
gm_commands/delacct.cpp
gm_commands/deletegraveyard.cpp
gm_commands/delpetition.cpp
gm_commands/depop.cpp
gm_commands/depopzone.cpp
gm_commands/details.cpp
gm_commands/devtools.cpp
gm_commands/disablerecipe.cpp
gm_commands/disarmtrap.cpp
gm_commands/distance.cpp
gm_commands/doanim.cpp
gm_commands/door.cpp
gm_commands/dye.cpp
gm_commands/dz.cpp
gm_commands/dzkickplayers.cpp
gm_commands/editmassrespawn.cpp
gm_commands/emote.cpp
gm_commands/emotesearch.cpp
gm_commands/emoteview.cpp
gm_commands/enablerecipe.cpp
gm_commands/endurance.cpp
gm_commands/equipitem.cpp
gm_commands/face.cpp
gm_commands/faction.cpp
gm_commands/findclass.cpp
gm_commands/findfaction.cpp
gm_commands/findnpctype.cpp
gm_commands/findrace.cpp
gm_commands/findskill.cpp
gm_commands/findspell.cpp
gm_commands/findtask.cpp
gm_commands/findzone.cpp
gm_commands/fixmob.cpp
gm_commands/flag.cpp
gm_commands/flagedit.cpp
gm_commands/flags.cpp
gm_commands/flymode.cpp
gm_commands/fov.cpp
gm_commands/freeze.cpp
gm_commands/gassign.cpp
gm_commands/gearup.cpp
gm_commands/gender.cpp
gm_commands/getplayerburiedcorpsecount.cpp
gm_commands/getvariable.cpp
gm_commands/ginfo.cpp
gm_commands/giveitem.cpp
gm_commands/givemoney.cpp
gm_commands/globalview.cpp
gm_commands/gm.cpp
gm_commands/gmspeed.cpp
gm_commands/gmzone.cpp
gm_commands/goto.cpp
gm_commands/grid.cpp
gm_commands/guild.cpp
gm_commands/guildapprove.cpp
gm_commands/guildcreate.cpp
gm_commands/guildlist.cpp
gm_commands/hair.cpp
gm_commands/haircolor.cpp
gm_commands/haste.cpp
gm_commands/hatelist.cpp
gm_commands/heal.cpp
gm_commands/helm.cpp
gm_commands/heritage.cpp
gm_commands/heromodel.cpp
gm_commands/hideme.cpp
gm_commands/hp.cpp
gm_commands/incstat.cpp
gm_commands/instance.cpp
gm_commands/interrogateinv.cpp
gm_commands/interrupt.cpp
gm_commands/invsnapshot.cpp
gm_commands/invul.cpp
gm_commands/ipban.cpp
gm_commands/iplookup.cpp
gm_commands/iteminfo.cpp
gm_commands/itemsearch.cpp
gm_commands/kick.cpp
gm_commands/kill.cpp
gm_commands/killallnpcs.cpp
gm_commands/lastname.cpp
gm_commands/list.cpp
gm_commands/listpetition.cpp
gm_commands/loc.cpp
gm_commands/lock.cpp
gm_commands/logcommand.cpp
gm_commands/logs.cpp
gm_commands/makepet.cpp
gm_commands/mana.cpp
gm_commands/max_all_skills.cpp
gm_commands/memspell.cpp
gm_commands/merchantcloseshop.cpp
gm_commands/merchantopenshop.cpp
gm_commands/modifynpcstat.cpp
gm_commands/motd.cpp
gm_commands/movechar.cpp
gm_commands/movement.cpp
gm_commands/myskills.cpp
gm_commands/mysql.cpp
gm_commands/mystats.cpp
gm_commands/name.cpp
gm_commands/netstats.cpp
gm_commands/network.cpp
gm_commands/npccast.cpp
gm_commands/npcedit.cpp
gm_commands/npceditmass.cpp
gm_commands/npcemote.cpp
gm_commands/npcloot.cpp
gm_commands/npcsay.cpp
gm_commands/npcshout.cpp
gm_commands/npcspawn.cpp
gm_commands/npcspecialattk.cpp
gm_commands/npcstats.cpp
gm_commands/npctype_cache.cpp
gm_commands/npctypespawn.cpp
gm_commands/nudge.cpp
gm_commands/nukebuffs.cpp
gm_commands/nukeitem.cpp
gm_commands/object.cpp
gm_commands/oocmute.cpp
gm_commands/opcode.cpp
gm_commands/path.cpp
gm_commands/peekinv.cpp
gm_commands/peqzone.cpp
gm_commands/permaclass.cpp
gm_commands/permagender.cpp
gm_commands/permarace.cpp
gm_commands/petitioninfo.cpp
gm_commands/petname.cpp
gm_commands/pf.cpp
gm_commands/picklock.cpp
gm_commands/profanity.cpp
gm_commands/proximity.cpp
gm_commands/push.cpp
gm_commands/pvp.cpp
gm_commands/qglobal.cpp
gm_commands/questerrors.cpp
gm_commands/race.cpp
gm_commands/raidloot.cpp
gm_commands/randomfeatures.cpp
gm_commands/refreshgroup.cpp
gm_commands/reloadaa.cpp
gm_commands/reloadallrules.cpp
gm_commands/reloademote.cpp
gm_commands/reloadlevelmods.cpp
gm_commands/reloadmerchants.cpp
gm_commands/reloadperlexportsettings.cpp
gm_commands/reloadqst.cpp
gm_commands/reloadstatic.cpp
gm_commands/reloadtitles.cpp
gm_commands/reloadtraps.cpp
gm_commands/reloadworld.cpp
gm_commands/reloadworldrules.cpp
gm_commands/reloadzps.cpp
gm_commands/repop.cpp
gm_commands/resetaa.cpp
gm_commands/resetaa_timer.cpp
gm_commands/resetdisc_timer.cpp
gm_commands/revoke.cpp
gm_commands/roambox.cpp
gm_commands/rules.cpp
gm_commands/save.cpp
gm_commands/scale.cpp
gm_commands/scribespell.cpp
gm_commands/scribespells.cpp
gm_commands/sendzonespawns.cpp
gm_commands/sensetrap.cpp
gm_commands/serverinfo.cpp
gm_commands/serverrules.cpp
gm_commands/set_adventure_points.cpp
gm_commands/setaapts.cpp
gm_commands/setaaxp.cpp
gm_commands/setanim.cpp
gm_commands/setcrystals.cpp
gm_commands/setfaction.cpp
gm_commands/setgraveyard.cpp
gm_commands/setlanguage.cpp
gm_commands/setlsinfo.cpp
gm_commands/setpass.cpp
gm_commands/setpvppoints.cpp
gm_commands/setskill.cpp
gm_commands/setskillall.cpp
gm_commands/setstartzone.cpp
gm_commands/setstat.cpp
gm_commands/setxp.cpp
gm_commands/showbonusstats.cpp
gm_commands/showbuffs.cpp
gm_commands/shownpcgloballoot.cpp
gm_commands/shownumhits.cpp
gm_commands/showskills.cpp
gm_commands/showspellslist.cpp
gm_commands/showstats.cpp
gm_commands/showzonegloballoot.cpp
gm_commands/showzonepoints.cpp
gm_commands/shutdown.cpp
gm_commands/size.cpp
gm_commands/spawn.cpp
gm_commands/spawnfix.cpp
gm_commands/spawnstatus.cpp
gm_commands/spellinfo.cpp
gm_commands/stun.cpp
gm_commands/summon.cpp
gm_commands/summonburiedplayercorpse.cpp
gm_commands/summonitem.cpp
gm_commands/suspend.cpp
gm_commands/task.cpp
gm_commands/tattoo.cpp
gm_commands/tempname.cpp
gm_commands/texture.cpp
gm_commands/time.cpp
gm_commands/timers.cpp
gm_commands/timezone.cpp
gm_commands/title.cpp
gm_commands/titlesuffix.cpp
gm_commands/traindisc.cpp
gm_commands/trapinfo.cpp
gm_commands/tune.cpp
gm_commands/ucs.cpp
gm_commands/undye.cpp
gm_commands/undyeme.cpp
gm_commands/unfreeze.cpp
gm_commands/unlock.cpp
gm_commands/unscribespell.cpp
gm_commands/unscribespells.cpp
gm_commands/untraindisc.cpp
gm_commands/untraindiscs.cpp
gm_commands/uptime.cpp
gm_commands/version.cpp
gm_commands/viewnpctype.cpp
gm_commands/viewpetition.cpp
gm_commands/viewzoneloot.cpp
gm_commands/wc.cpp
gm_commands/weather.cpp
gm_commands/who.cpp
gm_commands/worldshutdown.cpp
gm_commands/worldwide.cpp
gm_commands/wp.cpp
gm_commands/wpadd.cpp
gm_commands/wpinfo.cpp
gm_commands/xtargets.cpp
gm_commands/zclip.cpp
gm_commands/zcolor.cpp
gm_commands/zheader.cpp
gm_commands/zonebootup.cpp
gm_commands/zonelock.cpp
gm_commands/zoneshutdown.cpp
gm_commands/zonespawn.cpp
gm_commands/zonestatus.cpp
gm_commands/zopp.cpp
gm_commands/zsafecoords.cpp
gm_commands/zsave.cpp
gm_commands/zsky.cpp
gm_commands/zstats.cpp
gm_commands/zunderworld.cpp
gm_commands/zuwcoords.cpp
)
ADD_EXECUTABLE(zone ${zone_sources} ${zone_headers})
ADD_EXECUTABLE(zone ${zone_sources} ${zone_headers} ${gm_commands})
INSTALL(TARGETS zone RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)

File diff suppressed because it is too large Load Diff

View File

@ -1,22 +1,3 @@
/* 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 COMMAND_H
#define COMMAND_H
@ -25,18 +6,18 @@ class Seperator;
#include "../common/types.h"
#define COMMAND_CHAR '#'
#define COMMAND_CHAR '#'
typedef void (*CmdFuncPtr)(Client *,const Seperator *);
typedef void (*CmdFuncPtr)(Client *, const Seperator *);
typedef struct {
int access;
const char *desc; // description of command
CmdFuncPtr function; // null means perl function
} CommandRecord;
int access;
const char *desc; // description of command
CmdFuncPtr function; // null means perl function
} CommandRecord;
extern int (*command_dispatch)(Client *,char const*);
extern int commandcount; // number of commands loaded
extern int (*command_dispatch)(Client *, char const *);
extern int commandcount; // number of commands loaded
// the command system:
int command_init(void);
@ -59,7 +40,7 @@ void command_augmentitem(Client *c, const Seperator *sep);
void command_ban(Client *c, const Seperator *sep);
void command_beard(Client *c, const Seperator *sep);
void command_beardcolor(Client *c, const Seperator *sep);
void command_bind(Client* c, const Seperator *sep);
void command_bind(Client *c, const Seperator *sep);
void command_camerashake(Client *c, const Seperator *sep);
void command_castspell(Client *c, const Seperator *sep);
void command_chat(Client *c, const Seperator *sep);
@ -87,10 +68,10 @@ void command_doanim(Client *c, const Seperator *sep);
void command_dye(Client *c, const Seperator *sep);
void command_dz(Client *c, const Seperator *sep);
void command_dzkickplayers(Client *c, const Seperator *sep);
void command_editmassrespawn(Client* c, const Seperator* sep);
void command_editmassrespawn(Client *c, const Seperator *sep);
void command_emote(Client *c, const Seperator *sep);
void command_emotesearch(Client* c, const Seperator *sep);
void command_emoteview(Client* c, const Seperator *sep);
void command_emotesearch(Client *c, const Seperator *sep);
void command_emoteview(Client *c, const Seperator *sep);
void command_emptyinventory(Client *c, const Seperator *sep);
void command_enablerecipe(Client *c, const Seperator *sep);
void command_endurance(Client *c, const Seperator *sep);
@ -121,14 +102,14 @@ void command_getvariable(Client *c, const Seperator *sep);
void command_ginfo(Client *c, const Seperator *sep);
void command_giveitem(Client *c, const Seperator *sep);
void command_givemoney(Client *c, const Seperator *sep);
void command_globalview(Client* c, const Seperator *sep);
void command_globalview(Client *c, const Seperator *sep);
void command_gm(Client *c, const Seperator *sep);
void command_gmspeed(Client *c, const Seperator *sep);
void command_gmzone(Client *c, const Seperator *sep);
void command_goto(Client *c, const Seperator *sep);
void command_grid(Client *c, const Seperator *sep);
void command_guild(Client *c, const Seperator *sep);
bool helper_guild_edit(Client *c, uint32 dbid, uint32 eqid, uint8 rank, const char* what, const char* value);
bool helper_guild_edit(Client *c, uint32 dbid, uint32 eqid, uint8 rank, const char *what, const char *value);
void command_guildapprove(Client *c, const Seperator *sep);
void command_guildcreate(Client *c, const Seperator *sep);
void command_guildlist(Client *c, const Seperator *sep);
@ -193,12 +174,14 @@ void command_npcspecialattk(Client *c, const Seperator *sep);
void command_npcstats(Client *c, const Seperator *sep);
void command_npctype_cache(Client *c, const Seperator *sep);
void command_npctypespawn(Client *c, const Seperator *sep);
void command_nudge(Client* c, const Seperator* sep);
void command_nudge(Client *c, const Seperator *sep);
void command_nukebuffs(Client *c, const Seperator *sep);
void command_nukeitem(Client *c, const Seperator *sep);
void command_object(Client* c, const Seperator *sep);
void command_object(Client *c, const Seperator *sep);
void command_oocmute(Client *c, const Seperator *sep);
void command_opcode(Client *c, const Seperator *sep);
void command_bestz(Client *c, const Seperator *message);
void command_pf(Client *c, const Seperator *message);
#ifdef PACKET_PROFILER
void command_packetprofile(Client *c, const Seperator *sep);
@ -225,24 +208,24 @@ void command_pvp(Client *c, const Seperator *sep);
void command_qglobal(Client *c, const Seperator *sep);
void command_questerrors(Client *c, const Seperator *sep);
void command_race(Client *c, const Seperator *sep);
void command_raidloot(Client* c, const Seperator *sep);
void command_raidloot(Client *c, const Seperator *sep);
void command_randomfeatures(Client *c, const Seperator *sep);
void command_refreshgroup(Client *c, const Seperator *sep);
void command_reloadaa(Client *c, const Seperator *sep);
void command_reloadallrules(Client *c, const Seperator *sep);
void command_reloademote(Client* c, const Seperator *sep);
void command_reloademote(Client *c, const Seperator *sep);
void command_reloadlevelmods(Client *c, const Seperator *sep);
void command_reloadmerchants(Client *c, const Seperator *sep);
void command_reloadperlexportsettings(Client *c, const Seperator *sep);
void command_reloadqst(Client *c, const Seperator *sep);
void command_reloadstatic(Client *c, const Seperator *sep);
void command_reloadtitles(Client *c, const Seperator *sep);
void command_reloadtraps(Client* c, const Seperator *sep);
void command_reloadtraps(Client *c, const Seperator *sep);
void command_reloadworld(Client *c, const Seperator *sep);
void command_reloadworldrules(Client *c, const Seperator *sep);
void command_reloadzps(Client *c, const Seperator *sep);
void command_repop(Client *c, const Seperator *sep);
void command_resetaa(Client* c,const Seperator *sep);
void command_resetaa(Client *c, const Seperator *sep);
void command_resetaa_timer(Client *c, const Seperator *sep);
void command_resetdisc_timer(Client *c, const Seperator *sep);
void command_revoke(Client *c, const Seperator *sep);
@ -305,7 +288,7 @@ void command_timezone(Client *c, const Seperator *sep);
void command_title(Client *c, const Seperator *sep);
void command_titlesuffix(Client *c, const Seperator *sep);
void command_traindisc(Client *c, const Seperator *sep);
void command_trapinfo(Client* c, const Seperator *sep);
void command_trapinfo(Client *c, const Seperator *sep);
void command_tune(Client *c, const Seperator *sep);
void command_ucs(Client *c, const Seperator *sep);
void command_undye(Client *c, const Seperator *sep);

View File

@ -0,0 +1,11 @@
#include "../client.h"
void command_acceptrules(Client *c, const Seperator *sep)
{
if (!database.GetAgreementFlag(c->AccountID())) {
database.SetAgreementFlag(c->AccountID());
c->SendAppearancePacket(AT_Anim, ANIM_STAND);
c->Message(Chat::White, "It is recorded you have agreed to the rules.");
}
}

534
zone/gm_commands/advnpcspawn.cpp Executable file
View File

@ -0,0 +1,534 @@
#include "../client.h"
#include "../groups.h"
void command_advnpcspawn(Client *c, const Seperator *sep)
{
int arguments = sep->argnum;
if (!arguments) {
c->Message(
Chat::White,
"Usage: #advnpcspawn addentry [Spawngroup ID] [NPC ID] [Spawn Chance] - Adds a new Spawngroup Entry"
);
c->Message(
Chat::White,
"Usage: #advnpcspawn addspawn [Spawngroup ID] - Adds a new Spawngroup Entry from an existing Spawngroup"
);
c->Message(Chat::White, "Usage: #advnpcspawn clearbox [Spawngroup ID] - Clears the roambox of a Spawngroup");
c->Message(Chat::White, "Usage: #advnpcspawn deletespawn - Deletes a Spawngroup");
c->Message(
Chat::White,
"Usage: #advnpcspawn editbox [Spawngroup ID] [Distance] [Minimum X] [Maximum X] [Minimum Y] [Maximum Y] [Delay] - Edit the roambox of a Spawngroup"
);
c->Message(
Chat::White,
"Usage: #advnpcspawn editrespawn [Respawn Timer] [Variance] - Edit the Respawn Timer of a Spawngroup"
);
c->Message(
Chat::White,
"Usage: #advnpcspawn makegroup [Spawn Group Name] [Spawn Limit] [Distance] [Minimum X] [Maximum X] [Minimum Y] [Maximum Y] [Delay] - Makes a new Spawngroup"
);
c->Message(Chat::White, "Usage: #advnpcspawn makenpc - Makes a new NPC");
c->Message(Chat::White, "Usage: #advnpcspawn movespawn - Moves a Spawngroup to your current location");
c->Message(Chat::White, "Usage: #advnpcspawn setversion [Version] - Sets a Spawngroup's Version");
return;
}
std::string spawn_command = str_tolower(sep->arg[1]);
bool is_add_entry = spawn_command.find("addentry") != std::string::npos;
bool is_add_spawn = spawn_command.find("addspawn") != std::string::npos;
bool is_clear_box = spawn_command.find("clearbox") != std::string::npos;
bool is_delete_spawn = spawn_command.find("deletespawn") != std::string::npos;
bool is_edit_box = spawn_command.find("editgroup") != std::string::npos;
bool is_edit_respawn = spawn_command.find("editrespawn") != std::string::npos;
bool is_make_group = spawn_command.find("makegroup") != std::string::npos;
bool is_make_npc = spawn_command.find("makenpc") != std::string::npos;
bool is_move_spawn = spawn_command.find("movespawn") != std::string::npos;
bool is_set_version = spawn_command.find("setversion") != std::string::npos;
if (
!is_add_entry &&
!is_add_spawn &&
!is_clear_box &&
!is_delete_spawn &&
!is_edit_box &&
!is_edit_respawn &&
!is_make_group &&
!is_make_npc &&
!is_move_spawn &&
!is_set_version
) {
c->Message(
Chat::White,
"Usage: #advnpcspawn addentry [Spawngroup ID] [NPC ID] [Spawn Chance] - Adds a new Spawngroup Entry"
);
c->Message(
Chat::White,
"Usage: #advnpcspawn addspawn [Spawngroup ID] - Adds a new Spawngroup Entry from an existing Spawngroup"
);
c->Message(Chat::White, "Usage: #advnpcspawn clearbox [Spawngroup ID] - Clears the roambox of a Spawngroup");
c->Message(Chat::White, "Usage: #advnpcspawn deletespawn - Deletes a Spawngroup");
c->Message(
Chat::White,
"Usage: #advnpcspawn editbox [Spawngroup ID] [Distance] [Minimum X] [Maximum X] [Minimum Y] [Maximum Y] [Delay] - Edit the roambox of a Spawngroup"
);
c->Message(
Chat::White,
"Usage: #advnpcspawn editrespawn [Respawn Timer] [Variance] - Edit the Respawn Timer of a Spawngroup"
);
c->Message(
Chat::White,
"Usage: #advnpcspawn makegroup [Spawn Group Name] [Spawn Limit] [Distance] [Minimum X] [Maximum X] [Minimum Y] [Maximum Y] [Delay] - Makes a new Spawngroup"
);
c->Message(Chat::White, "Usage: #advnpcspawn makenpc - Makes a new NPC");
c->Message(Chat::White, "Usage: #advnpcspawn movespawn - Moves a Spawngroup to your current location");
c->Message(Chat::White, "Usage: #advnpcspawn setversion [Version] - Sets a Spawngroup's Version");
return;
}
if (is_add_entry) {
if (arguments < 4) {
c->Message(Chat::White, "Usage: #advnpcspawn addentry [Spawngroup ID] [NPC ID] [Spawn Chance]");
return;
}
auto spawngroup_id = std::stoi(sep->arg[2]);
auto npc_id = std::stoi(sep->arg[2]);
auto spawn_chance = std::stoi(sep->arg[2]);
std::string query = fmt::format(
SQL(
INSERT INTO spawnentry(spawngroupID, npcID, chance)
VALUES({}, {}, {})
),
spawngroup_id,
npc_id,
spawn_chance
);
auto results = content_db.QueryDatabase(query);
if (!results.Success()) {
c->Message(Chat::White, "Failed to add entry to Spawngroup.");
return;
}
c->Message(
Chat::White,
fmt::format(
"{} ({}) added to Spawngroup {}, its spawn chance is {}%%.",
database.GetCleanNPCNameByID(npc_id),
npc_id,
spawngroup_id,
spawn_chance
).c_str()
);
return;
}
else if (is_add_spawn) {
content_db.NPCSpawnDB(
NPCSpawnTypes::AddSpawnFromSpawngroup,
zone->GetShortName(),
zone->GetInstanceVersion(),
c,
0,
std::stoi(sep->arg[2])
);
c->Message(
Chat::White,
fmt::format(
"Spawn Added | Added spawn from Spawngroup ID {}.",
std::stoi(sep->arg[2])
).c_str()
);
return;
}
else if (is_clear_box) {
if (arguments != 2 || !sep->IsNumber(2)) {
c->Message(Chat::White, "Usage: #advnpcspawn clearbox [Spawngroup ID]");
return;
}
std::string query = fmt::format(
"UPDATE spawngroup SET dist = 0, min_x = 0, max_x = 0, min_y = 0, max_y = 0, delay = 0 WHERE id = {}",
std::stoi(sep->arg[2])
);
auto results = content_db.QueryDatabase(query);
if (!results.Success()) {
c->Message(Chat::White, "Failed to clear Spawngroup box.");
return;
}
c->Message(
Chat::White,
fmt::format(
"Spawngroup {} Roambox Cleared | Delay: 0 Distance: 0.00",
std::stoi(sep->arg[2])
).c_str()
);
c->Message(
Chat::White,
fmt::format(
"Spawngroup {} Roambox Cleared | Minimum X: 0.00 Maximum X: 0.00",
std::stoi(sep->arg[2])
).c_str()
);
c->Message(
Chat::White,
fmt::format(
"Spawngroup {} Roambox Cleared | Minimum Y: 0.00 Maximum Y: 0.00",
std::stoi(sep->arg[2])
).c_str()
);
return;
}
else if (is_delete_spawn) {
if (!c->GetTarget() || !c->GetTarget()->IsNPC()) {
c->Message(Chat::White, "You must target an NPC to use this command.");
return;
}
NPC *target = c->GetTarget()->CastToNPC();
Spawn2 *spawn2 = target->respawn2;
if (!spawn2) {
c->Message(Chat::White, "Failed to delete spawn because NPC has no Spawn2.");
return;
}
auto spawn2_id = spawn2->GetID();
std::string query = fmt::format(
"DELETE FROM spawn2 WHERE id = {}",
spawn2_id
);
auto results = content_db.QueryDatabase(query);
if (!results.Success()) {
c->Message(Chat::White, "Failed to delete spawn.");
return;
}
c->Message(
Chat::White,
fmt::format(
"Spawn2 {} Deleted | Name: {} ({})",
spawn2_id,
target->GetCleanName(),
target->GetID()
).c_str()
);
target->Depop(false);
return;
}
else if (is_edit_box) {
if (
arguments != 8 ||
!sep->IsNumber(3) ||
!sep->IsNumber(4) ||
!sep->IsNumber(5) ||
!sep->IsNumber(6) ||
!sep->IsNumber(7) ||
!sep->IsNumber(8)
) {
c->Message(
Chat::White,
"Usage: #advnpcspawn editbox [Spawngroup ID] [Distance] [Minimum X] [Maximum X] [Minimum Y] [Maximum Y] [Delay]"
);
return;
}
auto spawngroup_id = std::stoi(sep->arg[2]);
auto distance = std::stof(sep->arg[3]);
auto minimum_x = std::stof(sep->arg[4]);
auto maximum_x = std::stof(sep->arg[5]);
auto minimum_y = std::stof(sep->arg[6]);
auto maximum_y = std::stof(sep->arg[7]);
auto delay = std::stoi(sep->arg[8]);
std::string query = fmt::format(
"UPDATE spawngroup SET dist = {:.2f}, min_x = {:.2f}, max_x = {:.2f}, max_y = {:.2f}, min_y = {:.2f}, delay = {} WHERE id = {}",
distance,
minimum_x,
maximum_x,
minimum_y,
maximum_y,
delay,
spawngroup_id
);
auto results = content_db.QueryDatabase(query);
if (!results.Success()) {
c->Message(Chat::White, "Failed to edit Spawngroup box.");
return;
}
c->Message(
Chat::White,
fmt::format(
"Spawngroup {} Roambox Edited | Delay: {} Distance: {:.2f}",
spawngroup_id,
delay,
distance
).c_str()
);
c->Message(
Chat::White,
fmt::format(
"Spawngroup {} Roambox Edited | Minimum X: {:.2f} Maximum X: {:.2f}",
spawngroup_id,
minimum_x,
maximum_x
).c_str()
);
c->Message(
Chat::White,
fmt::format(
"Spawngroup {} Roambox Edited | Minimum Y: {:.2f} Maximum Y: {:.2f}",
spawngroup_id,
minimum_y,
maximum_y
).c_str()
);
return;
}
else if (is_edit_respawn) {
if (arguments < 2 || !sep->IsNumber(2)) {
c->Message(Chat::White, "Usage: #advnpcspawn editrespawn [Respawn Timer] [Variance]");
return;
}
if (!c->GetTarget() || !c->GetTarget()->IsNPC()) {
c->Message(Chat::White, "You must target an NPC to use this command.");
return;
}
NPC *target = c->GetTarget()->CastToNPC();
Spawn2 *spawn2 = target->respawn2;
if (!spawn2) {
c->Message(Chat::White, "Failed to edit respawn because NPC has no Spawn2.");
return;
}
auto spawn2_id = spawn2->GetID();
uint32 respawn_timer = std::stoi(sep->arg[2]);
uint32 variance = (
sep->IsNumber(3) ?
std::stoi(sep->arg[3]) :
spawn2->GetVariance()
);
std::string query = fmt::format(
"UPDATE spawn2 SET respawntime = {}, variance = {} WHERE id = {}",
respawn_timer,
variance,
spawn2_id
);
auto results = content_db.QueryDatabase(query);
if (!results.Success()) {
c->Message(Chat::White, "Failed to edit respawn.");
return;
}
c->Message(
Chat::White,
fmt::format(
"Spawn2 {} Respawn Modified | Name: {} ({}) Respawn Timer: {} Variance: {}",
spawn2_id,
target->GetCleanName(),
target->GetID(),
respawn_timer,
variance
).c_str()
);
spawn2->SetRespawnTimer(respawn_timer);
spawn2->SetVariance(variance);
return;
}
else if (is_make_group) {
if (
arguments != 9 ||
!sep->IsNumber(3) ||
!sep->IsNumber(4) ||
!sep->IsNumber(5) ||
!sep->IsNumber(6) ||
!sep->IsNumber(7) ||
!sep->IsNumber(8) ||
!sep->IsNumber(9)
) {
c->Message(
Chat::White,
"Usage: #advncspawn makegroup [Spawn Group Name] [Spawn Limit] [Distance] [Minimum X] [Maximum X] [Minimum Y] [Maximum Y] [Delay]"
);
return;
}
std::string spawngroup_name = sep->arg[2];
auto spawn_limit = std::stoi(sep->arg[3]);
auto distance = std::stof(sep->arg[4]);
auto minimum_x = std::stof(sep->arg[5]);
auto maximum_x = std::stof(sep->arg[6]);
auto minimum_y = std::stof(sep->arg[7]);
auto maximum_y = std::stof(sep->arg[8]);
auto delay = std::stoi(sep->arg[9]);
std::string query = fmt::format(
"INSERT INTO spawngroup"
"(name, spawn_limit, dist, min_x, max_x, min_y, max_y, delay)"
"VALUES ('{}', {}, {:.2f}, {:.2f}, {:.2f}, {:.2f}, {:.2f}, {})",
spawngroup_name,
spawn_limit,
distance,
minimum_x,
maximum_x,
minimum_y,
maximum_y,
delay
);
auto results = content_db.QueryDatabase(query);
if (!results.Success()) {
c->Message(Chat::White, "Failed to make Spawngroup.");
return;
}
auto spawngroup_id = results.LastInsertedID();
c->Message(
Chat::White,
fmt::format(
"Spawngroup {} Created | Name: {} Spawn Limit: {}",
spawngroup_id,
spawngroup_name,
spawn_limit
).c_str()
);
c->Message(
Chat::White,
fmt::format(
"Spawngroup {} Created | Delay: {} Distance: {:.2f}",
spawngroup_id,
delay,
distance
).c_str()
);
c->Message(
Chat::White,
fmt::format(
"Spawngroup {} Created | Minimum X: {:.2f} Maximum X: {:.2f}",
spawngroup_id,
minimum_x,
maximum_x
).c_str()
);
c->Message(
Chat::White,
fmt::format(
"Spawngroup {} Created | Minimum Y: {:.2f} Maximum Y: {:.2f}",
spawngroup_id,
minimum_y,
maximum_y
).c_str()
);
return;
}
else if (is_make_npc) {
if (!c->GetTarget() || !c->GetTarget()->IsNPC()) {
c->Message(Chat::White, "You must target an NPC to use this command.");
return;
}
NPC *target = c->GetTarget()->CastToNPC();
content_db.NPCSpawnDB(
NPCSpawnTypes::CreateNewNPC,
zone->GetShortName(),
zone->GetInstanceVersion(),
c,
target
);
return;
}
else if (is_move_spawn) {
if (!c->GetTarget() || !c->GetTarget()->IsNPC()) {
c->Message(Chat::White, "You must target an NPC to use this command.");
return;
}
NPC *target = c->GetTarget()->CastToNPC();
Spawn2 *spawn2 = target->respawn2;
if (!spawn2) {
c->Message(Chat::White, "Failed to move spawn because NPC has no Spawn2.");
return;
}
auto client_position = c->GetPosition();
auto spawn2_id = spawn2->GetID();
std::string query = fmt::format(
"UPDATE spawn2 SET x = {:.2f}, y = {:.2f}, z = {:.2f}, heading = {:.2f} WHERE id = {}",
client_position.x,
client_position.y,
client_position.z,
client_position.w,
spawn2_id
);
auto results = content_db.QueryDatabase(query);
if (!results.Success()) {
c->Message(Chat::White, "Failed to move spawn.");
return;
}
c->Message(
Chat::White,
fmt::format(
"Spawn2 {} Moved | Name: {} ({})",
spawn2_id,
target->GetCleanName(),
target->GetID()
).c_str()
);
c->Message(
Chat::White,
fmt::format(
"Spawn2 {} Moved | XYZ: {}, {}, {} Heading: {}",
spawn2_id,
client_position.x,
client_position.y,
client_position.z,
client_position.w
).c_str()
);
target->GMMove(
client_position.x,
client_position.y,
client_position.z,
client_position.w
);
return;
}
else if (is_set_version) {
if (arguments != 2 || !sep->IsNumber(2)) {
c->Message(Chat::White, "Usage: #advnpcspawn setversion [Version]");
return;
}
if (!c->GetTarget() || !c->GetTarget()->IsNPC()) {
c->Message(Chat::White, "You must target an NPC to use this command.");
return;
}
NPC *target = c->GetTarget()->CastToNPC();
auto version = std::stoi(sep->arg[2]);
std::string query = fmt::format(
"UPDATE spawn2 SET version = {} WHERE spawngroupID = {}",
version,
target->GetSpawnGroupId()
);
auto results = content_db.QueryDatabase(query);
if (!results.Success()) {
c->Message(Chat::White, "Failed to set version.");
return;
}
c->Message(
Chat::White,
fmt::format(
"Spawngroup {} Version Modified | Name: {} ({}) Version: {}",
target->GetSpawnGroupId(),
target->GetCleanName(),
target->GetID(),
version
).c_str()
);
target->Depop(false);
return;
}
}

21
zone/gm_commands/aggro.cpp Executable file
View File

@ -0,0 +1,21 @@
#include "../client.h"
void command_aggro(Client *c, const Seperator *sep)
{
if (c->GetTarget() == nullptr || !c->GetTarget()->IsNPC()) {
c->Message(Chat::White, "Error: you must have an NPC target.");
return;
}
float d = atof(sep->arg[1]);
if (d == 0.0f) {
c->Message(Chat::Red, "Error: distance argument required.");
return;
}
bool verbose = false;
if (sep->arg[2][0] == '-' && sep->arg[2][1] == 'v' && sep->arg[2][2] == '\0') {
verbose = true;
}
entity_list.DescribeAggro(c, c->GetTarget()->CastToNPC(), d, verbose);
}

19
zone/gm_commands/aggrozone.cpp Executable file
View File

@ -0,0 +1,19 @@
#include "../client.h"
void command_aggrozone(Client *c, const Seperator *sep)
{
if (!c) {
return;
}
Mob *m = c->CastToMob();
if (!m) {
return;
}
uint32 hate = atoi(sep->arg[1]); //should default to 0 if we don't enter anything
entity_list.AggroZone(m, hate);
c->Message(Chat::White, "Train to you! Last chance to go invulnerable...");
}

139
zone/gm_commands/ai.cpp Executable file
View File

@ -0,0 +1,139 @@
#include "../client.h"
void command_ai(Client *c, const Seperator *sep)
{
Mob *target = c->GetTarget();
if (strcasecmp(sep->arg[1], "factionid") == 0) {
if (target && sep->IsNumber(2)) {
if (target->IsNPC()) {
target->CastToNPC()->SetNPCFactionID(atoi(sep->arg[2]));
}
else {
c->Message(Chat::White, "%s is not an NPC.", target->GetName());
}
}
else {
c->Message(Chat::White, "Usage: (targeted) #ai factionid [factionid]");
}
}
else if (strcasecmp(sep->arg[1], "spellslist") == 0) {
if (target && sep->IsNumber(2) && atoi(sep->arg[2]) >= 0) {
if (target->IsNPC()) {
target->CastToNPC()->AI_AddNPCSpells(atoi(sep->arg[2]));
}
else {
c->Message(Chat::White, "%s is not an NPC.", target->GetName());
}
}
else {
c->Message(Chat::White, "Usage: (targeted) #ai spellslist [npc_spells_id]");
}
}
else if (strcasecmp(sep->arg[1], "con") == 0) {
if (target && sep->arg[2][0] != 0) {
Mob *tar2 = entity_list.GetMob(sep->arg[2]);
if (tar2) {
c->Message(
Chat::White,
"%s considering %s: %i",
target->GetName(),
tar2->GetName(),
tar2->GetReverseFactionCon(target));
}
else {
c->Message(Chat::White, "Error: %s not found.", sep->arg[2]);
}
}
else {
c->Message(Chat::White, "Usage: (targeted) #ai con [mob name]");
}
}
else if (strcasecmp(sep->arg[1], "guard") == 0) {
if (target && target->IsNPC()) {
target->CastToNPC()->SaveGuardSpot(target->GetPosition());
}
else {
c->Message(
Chat::White,
"Usage: (targeted) #ai guard - sets npc to guard the current location (use #summon to move)"
);
}
}
else if (strcasecmp(sep->arg[1], "roambox") == 0) {
if (target && target->IsAIControlled() && target->IsNPC()) {
if ((sep->argnum == 6 || sep->argnum == 7 || sep->argnum == 8) && sep->IsNumber(2) && sep->IsNumber(3) &&
sep->IsNumber(4) && sep->IsNumber(5) && sep->IsNumber(6)) {
uint32 tmp = 2500;
uint32 tmp2 = 2500;
if (sep->IsNumber(7)) {
tmp = atoi(sep->arg[7]);
}
if (sep->IsNumber(8)) {
tmp2 = atoi(sep->arg[8]);
}
target->CastToNPC()->AI_SetRoambox(
atof(sep->arg[2]),
atof(sep->arg[3]),
atof(sep->arg[4]),
atof(sep->arg[5]),
atof(sep->arg[6]),
tmp,
tmp2
);
}
else if ((sep->argnum == 3 || sep->argnum == 4) && sep->IsNumber(2) && sep->IsNumber(3)) {
uint32 tmp = 2500;
uint32 tmp2 = 2500;
if (sep->IsNumber(4)) {
tmp = atoi(sep->arg[4]);
}
if (sep->IsNumber(5)) {
tmp2 = atoi(sep->arg[5]);
}
target->CastToNPC()->AI_SetRoambox(atof(sep->arg[2]), atof(sep->arg[3]), tmp, tmp2);
}
else {
c->Message(Chat::White, "Usage: #ai roambox dist max_x min_x max_y min_y [delay] [mindelay]");
c->Message(Chat::White, "Usage: #ai roambox dist roamdist [delay] [mindelay]");
}
}
else {
c->Message(Chat::White, "You need a AI NPC targeted");
}
}
else if (strcasecmp(sep->arg[1], "stop") == 0 && c->Admin() >= commandToggleAI) {
if (target) {
if (target->IsAIControlled()) {
target->AI_Stop();
}
else {
c->Message(Chat::White, "Error: Target is not AI controlled");
}
}
else {
c->Message(Chat::White, "Usage: Target a Mob with AI enabled and use this to turn off their AI.");
}
}
else if (strcasecmp(sep->arg[1], "start") == 0 && c->Admin() >= commandToggleAI) {
if (target) {
if (!target->IsAIControlled()) {
target->AI_Start();
}
else {
c->Message(Chat::White, "Error: Target is already AI controlled");
}
}
else {
c->Message(Chat::White, "Usage: Target a Mob with AI disabled and use this to turn on their AI.");
}
}
else {
c->Message(Chat::White, "#AI Sub-commands");
c->Message(Chat::White, " factionid");
c->Message(Chat::White, " spellslist");
c->Message(Chat::White, " con");
c->Message(Chat::White, " guard");
}
}

26
zone/gm_commands/appearance.cpp Executable file
View File

@ -0,0 +1,26 @@
#include "../client.h"
void command_appearance(Client *c, const Seperator *sep)
{
Mob *t = c->CastToMob();
// sends any appearance packet
// Dev debug command, for appearance types
if (sep->arg[2][0] == 0) {
c->Message(Chat::White, "Usage: #appearance type value");
}
else {
if ((c->GetTarget())) {
t = c->GetTarget();
}
t->SendAppearancePacket(atoi(sep->arg[1]), atoi(sep->arg[2]));
c->Message(
Chat::White,
"Sending appearance packet: target=%s, type=%s, value=%s",
t->GetName(),
sep->arg[1],
sep->arg[2]
);
}
}

18
zone/gm_commands/attack.cpp Executable file
View File

@ -0,0 +1,18 @@
#include "../client.h"
void command_attack(Client *c, const Seperator *sep)
{
if (c->GetTarget() && c->GetTarget()->IsNPC() && sep->arg[1] != 0) {
Mob *sictar = entity_list.GetMob(sep->argplus[1]);
if (sictar) {
c->GetTarget()->CastToNPC()->AddToHateList(sictar, 1, 0);
}
else {
c->Message(Chat::White, "Error: %s not found", sep->arg[1]);
}
}
else {
c->Message(Chat::White, "Usage: (needs NPC targeted) #attack targetname");
}
}

View File

@ -0,0 +1,18 @@
#include "../client.h"
#include "../object.h"
void command_augmentitem(Client *c, const Seperator *sep)
{
if (!c) {
return;
}
auto in_augment = new AugmentItem_Struct[sizeof(AugmentItem_Struct)];
in_augment->container_slot = 1000; // <watch>
in_augment->augment_slot = -1;
if (c->GetTradeskillObject() != nullptr) {
Object::HandleAugmentation(c, in_augment, c->GetTradeskillObject());
}
safe_delete_array(in_augment);
}

72
zone/gm_commands/ban.cpp Executable file
View File

@ -0,0 +1,72 @@
#include "../client.h"
#include "../worldserver.h"
extern WorldServer worldserver;
void command_ban(Client *c, const Seperator *sep)
{
if (sep->arg[1][0] == 0 || sep->arg[2][0] == 0) {
c->Message(Chat::White, "Usage: #ban <charname> <message>");
return;
}
auto account_id = database.GetAccountIDByChar(sep->arg[1]);
std::string message;
int i = 2;
while (1) {
if (sep->arg[i][0] == 0) {
break;
}
if (message.length() > 0) {
message.push_back(' ');
}
message += sep->arg[i];
++i;
}
if (message.length() == 0) {
c->Message(Chat::White, "Usage: #ban <charname> <message>");
return;
}
if (account_id == 0) {
c->Message(Chat::Red, "Character does not exist.");
return;
}
std::string query = StringFormat(
"UPDATE account SET status = -2, ban_reason = '%s' "
"WHERE id = %i", EscapeString(message).c_str(), account_id
);
auto results = database.QueryDatabase(query);
c->Message(
Chat::Red,
"Account number %i with the character %s has been banned with message: \"%s\"",
account_id,
sep->arg[1],
message.c_str());
ServerPacket flagUpdatePack(ServerOP_FlagUpdate, 6);
*((uint32 *) &flagUpdatePack.pBuffer[0]) = account_id;
*((int16 *) &flagUpdatePack.pBuffer[4]) = -2;
worldserver.SendPacket(&flagUpdatePack);
Client *client = nullptr;
client = entity_list.GetClientByName(sep->arg[1]);
if (client) {
client->WorldKick();
return;
}
ServerPacket kickPlayerPack(ServerOP_KickPlayer, sizeof(ServerKickPlayer_Struct));
ServerKickPlayer_Struct *skp = (ServerKickPlayer_Struct *) kickPlayerPack.pBuffer;
strcpy(skp->adminname, c->GetName());
strcpy(skp->name, sep->arg[1]);
skp->adminrank = c->Admin();
worldserver.SendPacket(&kickPlayerPack);
}

37
zone/gm_commands/beard.cpp Executable file
View File

@ -0,0 +1,37 @@
#include "../client.h"
void command_beard(Client *c, const Seperator *sep)
{
Mob *target = c->GetTarget();
if (!sep->IsNumber(1)) {
c->Message(Chat::White, "Usage: #beard [number of beard style]");
}
else if (!target) {
c->Message(Chat::White, "Error: this command requires a target");
}
else {
uint16 Race = target->GetRace();
uint8 Gender = target->GetGender();
uint8 Texture = 0xFF;
uint8 HelmTexture = 0xFF;
uint8 HairColor = target->GetHairColor();
uint8 BeardColor = target->GetBeardColor();
uint8 EyeColor1 = target->GetEyeColor1();
uint8 EyeColor2 = target->GetEyeColor2();
uint8 HairStyle = target->GetHairStyle();
uint8 LuclinFace = target->GetLuclinFace();
uint8 Beard = atoi(sep->arg[1]);
uint32 DrakkinHeritage = target->GetDrakkinHeritage();
uint32 DrakkinTattoo = target->GetDrakkinTattoo();
uint32 DrakkinDetails = target->GetDrakkinDetails();
target->SendIllusionPacket(
Race, Gender, Texture, HelmTexture, HairColor, BeardColor,
EyeColor1, EyeColor2, HairStyle, LuclinFace, Beard, 0xFF,
DrakkinHeritage, DrakkinTattoo, DrakkinDetails
);
c->Message(Chat::White, "Beard = %i", atoi(sep->arg[1]));
}
}

37
zone/gm_commands/beardcolor.cpp Executable file
View File

@ -0,0 +1,37 @@
#include "../client.h"
void command_beardcolor(Client *c, const Seperator *sep)
{
Mob *target = c->GetTarget();
if (!sep->IsNumber(1)) {
c->Message(Chat::White, "Usage: #beardcolor [number of beard color]");
}
else if (!target) {
c->Message(Chat::White, "Error: this command requires a target");
}
else {
uint16 Race = target->GetRace();
uint8 Gender = target->GetGender();
uint8 Texture = 0xFF;
uint8 HelmTexture = 0xFF;
uint8 HairColor = target->GetHairColor();
uint8 BeardColor = atoi(sep->arg[1]);
uint8 EyeColor1 = target->GetEyeColor1();
uint8 EyeColor2 = target->GetEyeColor2();
uint8 HairStyle = target->GetHairStyle();
uint8 LuclinFace = target->GetLuclinFace();
uint8 Beard = target->GetBeard();
uint32 DrakkinHeritage = target->GetDrakkinHeritage();
uint32 DrakkinTattoo = target->GetDrakkinTattoo();
uint32 DrakkinDetails = target->GetDrakkinDetails();
target->SendIllusionPacket(
Race, Gender, Texture, HelmTexture, HairColor, BeardColor,
EyeColor1, EyeColor2, HairStyle, LuclinFace, Beard, 0xFF,
DrakkinHeritage, DrakkinTattoo, DrakkinDetails
);
c->Message(Chat::White, "Beard Color = %i", atoi(sep->arg[1]));
}
}

89
zone/gm_commands/bestz.cpp Executable file
View File

@ -0,0 +1,89 @@
#include "../client.h"
#include "../water_map.h"
void command_bestz(Client *c, const Seperator *sep)
{
if (zone->zonemap == nullptr) {
c->Message(Chat::White, "Map not loaded for this zone");
}
else {
glm::vec3 me;
me.x = c->GetX();
me.y = c->GetY();
me.z = c->GetZ() + (c->GetSize() == 0.0 ? 6 : c->GetSize()) * HEAD_POSITION;
glm::vec3 hit;
glm::vec3 bme(me);
bme.z -= 500;
float best_z = zone->zonemap->FindBestZ(me, &hit);
if (best_z != BEST_Z_INVALID) {
c->Message(Chat::White, "Z is %.3f at (%.3f, %.3f).", best_z, me.x, me.y);
}
else {
c->Message(Chat::White, "Found no Z.");
}
}
if (zone->watermap == nullptr) {
c->Message(Chat::White, "Water Region Map not loaded for this zone");
}
else {
WaterRegionType RegionType;
float z;
if (c->GetTarget()) {
z = c->GetTarget()->GetZ();
auto position = glm::vec3(c->GetTarget()->GetX(), c->GetTarget()->GetY(), z);
RegionType = zone->watermap->ReturnRegionType(position);
c->Message(Chat::White, "InWater returns %d", zone->watermap->InWater(position));
c->Message(Chat::White, "InLava returns %d", zone->watermap->InLava(position));
}
else {
z = c->GetZ();
auto position = glm::vec3(c->GetX(), c->GetY(), z);
RegionType = zone->watermap->ReturnRegionType(position);
c->Message(Chat::White, "InWater returns %d", zone->watermap->InWater(position));
c->Message(Chat::White, "InLava returns %d", zone->watermap->InLava(position));
}
switch (RegionType) {
case RegionTypeNormal: {
c->Message(Chat::White, "There is nothing special about the region you are in!");
break;
}
case RegionTypeWater: {
c->Message(Chat::White, "You/your target are in Water.");
break;
}
case RegionTypeLava: {
c->Message(Chat::White, "You/your target are in Lava.");
break;
}
case RegionTypeVWater: {
c->Message(Chat::White, "You/your target are in VWater (Icy Water?).");
break;
}
case RegionTypePVP: {
c->Message(Chat::White, "You/your target are in a pvp enabled area.");
break;
}
case RegionTypeSlime: {
c->Message(Chat::White, "You/your target are in slime.");
break;
}
case RegionTypeIce: {
c->Message(Chat::White, "You/your target are in ice.");
break;
}
default:
c->Message(Chat::White, "You/your target are in an unknown region type.");
}
}
}

17
zone/gm_commands/bind.cpp Executable file
View File

@ -0,0 +1,17 @@
#include "../client.h"
void command_bind(Client *c, const Seperator *sep)
{
if (c->GetTarget() != 0) {
if (c->GetTarget()->IsClient()) {
c->GetTarget()->CastToClient()->SetBindPoint();
}
else {
c->Message(Chat::White, "Error: target not a Player");
}
}
else {
c->SetBindPoint();
}
}

View File

@ -0,0 +1,24 @@
#include "../client.h"
#include "../worldserver.h"
extern WorldServer worldserver;
void command_camerashake(Client *c, const Seperator *sep)
{
if (c) {
if (sep->arg[1][0] && sep->arg[2][0]) {
auto pack = new ServerPacket(ServerOP_CameraShake, sizeof(ServerCameraShake_Struct));
ServerCameraShake_Struct *scss = (ServerCameraShake_Struct *) pack->pBuffer;
scss->duration = atoi(sep->arg[1]);
scss->intensity = atoi(sep->arg[2]);
worldserver.SendPacket(pack);
c->Message(Chat::Red, "Successfully sent the packet to world! Shake it, world, shake it!");
safe_delete(pack);
}
else {
c->Message(Chat::Red, "Usage -- #camerashake [duration], [intensity [1-10])");
}
}
return;
}

77
zone/gm_commands/castspell.cpp Executable file
View File

@ -0,0 +1,77 @@
#include "../client.h"
void command_castspell(Client *c, const Seperator *sep)
{
if (SPDAT_RECORDS <= 0) {
c->Message(Chat::White, "Spells not loaded.");
return;
}
Mob *target = c;
if (c->GetTarget()) {
target = c->GetTarget();
}
if (!sep->IsNumber(1)) {
c->Message(
Chat::White,
"Usage: #castspell [Spell ID] [Instant (0 = False, 1 = True, Default is 1 if Unused)]"
);
}
else {
uint16 spell_id = std::stoul(sep->arg[1]);
if (CastRestrictedSpell(spell_id) && c->Admin() < commandCastSpecials) {
c->Message(Chat::Red, "Unable to cast spell.");
}
else if (spell_id >= SPDAT_RECORDS) {
c->Message(Chat::White, "Invalid Spell ID.");
}
else {
bool instant_cast = (c->Admin() >= commandInstacast ? true : false);
if (instant_cast && sep->IsNumber(2)) {
instant_cast = std::stoi(sep->arg[2]) ? true : false;
c->Message(Chat::White, fmt::format("{}", std::stoi(sep->arg[2])).c_str());
}
if (c->Admin() >= commandInstacast && instant_cast) {
c->SpellFinished(
spell_id,
target,
EQ::spells::CastingSlot::Item,
0,
-1,
spells[spell_id].resist_difficulty
);
}
else {
c->CastSpell(spell_id, target->GetID(), EQ::spells::CastingSlot::Item, spells[spell_id].cast_time);
}
if (c != target) {
c->Message(
Chat::White,
fmt::format(
"Cast {} ({}) on {}{}.",
GetSpellName(spell_id),
spell_id,
target->GetCleanName(),
instant_cast ? " instantly" : ""
).c_str()
);
}
else {
c->Message(
Chat::White,
fmt::format(
"Cast {} ({}) on yourself{}.",
GetSpellName(spell_id),
spell_id,
instant_cast ? " instantly" : ""
).c_str()
);
}
}
}
}

15
zone/gm_commands/chat.cpp Executable file
View File

@ -0,0 +1,15 @@
#include "../client.h"
#include "../worldserver.h"
extern WorldServer worldserver;
void command_chat(Client *c, const Seperator *sep)
{
if (sep->arg[2][0] == 0) {
c->Message(Chat::White, "Usage: #chat [channum] [message]");
}
else if (!worldserver.SendChannelMessage(0, 0, (uint8) atoi(sep->arg[1]), 0, 0, 100, sep->argplus[2])) {
c->Message(Chat::White, "Error: World server disconnected");
}
}

20
zone/gm_commands/checklos.cpp Executable file
View File

@ -0,0 +1,20 @@
#include "../client.h"
void command_checklos(Client *c, const Seperator *sep)
{
if (!c->GetTarget()) {
c->Message(Chat::White, "You must have a target to use this command.");
}
bool has_los = c->CheckLosFN(c->GetTarget());
c->Message(
Chat::White,
fmt::format(
"You {}have line of sight to {} ({}).",
has_los ? "" : "do not ",
c->GetTarget()->GetCleanName(),
c->GetTarget()->GetID()
).c_str()
);
}

View File

@ -0,0 +1,34 @@
#include "../client.h"
void command_copycharacter(Client *c, const Seperator *sep)
{
if (sep->argnum < 3) {
c->Message(
Chat::White,
"Usage: [source_character_name] [destination_character_name] [destination_account_name]"
);
return;
}
std::string source_character_name = sep->arg[1];
std::string destination_character_name = sep->arg[2];
std::string destination_account_name = sep->arg[3];
bool result = database.CopyCharacter(
source_character_name,
destination_character_name,
destination_account_name
);
c->Message(
Chat::Yellow,
fmt::format(
"Character Copy [{}] to [{}] via account [{}] [{}]",
source_character_name,
destination_character_name,
destination_account_name,
result ? "Success" : "Failed"
).c_str()
);
}

168
zone/gm_commands/corpse.cpp Executable file
View File

@ -0,0 +1,168 @@
#include "../client.h"
#include "../corpse.h"
void command_corpse(Client *c, const Seperator *sep)
{
Mob *target = c->GetTarget();
if (strcasecmp(sep->arg[1], "DeletePlayerCorpses") == 0 && c->Admin() >= commandEditPlayerCorpses) {
int32 tmp = entity_list.DeletePlayerCorpses();
if (tmp >= 0) {
c->Message(Chat::White, "%i corpses deleted.", tmp);
}
else {
c->Message(Chat::White, "DeletePlayerCorpses Error #%i", tmp);
}
}
else if (strcasecmp(sep->arg[1], "delete") == 0) {
if (target == 0 || !target->IsCorpse()) {
c->Message(Chat::White, "Error: Target the corpse you wish to delete");
}
else if (target->IsNPCCorpse()) {
c->Message(Chat::White, "Depoping %s.", target->GetName());
target->CastToCorpse()->Delete();
}
else if (c->Admin() >= commandEditPlayerCorpses) {
c->Message(Chat::White, "Deleting %s.", target->GetName());
target->CastToCorpse()->Delete();
}
else {
c->Message(Chat::White, "Insufficient status to delete player corpse.");
}
}
else if (strcasecmp(sep->arg[1], "ListNPC") == 0) {
entity_list.ListNPCCorpses(c);
}
else if (strcasecmp(sep->arg[1], "ListPlayer") == 0) {
entity_list.ListPlayerCorpses(c);
}
else if (strcasecmp(sep->arg[1], "DeleteNPCCorpses") == 0) {
int32 tmp = entity_list.DeleteNPCCorpses();
if (tmp >= 0) {
c->Message(Chat::White, "%d corpses deleted.", tmp);
}
else {
c->Message(Chat::White, "DeletePlayerCorpses Error #%d", tmp);
}
}
else if (strcasecmp(sep->arg[1], "charid") == 0 && c->Admin() >= commandEditPlayerCorpses) {
if (target == 0 || !target->IsPlayerCorpse()) {
c->Message(Chat::White, "Error: Target must be a player corpse.");
}
else if (!sep->IsNumber(2)) {
c->Message(Chat::White, "Error: charid must be a number.");
}
else {
c->Message(
Chat::White,
"Setting CharID=%u on PlayerCorpse '%s'",
target->CastToCorpse()->SetCharID(atoi(sep->arg[2])),
target->GetName());
}
}
else if (strcasecmp(sep->arg[1], "ResetLooter") == 0) {
if (target == 0 || !target->IsCorpse()) {
c->Message(Chat::White, "Error: Target the corpse you wish to reset");
}
else {
target->CastToCorpse()->ResetLooter();
}
}
else if (strcasecmp(sep->arg[1], "RemoveCash") == 0) {
if (target == 0 || !target->IsCorpse()) {
c->Message(Chat::White, "Error: Target the corpse you wish to remove the cash from");
}
else if (!target->IsPlayerCorpse() || c->Admin() >= commandEditPlayerCorpses) {
c->Message(Chat::White, "Removing Cash from %s.", target->GetName());
target->CastToCorpse()->RemoveCash();
}
else {
c->Message(Chat::White, "Insufficient status to modify player corpse.");
}
}
else if (strcasecmp(sep->arg[1], "InspectLoot") == 0) {
if (target == 0 || !target->IsCorpse()) {
c->Message(Chat::White, "Error: Target must be a corpse.");
}
else {
target->CastToCorpse()->QueryLoot(c);
}
}
else if (strcasecmp(sep->arg[1], "lock") == 0) {
if (target == 0 || !target->IsCorpse()) {
c->Message(Chat::White, "Error: Target must be a corpse.");
}
else {
target->CastToCorpse()->Lock();
c->Message(Chat::White, "Locking %s...", target->GetName());
}
}
else if (strcasecmp(sep->arg[1], "unlock") == 0) {
if (target == 0 || !target->IsCorpse()) {
c->Message(Chat::White, "Error: Target must be a corpse.");
}
else {
target->CastToCorpse()->UnLock();
c->Message(Chat::White, "Unlocking %s...", target->GetName());
}
}
else if (strcasecmp(sep->arg[1], "depop") == 0) {
if (target == 0 || !target->IsPlayerCorpse()) {
c->Message(Chat::White, "Error: Target must be a player corpse.");
}
else if (c->Admin() >= commandEditPlayerCorpses && target->IsPlayerCorpse()) {
c->Message(Chat::White, "Depoping %s.", target->GetName());
target->CastToCorpse()->DepopPlayerCorpse();
if (!sep->arg[2][0] || atoi(sep->arg[2]) != 0) {
target->CastToCorpse()->Bury();
}
}
else {
c->Message(Chat::White, "Insufficient status to depop player corpse.");
}
}
else if (strcasecmp(sep->arg[1], "depopall") == 0) {
if (target == 0 || !target->IsClient()) {
c->Message(Chat::White, "Error: Target must be a player.");
}
else if (c->Admin() >= commandEditPlayerCorpses && target->IsClient()) {
c->Message(Chat::White, "Depoping %s\'s corpses.", target->GetName());
target->CastToClient()->DepopAllCorpses();
if (!sep->arg[2][0] || atoi(sep->arg[2]) != 0) {
target->CastToClient()->BuryPlayerCorpses();
}
}
else {
c->Message(Chat::White, "Insufficient status to depop player corpse.");
}
}
else if (strcasecmp(sep->arg[1], "moveallgraveyard") == 0) {
int count = entity_list.MovePlayerCorpsesToGraveyard(true);
c->Message(Chat::White, "Moved [%d] player corpse(s) to zone graveyard", count);
}
else if (sep->arg[1][0] == 0 || strcasecmp(sep->arg[1], "help") == 0) {
c->Message(Chat::White, "#Corpse Sub-Commands:");
c->Message(Chat::White, " DeleteNPCCorpses");
c->Message(Chat::White, " Delete - Delete targetted corpse");
c->Message(Chat::White, " ListNPC");
c->Message(Chat::White, " ListPlayer");
c->Message(Chat::White, " Lock - GM locks the corpse - cannot be looted by non-GM");
c->Message(Chat::White, " MoveAllGraveyard - move all player corpses to zone's graveyard or non-instance");
c->Message(Chat::White, " UnLock");
c->Message(Chat::White, " RemoveCash");
c->Message(Chat::White, " InspectLoot");
c->Message(Chat::White, " [to remove items from corpses, loot them]");
c->Message(Chat::White, "Lead-GM status required to delete/modify player corpses");
c->Message(Chat::White, " DeletePlayerCorpses");
c->Message(Chat::White, " CharID [charid] - change player corpse's owner");
c->Message(Chat::White, " Depop [bury] - Depops single target corpse.");
c->Message(Chat::White, " Depopall [bury] - Depops all target player's corpses.");
c->Message(Chat::White, "Set bury to 0 to skip burying the corpses.");
}
else {
c->Message(Chat::White, "Error, #corpse sub-command not found");
}
}

8
zone/gm_commands/corpsefix.cpp Executable file
View File

@ -0,0 +1,8 @@
#include "../client.h"
#include "../corpse.h"
void command_corpsefix(Client *c, const Seperator *sep)
{
entity_list.CorpseFix(c);
}

17
zone/gm_commands/cvs.cpp Executable file
View File

@ -0,0 +1,17 @@
#include "../client.h"
#include "../worldserver.h"
extern WorldServer worldserver;
void command_cvs(Client *c, const Seperator *sep)
{
auto pack = new ServerPacket(
ServerOP_ClientVersionSummary,
sizeof(ServerRequestClientVersionSummary_Struct)
);
auto srcvss = (ServerRequestClientVersionSummary_Struct *) pack->pBuffer;
strn0cpy(srcvss->Name, c->GetName(), sizeof(srcvss->Name));
worldserver.SendPacket(pack);
safe_delete(pack);
}

21
zone/gm_commands/damage.cpp Executable file
View File

@ -0,0 +1,21 @@
#include "../client.h"
void command_damage(Client *c, const Seperator *sep)
{
if (c->GetTarget() == 0) {
c->Message(Chat::White, "Error: #Damage: No Target.");
}
else if (!sep->IsNumber(1)) {
c->Message(Chat::White, "Usage: #damage x");
}
else {
int32 nkdmg = atoi(sep->arg[1]);
if (nkdmg > 2100000000) {
c->Message(Chat::White, "Enter a value less then 2,100,000,000.");
}
else {
c->GetTarget()->Damage(c, nkdmg, SPELL_UNKNOWN, EQ::skills::SkillHandtoHand, false);
}
}
}

View File

@ -0,0 +1,92 @@
#include "../client.h"
#include "../data_bucket.h"
void command_databuckets(Client *c, const Seperator *sep)
{
if (sep->arg[1][0] == 0) {
c->Message(Chat::Yellow, "Usage: #databuckets view (partial key)|(limit) OR #databuckets delete (key)");
return;
}
if (strcasecmp(sep->arg[1], "view") == 0) {
std::string key_filter;
uint8 limit = 50;
for (int i = 2; i < 4; i++) {
if (sep->arg[i][0] == '\0') {
break;
}
if (strcasecmp(sep->arg[i], "limit") == 0) {
limit = (uint8) atoi(sep->arg[i + 1]);
continue;
}
}
if (sep->arg[2]) {
key_filter = str_tolower(sep->arg[2]);
}
std::string query = "SELECT `id`, `key`, `value`, `expires` FROM data_buckets";
if (!key_filter.empty()) { query += StringFormat(" WHERE `key` LIKE '%%%s%%'", key_filter.c_str()); }
query += StringFormat(" LIMIT %u", limit);
auto results = database.QueryDatabase(query);
if (!results.Success()) {
return;
}
if (results.RowCount() == 0) {
c->Message(Chat::Yellow, "No data_buckets found");
return;
}
int _ctr = 0;
// put in window for easier readability in case want command line for something else
std::string window_title = "Data Buckets";
std::string window_text =
"<table>"
"<tr>"
"<td>ID</td>"
"<td>Expires</td>"
"<td>Key</td>"
"<td>Value</td>"
"</tr>";
for (auto row = results.begin(); row != results.end(); ++row) {
auto id = static_cast<uint32>(atoi(row[0]));
std::string key = row[1];
std::string value = row[2];
std::string expires = row[3];
window_text.append(
StringFormat(
"<tr>"
"<td>%u</td>"
"<td>%s</td>"
"<td>%s</td>"
"<td>%s</td>"
"</tr>",
id,
expires.c_str(),
key.c_str(),
value.c_str()
));
_ctr++;
std::string del_saylink = StringFormat("#databuckets delete %s", key.c_str());
c->Message(
Chat::White,
"%s : %s",
EQ::SayLinkEngine::GenerateQuestSaylink(del_saylink, false, "Delete").c_str(),
key.c_str(),
" Value: ",
value.c_str());
}
window_text.append("</table>");
c->SendPopupToClient(window_title.c_str(), window_text.c_str());
std::string response = _ctr > 0 ? StringFormat("Found %i matching data buckets", _ctr).c_str()
: "No Databuckets found.";
c->Message(Chat::Yellow, response.c_str());
}
else if (strcasecmp(sep->arg[1], "delete") == 0) {
if (DataBucket::DeleteData(sep->argplus[2])) {
c->Message(Chat::Yellow, "data bucket %s deleted.", sep->argplus[2]);
}
else {
c->Message(Chat::Red, "An error occurred deleting data bucket %s", sep->argplus[2]);
}
return;
}
}

29
zone/gm_commands/date.cpp Executable file
View File

@ -0,0 +1,29 @@
#include "../client.h"
void command_date(Client *c, const Seperator *sep)
{
//yyyy mm dd hh mm local
if (sep->arg[3][0] == 0 || !sep->IsNumber(1) || !sep->IsNumber(2) || !sep->IsNumber(3)) {
c->Message(Chat::Red, "Usage: #date yyyy mm dd [HH MM]");
}
else {
int h = 0, m = 0;
TimeOfDay_Struct eqTime;
zone->zone_time.GetCurrentEQTimeOfDay(time(0), &eqTime);
if (!sep->IsNumber(4)) {
h = eqTime.hour;
}
else {
h = atoi(sep->arg[4]);
}
if (!sep->IsNumber(5)) {
m = eqTime.minute;
}
else {
m = atoi(sep->arg[5]);
}
c->Message(Chat::Red, "Setting world time to %s-%s-%s %i:%i...", sep->arg[1], sep->arg[2], sep->arg[3], h, m);
zone->SetDate(atoi(sep->arg[1]), atoi(sep->arg[2]), atoi(sep->arg[3]), h, m);
}
}

31
zone/gm_commands/dbspawn2.cpp Executable file
View File

@ -0,0 +1,31 @@
#include "../client.h"
void command_dbspawn2(Client *c, const Seperator *sep)
{
if (sep->IsNumber(1) && sep->IsNumber(2) && sep->IsNumber(3)) {
LogInfo("Spawning database spawn");
uint16 cond = 0;
int16 cond_min = 0;
if (sep->IsNumber(4)) {
cond = atoi(sep->arg[4]);
if (sep->IsNumber(5)) {
cond_min = atoi(sep->arg[5]);
}
}
database.CreateSpawn2(
c,
atoi(sep->arg[1]),
zone->GetShortName(),
c->GetPosition(),
atoi(sep->arg[2]),
atoi(sep->arg[3]),
cond,
cond_min
);
}
else {
c->Message(Chat::White, "Usage: #dbspawn2 spawngroup respawn variance [condition_id] [condition_min]");
}
}

21
zone/gm_commands/delacct.cpp Executable file
View File

@ -0,0 +1,21 @@
#include "../client.h"
void command_delacct(Client *c, const Seperator *sep)
{
if (sep->arg[1][0] == 0) {
c->Message(Chat::White, "Format: #delacct accountname");
}
else {
std::string user;
std::string loginserver;
ParseAccountString(sep->arg[1], user, loginserver);
if (database.DeleteAccount(user.c_str(), loginserver.c_str())) {
c->Message(Chat::White, "The account was deleted.");
}
else {
c->Message(Chat::White, "Unable to delete account.");
}
}
}

View File

@ -0,0 +1,35 @@
#include "../client.h"
void command_deletegraveyard(Client *c, const Seperator *sep)
{
uint32 zoneid = 0;
uint32 graveyard_id = 0;
if (!sep->arg[1][0]) {
c->Message(Chat::White, "Usage: #deletegraveyard [zonename]");
return;
}
zoneid = ZoneID(sep->arg[1]);
graveyard_id = content_db.GetZoneGraveyardID(zoneid, 0);
if (zoneid > 0 && graveyard_id > 0) {
if (content_db.DeleteGraveyard(zoneid, graveyard_id)) {
c->Message(Chat::White, "Successfuly deleted graveyard %u for zone %s.", graveyard_id, sep->arg[1]);
}
else {
c->Message(Chat::White, "Unable to delete graveyard %u for zone %s.", graveyard_id, sep->arg[1]);
}
}
else {
if (zoneid <= 0) {
c->Message(Chat::White, "Unable to retrieve a ZoneID for the zone: %s", sep->arg[1]);
}
else if (graveyard_id <= 0) {
c->Message(Chat::White, "Unable to retrieve a valid GraveyardID for the zone: %s", sep->arg[1]);
}
}
return;
}

View File

@ -0,0 +1,20 @@
#include "../client.h"
void command_delpetition(Client *c, const Seperator *sep)
{
if (sep->arg[1][0] == 0 || strcasecmp(sep->arg[1], "*") == 0) {
c->Message(Chat::White, "Usage: #delpetition (petition number) Type #listpetition for a list");
return;
}
c->Message(Chat::Red, "Attempting to delete petition number: %i", atoi(sep->argplus[1]));
std::string query = StringFormat("DELETE FROM petitions WHERE petid = %i", atoi(sep->argplus[1]));
auto results = database.QueryDatabase(query);
if (!results.Success()) {
return;
}
LogInfo("Delete petition request from [{}], petition number:", c->GetName(), atoi(sep->argplus[1]));
}

14
zone/gm_commands/depop.cpp Executable file
View File

@ -0,0 +1,14 @@
#include "../client.h"
#include "../corpse.h"
void command_depop(Client *c, const Seperator *sep)
{
if (c->GetTarget() == 0 || !(c->GetTarget()->IsNPC() || c->GetTarget()->IsNPCCorpse())) {
c->Message(Chat::White, "You must have a NPC target for this command. (maybe you meant #depopzone?)");
}
else {
c->Message(Chat::White, "Depoping '%s'.", c->GetTarget()->GetName());
c->GetTarget()->Depop();
}
}

8
zone/gm_commands/depopzone.cpp Executable file
View File

@ -0,0 +1,8 @@
#include "../client.h"
void command_depopzone(Client *c, const Seperator *sep)
{
zone->Depop();
c->Message(Chat::White, "Zone depoped.");
}

37
zone/gm_commands/details.cpp Executable file
View File

@ -0,0 +1,37 @@
#include "../client.h"
void command_details(Client *c, const Seperator *sep)
{
Mob *target = c->GetTarget();
if (!sep->IsNumber(1)) {
c->Message(Chat::White, "Usage: #details [number of drakkin detail]");
}
else if (!target) {
c->Message(Chat::White, "Error: this command requires a target");
}
else {
uint16 Race = target->GetRace();
uint8 Gender = target->GetGender();
uint8 Texture = 0xFF;
uint8 HelmTexture = 0xFF;
uint8 HairColor = target->GetHairColor();
uint8 BeardColor = target->GetBeardColor();
uint8 EyeColor1 = target->GetEyeColor1();
uint8 EyeColor2 = target->GetEyeColor2();
uint8 HairStyle = target->GetHairStyle();
uint8 LuclinFace = target->GetLuclinFace();
uint8 Beard = target->GetBeard();
uint32 DrakkinHeritage = target->GetDrakkinHeritage();
uint32 DrakkinTattoo = target->GetDrakkinTattoo();
uint32 DrakkinDetails = atoi(sep->arg[1]);
target->SendIllusionPacket(
Race, Gender, Texture, HelmTexture, HairColor, BeardColor,
EyeColor1, EyeColor2, HairStyle, LuclinFace, Beard, 0xFF,
DrakkinHeritage, DrakkinTattoo, DrakkinDetails
);
c->Message(Chat::White, "Details = %i", atoi(sep->arg[1]));
}
}

22
zone/gm_commands/devtools.cpp Executable file
View File

@ -0,0 +1,22 @@
#include "../client.h"
#include "../data_bucket.h"
void command_devtools(Client *c, const Seperator *sep)
{
std::string dev_tools_key = StringFormat("%i-dev-tools-disabled", c->AccountID());
/**
* Handle window toggle
*/
if (strcasecmp(sep->arg[1], "disable") == 0) {
DataBucket::SetData(dev_tools_key, "true");
c->SetDevToolsEnabled(false);
}
if (strcasecmp(sep->arg[1], "enable") == 0) {
DataBucket::DeleteData(dev_tools_key);
c->SetDevToolsEnabled(true);
}
c->ShowDevToolsMenu();
}

View File

@ -0,0 +1,29 @@
#include "../client.h"
void command_disablerecipe(Client *c, const Seperator *sep)
{
uint32 recipe_id = 0;
bool success = false;
if (c) {
if (sep->argnum == 1) {
recipe_id = atoi(sep->arg[1]);
}
else {
c->Message(Chat::White, "Invalid number of arguments.\nUsage: #disablerecipe recipe_id");
return;
}
if (recipe_id > 0) {
success = content_db.DisableRecipe(recipe_id);
if (success) {
c->Message(Chat::White, "Recipe disabled.");
}
else {
c->Message(Chat::White, "Recipe not disabled.");
}
}
else {
c->Message(Chat::White, "Invalid recipe id.\nUsage: #disablerecipe recipe_id");
}
}
}

25
zone/gm_commands/disarmtrap.cpp Executable file
View File

@ -0,0 +1,25 @@
#include "../client.h"
void command_disarmtrap(Client *c, const Seperator *sep)
{
Mob *target = c->GetTarget();
if (!target) {
c->Message(Chat::Red, "You must have a target.");
return;
}
if (target->IsNPC()) {
if (c->HasSkill(EQ::skills::SkillDisarmTraps)) {
if (DistanceSquaredNoZ(c->GetPosition(), target->GetPosition()) > RuleI(Adventure, LDoNTrapDistanceUse)) {
c->Message(Chat::Red, "%s is too far away.", target->GetCleanName());
return;
}
c->HandleLDoNDisarm(target->CastToNPC(), c->GetSkill(EQ::skills::SkillDisarmTraps), LDoNTypeMechanical);
}
else {
c->Message(Chat::Red, "You do not have the disarm trap skill.");
}
}
}

23
zone/gm_commands/distance.cpp Executable file
View File

@ -0,0 +1,23 @@
#include "../client.h"
void command_distance(Client *c, const Seperator *sep)
{
if (c->GetTarget()) {
Mob *target = c->GetTarget();
if (c != target) {
c->Message(
Chat::White,
fmt::format(
"{} ({}) is {:.2f} units from you.",
target->GetCleanName(),
target->GetID(),
Distance(
c->GetPosition(),
target->GetPosition()
)
).c_str()
);
}
}
}

20
zone/gm_commands/doanim.cpp Executable file
View File

@ -0,0 +1,20 @@
#include "../client.h"
void command_doanim(Client *c, const Seperator *sep)
{
if (!sep->IsNumber(1)) {
c->Message(Chat::White, "Usage: #DoAnim [number]");
}
else if (c->Admin() >= commandDoAnimOthers) {
if (c->GetTarget() == 0) {
c->Message(Chat::White, "Error: You need a target.");
}
else {
c->GetTarget()->DoAnim(atoi(sep->arg[1]), atoi(sep->arg[2]));
}
}
else {
c->DoAnim(atoi(sep->arg[1]), atoi(sep->arg[2]));
}
}

9
zone/gm_commands/door.cpp Executable file
View File

@ -0,0 +1,9 @@
#include "../client.h"
#include "door_manipulation.h"
#include "../doors.h"
void command_door(Client *c, const Seperator *sep)
{
DoorManipulation::CommandHandler(c, sep);
}

View File

@ -37,7 +37,10 @@ void DoorManipulation::CommandHandler(Client *c, const Seperator *sep)
// option
if (arg1.empty()) {
DoorManipulation::CommandHeader(c);
c->Message(Chat::White, "#door create <modelname> | Creates a door from a model. (Example IT78 creates a campfire)");
c->Message(
Chat::White,
"#door create <modelname> | Creates a door from a model. (Example IT78 creates a campfire)"
);
c->Message(Chat::White, "#door setinvertstate [0|1] | Sets selected door invert state");
c->Message(Chat::White, "#door setincline <incline> | Sets selected door incline");
c->Message(Chat::White, "#door opentype <opentype> | Sets selected door opentype");
@ -129,7 +132,7 @@ void DoorManipulation::CommandHandler(Client *c, const Seperator *sep)
std::vector<std::string> move_h_options_negative;
std::vector<std::string> set_size_options_positive;
std::vector<std::string> set_size_options_negative;
for (const auto &move_option : move_options) {
for (const auto &move_option : move_options) {
if (move_option == move_x_action) {
move_x_options_positive.emplace_back(
EQ::SayLinkEngine::GenerateQuestSaylink(
@ -297,10 +300,10 @@ void DoorManipulation::CommandHandler(Client *c, const Seperator *sep)
// we're passing a move action here
if (!arg3.empty() && StringIsNumber(arg3)) {
float x_move = 0.0f;
float y_move = 0.0f;
float z_move = 0.0f;
float h_move = 0.0f;
float x_move = 0.0f;
float y_move = 0.0f;
float z_move = 0.0f;
float h_move = 0.0f;
float set_size = 0.0f;
if (arg2 == move_x_action) {

87
zone/gm_commands/dye.cpp Executable file
View File

@ -0,0 +1,87 @@
#include "../client.h"
void command_dye(Client *c, const Seperator *sep)
{
int arguments = sep->argnum;
if (arguments == 0) {
c->Message(Chat::White, "Command Syntax: #dye help | #dye [slot] [red] [green] [blue] [use_tint]");
return;
}
uint8 slot = 0;
uint8 red = 255;
uint8 green = 255;
uint8 blue = 255;
uint8 use_tint = 255;
std::vector<std::string> dye_slots = {
"Helmet",
"Chest",
"Arms",
"Wrist",
"Hands",
"Legs",
"Feet"
};
if (arguments == 1 && !strcasecmp(sep->arg[1], "help")) {
int slot_id = 0;
std::vector<std::string> slot_messages;
c->Message(Chat::White, "Command Syntax: #dye help | #dye [slot] [red] [green] [blue] [use_tint]");
c->Message(Chat::White, "Red, Green, and Blue go from 0 to 255.");
for (const auto &slot : dye_slots) {
slot_messages.push_back(fmt::format("({}) {}", slot_id, slot));
slot_id++;
}
c->Message(
Chat::White,
fmt::format(
"{} {}",
"Slots are as follows:",
implode(", ", slot_messages)
).c_str()
);
return;
}
if (arguments >= 1 && sep->IsNumber(1)) {
slot = atoi(sep->arg[1]);
}
if (arguments >= 2 && sep->IsNumber(2)) {
red = atoi(sep->arg[2]);
}
if (arguments >= 3 && sep->IsNumber(3)) {
green = atoi(sep->arg[3]);
}
if (arguments >= 4 && sep->IsNumber(4)) {
blue = atoi(sep->arg[4]);
}
if (arguments >= 5 && sep->IsNumber(5)) {
use_tint = atoi(sep->arg[5]);
}
if (RuleB(Command, DyeCommandRequiresDyes)) {
uint32 dye_item_id = 32557;
if (c->CountItem(dye_item_id) >= 1) {
c->RemoveItem(dye_item_id);
}
else {
EQ::SayLinkEngine linker;
linker.SetLinkType(EQ::saylink::SayLinkItemData);
const EQ::ItemData *dye_item = database.GetItem(dye_item_id);
linker.SetItemData(dye_item);
c->Message(Chat::White, fmt::format("This command requires a {} to use.", linker.GenerateLink()).c_str());
return;
}
}
c->DyeArmorBySlot(slot, red, green, blue, use_tint);
}

244
zone/gm_commands/dz.cpp Executable file
View File

@ -0,0 +1,244 @@
#include "../client.h"
#include "../expedition.h"
void command_dz(Client *c, const Seperator *sep)
{
if (!c || !zone) {
return;
}
if (strcasecmp(sep->arg[1], "cache") == 0) {
if (strcasecmp(sep->arg[2], "reload") == 0) {
DynamicZone::CacheAllFromDatabase();
Expedition::CacheAllFromDatabase();
c->Message(
Chat::White, fmt::format(
"Reloaded [{}] dynamic zone(s) and [{}] expedition(s) from database",
zone->dynamic_zone_cache.size(), zone->expedition_cache.size()
).c_str());
}
}
else if (strcasecmp(sep->arg[1], "expedition") == 0) {
if (strcasecmp(sep->arg[2], "list") == 0) {
std::vector<Expedition *> expeditions;
for (const auto &expedition : zone->expedition_cache) {
expeditions.emplace_back(expedition.second.get());
}
std::sort(
expeditions.begin(), expeditions.end(),
[](const Expedition *lhs, const Expedition *rhs) {
return lhs->GetID() < rhs->GetID();
}
);
c->Message(Chat::White, fmt::format("Total Active Expeditions: [{}]", expeditions.size()).c_str());
for (const auto &expedition : expeditions) {
auto dz = expedition->GetDynamicZone();
if (!dz) {
LogExpeditions("Expedition [{}] has an invalid dz [{}] in cache",
expedition->GetID(),
expedition->GetDynamicZoneID());
continue;
}
auto leader_saylink = EQ::SayLinkEngine::GenerateQuestSaylink(
fmt::format(
"#goto {}", expedition->GetLeaderName()), false, expedition->GetLeaderName());
auto zone_saylink = EQ::SayLinkEngine::GenerateQuestSaylink(
fmt::format(
"#zoneinstance {}", dz->GetInstanceID()), false, "zone"
);
auto seconds = dz->GetSecondsRemaining();
c->Message(
Chat::White, fmt::format(
"expedition id: [{}] dz id: [{}] name: [{}] leader: [{}] {}: [{}]:[{}]:[{}]:[{}] members: [{}] remaining: [{:02}:{:02}:{:02}]",
expedition->GetID(),
expedition->GetDynamicZoneID(),
expedition->GetName(),
leader_saylink,
zone_saylink,
ZoneName(dz->GetZoneID()),
dz->GetZoneID(),
dz->GetInstanceID(),
dz->GetZoneVersion(),
dz->GetMemberCount(),
seconds / 3600, // hours
(seconds / 60) % 60, // minutes
seconds % 60 // seconds
).c_str());
}
}
else if (strcasecmp(sep->arg[2], "reload") == 0) {
Expedition::CacheAllFromDatabase();
c->Message(
Chat::White, fmt::format(
"Reloaded [{}] expeditions to cache from database.", zone->expedition_cache.size()
).c_str());
}
else if (strcasecmp(sep->arg[2], "destroy") == 0 && sep->IsNumber(3)) {
auto expedition_id = std::strtoul(sep->arg[3], nullptr, 10);
auto expedition = Expedition::FindCachedExpeditionByID(expedition_id);
if (expedition) {
c->Message(
Chat::White, fmt::format(
"Destroying expedition [{}] ({})",
expedition_id, expedition->GetName()).c_str());
expedition->GetDynamicZone()->RemoveAllMembers();
}
else {
c->Message(Chat::Red, fmt::format("Failed to destroy expedition [{}]", sep->arg[3]).c_str());
}
}
else if (strcasecmp(sep->arg[2], "unlock") == 0 && sep->IsNumber(3)) {
auto expedition_id = std::strtoul(sep->arg[3], nullptr, 10);
auto expedition = Expedition::FindCachedExpeditionByID(expedition_id);
if (expedition) {
c->Message(Chat::White, fmt::format("Unlocking expedition [{}]", expedition_id).c_str());
expedition->SetLocked(false, ExpeditionLockMessage::None, true);
}
else {
c->Message(Chat::Red, fmt::format("Failed to find expedition [{}]", sep->arg[3]).c_str());
}
}
}
else if (strcasecmp(sep->arg[1], "list") == 0) {
c->Message(
Chat::White,
fmt::format("Total Dynamic Zones (cache): [{}]", zone->dynamic_zone_cache.size()).c_str());
std::vector<DynamicZone *> dynamic_zones;
for (const auto &dz : zone->dynamic_zone_cache) {
dynamic_zones.emplace_back(dz.second.get());
}
std::sort(
dynamic_zones.begin(), dynamic_zones.end(),
[](const DynamicZone *lhs, const DynamicZone *rhs) {
return lhs->GetID() < rhs->GetID();
}
);
for (const auto &dz : dynamic_zones) {
auto seconds = dz->GetSecondsRemaining();
auto zone_saylink = EQ::SayLinkEngine::GenerateQuestSaylink(
fmt::format("#zoneinstance {}", dz->GetInstanceID()), false, "zone"
);
std::string aligned_type = fmt::format(
"[{}]",
DynamicZone::GetDynamicZoneTypeName(static_cast<DynamicZoneType>(dz->GetType())));
c->Message(
Chat::White, fmt::format(
"id: [{}] type: {:>10} {}: [{}]:[{}]:[{}] members: [{}] remaining: [{:02}:{:02}:{:02}]",
dz->GetID(),
aligned_type,
zone_saylink,
dz->GetZoneID(),
dz->GetInstanceID(),
dz->GetZoneVersion(),
dz->GetMemberCount(),
seconds / 3600, // hours
(seconds / 60) % 60, // minutes
seconds % 60 // seconds
).c_str());
}
}
else if (strcasecmp(sep->arg[1], "listdb") == 0) {
auto dz_list = DynamicZonesRepository::AllDzInstancePlayerCounts(database);
c->Message(Chat::White, fmt::format("Total Dynamic Zones (database): [{}]", dz_list.size()).c_str());
auto now = std::chrono::system_clock::now();
for (const auto &dz : dz_list) {
auto expire_time = std::chrono::system_clock::from_time_t(dz.start_time + dz.duration);
auto remaining = std::chrono::duration_cast<std::chrono::seconds>(expire_time - now);
auto seconds = std::max(0, static_cast<int>(remaining.count()));
bool is_expired = now > expire_time;
if (!is_expired || strcasecmp(sep->arg[2], "all") == 0) {
auto zone_saylink = is_expired ? "zone" : EQ::SayLinkEngine::GenerateQuestSaylink(
fmt::format("#zoneinstance {}", dz.instance), false, "zone"
);
c->Message(
Chat::White, fmt::format(
"id: [{}] type: [{}] {}: [{}]:[{}]:[{}] members: [{}] remaining: [{:02}:{:02}:{:02}]",
dz.id,
DynamicZone::GetDynamicZoneTypeName(static_cast<DynamicZoneType>(dz.type)),
zone_saylink,
dz.zone,
dz.instance,
dz.version,
dz.member_count,
seconds / 3600, // hours
(seconds / 60) % 60, // minutes
seconds % 60 // seconds
).c_str());
}
}
}
else if (strcasecmp(sep->arg[1], "lockouts") == 0) {
if (strcasecmp(sep->arg[2], "remove") == 0 && sep->arg[3][0] != '\0') {
if (sep->arg[5][0] == '\0') {
c->Message(
Chat::White, fmt::format(
"Removing [{}] lockouts on [{}].", sep->arg[4][0] ? sep->arg[4] : "all", sep->arg[3]
).c_str());
}
else {
c->Message(
Chat::White, fmt::format(
"Removing [{}]:[{}] lockout on [{}].", sep->arg[4], sep->arg[5], sep->arg[3]
).c_str());
}
Expedition::RemoveLockoutsByCharacterName(sep->arg[3], sep->arg[4], sep->arg[5]);
}
}
else if (strcasecmp(sep->arg[1], "makeleader") == 0 && sep->IsNumber(2) && sep->arg[3][0] != '\0') {
auto expedition_id = std::strtoul(sep->arg[2], nullptr, 10);
auto expedition = Expedition::FindCachedExpeditionByID(expedition_id);
if (expedition) {
auto char_name = FormatName(sep->arg[3]);
c->Message(
Chat::White,
fmt::format("Setting expedition [{}] leader to [{}]", expedition_id, char_name).c_str());
expedition->SendWorldMakeLeaderRequest(c->CharacterID(), char_name);
}
else {
c->Message(Chat::Red, fmt::format("Failed to find expedition [{}]", expedition_id).c_str());
}
}
else {
c->Message(Chat::White, "#dz usage:");
c->Message(
Chat::White,
"#dz cache reload - reload the current zone cache from db (also reloads expedition cache dependency)"
);
c->Message(Chat::White, "#dz expedition list - list expeditions in current zone cache");
c->Message(Chat::White, "#dz expedition reload - reload expedition zone cache from database");
c->Message(
Chat::White,
"#dz expedition destroy <expedition_id> - destroy expedition globally (must be in cache)"
);
c->Message(Chat::White, "#dz expedition unlock <expedition_id> - unlock expedition");
c->Message(Chat::White, "#dz list - list all dynamic zone instances from current zone cache");
c->Message(
Chat::White,
"#dz listdb [all] - list dynamic zone instances from database -- 'all' includes expired"
);
c->Message(Chat::White, "#dz lockouts remove <char_name> - delete all of character's expedition lockouts");
c->Message(
Chat::White,
"#dz lockouts remove <char_name> \"<expedition_name>\" - delete lockouts by expedition"
);
c->Message(
Chat::White,
"#dz lockouts remove <char_name> \"<expedition_name>\" \"<event_name>\" - delete lockout by expedition event"
);
c->Message(Chat::White, "#dz makeleader <expedition_id> <character_name> - set new expedition leader");
}
}

View File

@ -0,0 +1,13 @@
#include "../client.h"
#include "../expedition.h"
void command_dzkickplayers(Client *c, const Seperator *sep)
{
if (c) {
auto expedition = c->GetExpedition();
if (expedition) {
expedition->DzKickPlayers(c);
}
}
}

View File

@ -0,0 +1,140 @@
#include "../client.h"
void command_editmassrespawn(Client *c, const Seperator *sep)
{
if (strcasecmp(sep->arg[1], "usage") == 0) {
c->Message(Chat::White, "#editmassrespawn [exact_match: =]npc_type_name new_respawn_seconds (apply)");
return;
}
std::string search_npc_type;
if (sep->arg[1]) {
search_npc_type = sep->arg[1];
}
int change_respawn_seconds = 0;
if (sep->arg[2] && sep->IsNumber(2)) {
change_respawn_seconds = atoi(sep->arg[2]);
}
bool change_apply = false;
if (sep->arg[3] && strcasecmp(sep->arg[3], "apply") == 0) {
change_apply = true;
}
std::string search_encapsulator = "%";
if (search_npc_type[0] == '=') {
search_npc_type = search_npc_type.substr(1);
search_encapsulator = "";
}
std::string query = fmt::format(
SQL(
SELECT npc_types.id, spawn2.spawngroupID, spawn2.id, npc_types.name, spawn2.respawntime
FROM spawn2
INNER JOIN spawnentry ON spawn2.spawngroupID = spawnentry.spawngroupID
INNER JOIN npc_types ON spawnentry.npcID = npc_types.id
WHERE spawn2.zone LIKE '{}'
AND spawn2.version = '{}'
AND npc_types.name LIKE '{}{}{}'
ORDER BY npc_types.id, spawn2.spawngroupID, spawn2.id
),
zone->GetShortName(),
zone->GetInstanceVersion(),
search_encapsulator,
search_npc_type,
search_encapsulator
);
std::string status = "(Searching)";
if (change_apply) {
status = "(Applying)";
}
int results_count = 0;
auto results = content_db.QueryDatabase(query);
if (results.Success() && results.RowCount()) {
results_count = results.RowCount();
for (auto row : results) {
c->Message(
Chat::Yellow,
fmt::format(
"NPC (npcid:{}) (sgid:{}) (s2id:{}) [{}] Respawn: Current [{}] New [{}] {}",
row[0],
row[1],
row[2],
row[3],
row[4],
change_respawn_seconds,
status
).c_str()
);
}
c->Message(Chat::Yellow, "Found (%i) NPC's that match this search...", results_count);
if (change_respawn_seconds > 0) {
if (change_apply) {
results = content_db.QueryDatabase(
fmt::format(
SQL(
UPDATE spawn2
SET respawntime = '{}'
WHERE id IN(
SELECT spawn2.id
FROM spawn2
INNER JOIN spawnentry ON spawn2.spawngroupID = spawnentry.spawngroupID
INNER JOIN npc_types ON spawnentry.npcID = npc_types.id
WHERE spawn2.zone LIKE '{}'
AND spawn2.version = '{}'
AND npc_types.name LIKE '{}{}{}'
)
),
change_respawn_seconds,
zone->GetShortName(),
zone->GetInstanceVersion(),
search_encapsulator,
search_npc_type,
search_encapsulator
)
);
if (results.Success()) {
c->Message(Chat::Yellow, "Changes applied to (%i) NPC 'Spawn2' entries", results_count);
zone->Repop();
}
else {
c->Message(Chat::Yellow, "Found (0) NPC's that match this search...");
}
}
else {
std::string saylink = fmt::format(
"#editmassrespawn {}{} {} apply",
(search_encapsulator.empty() ? "=" : ""),
search_npc_type,
change_respawn_seconds
);
c->Message(
Chat::Yellow, "To apply these changes, click <%s> or type [%s]",
EQ::SayLinkEngine::GenerateQuestSaylink(saylink, false, "Apply").c_str(),
saylink.c_str()
);
}
}
}
else {
c->Message(Chat::Yellow, "Found (0) NPC's that match this search...");
}
}

45
zone/gm_commands/emote.cpp Executable file
View File

@ -0,0 +1,45 @@
#include "../client.h"
#include "../worldserver.h"
extern WorldServer worldserver;
void command_emote(Client *c, const Seperator *sep)
{
if (sep->arg[3][0] == 0) {
c->Message(Chat::White, "Usage: #emote [name | world | zone] type# message");
}
else {
if (strcasecmp(sep->arg[1], "zone") == 0) {
char *newmessage = 0;
if (strstr(sep->arg[3], "^") == 0) {
entity_list.Message(0, atoi(sep->arg[2]), sep->argplus[3]);
}
else {
for (newmessage = strtok((char *) sep->arg[3], "^");
newmessage != nullptr;
newmessage = strtok(nullptr, "^"))
entity_list.Message(0, atoi(sep->arg[2]), newmessage);
}
}
else if (!worldserver.Connected()) {
c->Message(Chat::White, "Error: World server disconnected");
}
else if (!strcasecmp(sep->arg[1], "world")) {
worldserver.SendEmoteMessage(
0,
0,
atoi(sep->arg[2]),
sep->argplus[3]
);
}
else {
worldserver.SendEmoteMessage(
sep->arg[1],
0,
atoi(sep->arg[2]),
sep->argplus[3]
);
}
}
}

View File

@ -0,0 +1,78 @@
#include "../client.h"
void command_emotesearch(Client *c, const Seperator *sep)
{
if (sep->arg[1][0] == 0) {
c->Message(Chat::White, "Usage: #emotesearch [search string or emoteid]");
}
else {
const char *search_criteria = sep->argplus[1];
int count = 0;
if (Seperator::IsNumber(search_criteria)) {
uint16 emoteid = atoi(search_criteria);
LinkedListIterator<NPC_Emote_Struct *> iterator(zone->NPCEmoteList);
iterator.Reset();
while (iterator.MoreElements()) {
NPC_Emote_Struct *nes = iterator.GetData();
if (emoteid == nes->emoteid) {
c->Message(
Chat::White,
"EmoteID: %i Event: %i Type: %i Text: %s",
nes->emoteid,
nes->event_,
nes->type,
nes->text
);
count++;
}
iterator.Advance();
}
if (count == 0) {
c->Message(Chat::White, "No emotes found.");
}
else {
c->Message(Chat::White, "%i emote(s) found", count);
}
}
else {
char sText[64];
char sCriteria[515];
strn0cpy(sCriteria, search_criteria, sizeof(sCriteria));
strupr(sCriteria);
char *pdest;
LinkedListIterator<NPC_Emote_Struct *> iterator(zone->NPCEmoteList);
iterator.Reset();
while (iterator.MoreElements()) {
NPC_Emote_Struct *nes = iterator.GetData();
strn0cpy(sText, nes->text, sizeof(sText));
strupr(sText);
pdest = strstr(sText, sCriteria);
if (pdest != nullptr) {
c->Message(
Chat::White,
"EmoteID: %i Event: %i Type: %i Text: %s",
nes->emoteid,
nes->event_,
nes->type,
nes->text
);
count++;
}
if (count == 50) {
break;
}
iterator.Advance();
}
if (count == 50) {
c->Message(Chat::White, "50 emotes shown...too many results.");
}
else {
c->Message(Chat::White, "%i emote(s) found", count);
}
}
}
}

39
zone/gm_commands/emoteview.cpp Executable file
View File

@ -0,0 +1,39 @@
#include "../client.h"
void command_emoteview(Client *c, const Seperator *sep)
{
if (!c->GetTarget() || !c->GetTarget()->IsNPC()) {
c->Message(Chat::White, "You must target a NPC to view their emotes.");
return;
}
if (c->GetTarget() && c->GetTarget()->IsNPC()) {
int count = 0;
int emoteid = c->GetTarget()->CastToNPC()->GetEmoteID();
LinkedListIterator<NPC_Emote_Struct *> iterator(zone->NPCEmoteList);
iterator.Reset();
while (iterator.MoreElements()) {
NPC_Emote_Struct *nes = iterator.GetData();
if (emoteid == nes->emoteid) {
c->Message(
Chat::White,
"EmoteID: %i Event: %i Type: %i Text: %s",
nes->emoteid,
nes->event_,
nes->type,
nes->text
);
count++;
}
iterator.Advance();
}
if (count == 0) {
c->Message(Chat::White, "No emotes found.");
}
else {
c->Message(Chat::White, "%i emote(s) found", count);
}
}
}

View File

@ -0,0 +1,29 @@
#include "../client.h"
void command_enablerecipe(Client *c, const Seperator *sep)
{
uint32 recipe_id = 0;
bool success = false;
if (c) {
if (sep->argnum == 1) {
recipe_id = atoi(sep->arg[1]);
}
else {
c->Message(Chat::White, "Invalid number of arguments.\nUsage: #enablerecipe recipe_id");
return;
}
if (recipe_id > 0) {
success = content_db.EnableRecipe(recipe_id);
if (success) {
c->Message(Chat::White, "Recipe enabled.");
}
else {
c->Message(Chat::White, "Recipe not enabled.");
}
}
else {
c->Message(Chat::White, "Invalid recipe id.\nUsage: #enablerecipe recipe_id");
}
}
}

27
zone/gm_commands/endurance.cpp Executable file
View File

@ -0,0 +1,27 @@
#include "../client.h"
void command_endurance(Client *c, const Seperator *sep)
{
auto target = c->GetTarget() ? c->GetTarget() : c;
if (target->IsClient()) {
target->CastToClient()->SetEndurance(target->CastToClient()->GetMaxEndurance());
}
else {
target->SetEndurance(target->GetMaxEndurance());
}
if (c != target) {
c->Message(
Chat::White,
fmt::format(
"Set {} ({}) to full Endurance.",
target->GetCleanName(),
target->GetID()
).c_str()
);
}
else {
c->Message(Chat::White, "Restored your Endurance to full.");
}
}

82
zone/gm_commands/equipitem.cpp Executable file
View File

@ -0,0 +1,82 @@
#include "../client.h"
void command_equipitem(Client *c, const Seperator *sep)
{
uint32 slot_id = atoi(sep->arg[1]);
if (sep->IsNumber(1) && (slot_id >= EQ::invslot::EQUIPMENT_BEGIN && slot_id <= EQ::invslot::EQUIPMENT_END)) {
const EQ::ItemInstance *from_inst = c->GetInv().GetItem(EQ::invslot::slotCursor);
const EQ::ItemInstance *to_inst = c->GetInv().GetItem(slot_id); // added (desync issue when forcing stack to stack)
bool partialmove = false;
int16 movecount;
if (from_inst && from_inst->IsClassCommon()) {
auto outapp = new EQApplicationPacket(OP_MoveItem, sizeof(MoveItem_Struct));
MoveItem_Struct *mi = (MoveItem_Struct *) outapp->pBuffer;
mi->from_slot = EQ::invslot::slotCursor;
mi->to_slot = slot_id;
// mi->number_in_stack = from_inst->GetCharges(); // replaced with con check for stacking
// crude stackable check to only 'move' the difference count on client instead of entire stack when applicable
if (to_inst && to_inst->IsStackable() &&
(to_inst->GetItem()->ID == from_inst->GetItem()->ID) &&
(to_inst->GetCharges() < to_inst->GetItem()->StackSize) &&
(from_inst->GetCharges() > to_inst->GetItem()->StackSize - to_inst->GetCharges())) {
movecount = to_inst->GetItem()->StackSize - to_inst->GetCharges();
mi->number_in_stack = (uint32) movecount;
partialmove = true;
}
else {
mi->number_in_stack = from_inst->GetCharges();
}
// Save move changes
// Added conditional check to packet send..would have sent change even on a swap failure..whoops!
if (partialmove) { // remove this con check if someone can figure out removing charges from cursor stack issue below
// mi->number_in_stack is always from_inst->GetCharges() when partialmove is false
c->Message(Chat::Red, "Error: Partial stack added to existing stack exceeds allowable stacksize");
safe_delete(outapp);
return;
}
else if (c->SwapItem(mi)) {
c->FastQueuePacket(&outapp);
// if the below code is still needed..just send an an item trade packet to each slot..it should overwrite the client instance
// below code has proper logic, but client does not like to have cursor charges changed
// (we could delete the cursor item and resend, but issues would arise if there are queued items)
//if (partialmove) {
// EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_DeleteItem, sizeof(DeleteItem_Struct));
// DeleteItem_Struct* di = (DeleteItem_Struct*)outapp2->pBuffer;
// di->from_slot = SLOT_CURSOR;
// di->to_slot = 0xFFFFFFFF;
// di->number_in_stack = 0xFFFFFFFF;
// c->Message(Chat::White, "Deleting %i charges from stack", movecount); // debug line..delete
// for (int16 deletecount=0; deletecount < movecount; deletecount++)
// have to use 'movecount' because mi->number_in_stack is 'ENCODED' at this point (i.e., 99 charges returns 22...)
// c->QueuePacket(outapp2);
// safe_delete(outapp2);
//}
}
else {
c->Message(Chat::Red, "Error: Unable to equip current item");
}
safe_delete(outapp);
// also send out a wear change packet?
}
else if (from_inst == nullptr) {
c->Message(Chat::Red, "Error: There is no item on your cursor");
}
else {
c->Message(Chat::Red, "Error: Item on your cursor cannot be equipped");
}
}
else {
c->Message(Chat::White, "Usage: #equipitem slotid[0-21] - equips the item on your cursor to the position");
}
}

37
zone/gm_commands/face.cpp Executable file
View File

@ -0,0 +1,37 @@
#include "../client.h"
void command_face(Client *c, const Seperator *sep)
{
Mob *target = c->GetTarget();
if (!sep->IsNumber(1)) {
c->Message(Chat::White, "Usage: #face [number of face]");
}
else if (!target) {
c->Message(Chat::White, "Error: this command requires a target");
}
else {
uint16 Race = target->GetRace();
uint8 Gender = target->GetGender();
uint8 Texture = 0xFF;
uint8 HelmTexture = 0xFF;
uint8 HairColor = target->GetHairColor();
uint8 BeardColor = target->GetBeardColor();
uint8 EyeColor1 = target->GetEyeColor1();
uint8 EyeColor2 = target->GetEyeColor2();
uint8 HairStyle = target->GetHairStyle();
uint8 LuclinFace = atoi(sep->arg[1]);
uint8 Beard = target->GetBeard();
uint32 DrakkinHeritage = target->GetDrakkinHeritage();
uint32 DrakkinTattoo = target->GetDrakkinTattoo();
uint32 DrakkinDetails = target->GetDrakkinDetails();
target->SendIllusionPacket(
Race, Gender, Texture, HelmTexture, HairColor, BeardColor,
EyeColor1, EyeColor2, HairStyle, LuclinFace, Beard, 0xFF,
DrakkinHeritage, DrakkinTattoo, DrakkinDetails
);
c->Message(Chat::White, "Face = %i", atoi(sep->arg[1]));
}
}

174
zone/gm_commands/faction.cpp Executable file
View File

@ -0,0 +1,174 @@
#include "../client.h"
void command_faction(Client *c, const Seperator *sep)
{
int arguments = sep->argnum;
if (!arguments) {
c->Message(
Chat::White,
"Usage: #faction review [Search Criteria | All] - Review Targeted Player's Faction Hits"
);
c->Message(
Chat::White,
"Usage: #faction reset [Faction ID] - Reset Targeted Player's Faction to Base Faction Value"
);
c->Message(Chat::White, "Usage: #faction view - Displays Target NPC's Primary Faction");
return;
}
std::string faction_filter;
if (sep->arg[2]) {
faction_filter = str_tolower(sep->arg[2]);
}
if (!strcasecmp(sep->arg[1], "review")) {
if (!(c->GetTarget() && c->GetTarget()->IsClient())) {
c->Message(Chat::Red, "Player Target Required for faction review");
return;
}
Client *target = c->GetTarget()->CastToClient();
uint32 character_id = target->CharacterID();
std::string query;
if (!strcasecmp(faction_filter.c_str(), "all")) {
query = fmt::format(
"SELECT id, `name`, current_value FROM faction_list INNER JOIN faction_values ON faction_list.id = faction_values.faction_id WHERE char_id = {}",
character_id
);
}
else {
query = fmt::format(
"SELECT id, `name`, current_value FROM faction_list INNER JOIN faction_values ON faction_list.id = faction_values.faction_id WHERE `name` like '%{}%' and char_id = {}",
faction_filter.c_str(),
character_id
);
}
auto results = content_db.QueryDatabase(query);
if (!results.Success() || !results.RowCount()) {
c->Message(Chat::Yellow, "No faction hits found. All are at base level.");
return;
}
uint32 found_count = 0;
for (auto row : results) {
uint32 faction_number = (found_count + 1);
auto faction_id = std::stoul(row[0]);
std::string faction_name = row[1];
std::string faction_value = row[2];
std::string reset_link = EQ::SayLinkEngine::GenerateQuestSaylink(
fmt::format("#faction reset {}", faction_id),
false,
"Reset"
);
c->Message(
Chat::White,
fmt::format(
"Faction {} | Name: {} ({}) Value: {} [{}]",
faction_number,
faction_name,
faction_id,
faction_value,
reset_link
).c_str()
);
found_count++;
}
auto faction_message = (
found_count > 0 ?
(
found_count == 1 ?
"A Faction was" :
fmt::format("{} Factions were", found_count)
) :
"No Factions were"
);
c->Message(
Chat::White,
fmt::format(
"{} found.",
faction_message
).c_str()
);
}
else if (!strcasecmp(sep->arg[1], "reset")) {
if (strlen(faction_filter.c_str()) > 0) {
if (c->GetTarget() && c->GetTarget()->IsClient()) {
Client *target = c->GetTarget()->CastToClient();
if (
(
!c->GetFeigned() &&
c->GetAggroCount() == 0
) ||
(
!target->GetFeigned() &&
target->GetAggroCount() == 0
)
) {
uint32 character_id = target->CharacterID();
uint32 faction_id = std::stoul(faction_filter.c_str());
if (target->ReloadCharacterFaction(target, faction_id, character_id)) {
c->Message(
Chat::White,
fmt::format(
"Faction Reset | {} ({}) was reset for {}.",
content_db.GetFactionName(faction_id),
faction_id,
target->GetCleanName()
).c_str()
);
}
else {
c->Message(
Chat::White,
fmt::format(
"Faction Reset Failed | {} ({}) was unable to be reset for {}.",
content_db.GetFactionName(faction_id),
faction_id,
target->GetCleanName()
).c_str()
);
}
}
else {
c->Message(
Chat::White,
"You cannot reset factions while you or your target is in combat or feigned."
);
return;
}
}
else {
c->Message(Chat::White, "You must target a PC for this command.");
return;
}
}
else {
c->Message(
Chat::White,
"Usage: #faction reset [Faction ID] - Reset Targeted Player's Faction to Base Faction Value"
);
}
}
else if (!strcasecmp(sep->arg[1], "view")) {
if (c->GetTarget() && c->GetTarget()->IsNPC()) {
Mob *target = c->GetTarget();
uint32 npc_id = target->GetNPCTypeID();
uint32 npc_faction_id = target->CastToNPC()->GetPrimaryFaction();
std::string npc_name = target->GetCleanName();
c->Message(
Chat::White,
fmt::format(
"{} ({}) has a Primary Faction of {} ({}).",
npc_name,
npc_id,
content_db.GetFactionName(npc_faction_id),
npc_faction_id
).c_str()
);
}
}
}

84
zone/gm_commands/findclass.cpp Executable file
View File

@ -0,0 +1,84 @@
#include "../client.h"
void command_findclass(Client *c, const Seperator *sep)
{
int arguments = sep->argnum;
if (arguments == 0) {
c->Message(Chat::White, "Command Syntax: #findclass [search criteria]");
return;
}
if (sep->IsNumber(1)) {
int class_id = std::stoi(sep->arg[1]);
if (class_id >= WARRIOR && class_id <= MERCERNARY_MASTER) {
std::string class_name = GetClassIDName(class_id);
c->Message(
Chat::White,
fmt::format(
"Class {}: {}",
class_id,
class_name
).c_str()
);
}
else {
c->Message(
Chat::White,
fmt::format(
"Class ID {} was not found.",
class_id
).c_str()
);
}
}
else {
std::string search_criteria = str_tolower(sep->argplus[1]);
int found_count = 0;
for (int class_id = WARRIOR; class_id <= MERCERNARY_MASTER; class_id++) {
std::string class_name = GetClassIDName(class_id);
std::string class_name_lower = str_tolower(class_name);
if (search_criteria.length() > 0 && class_name_lower.find(search_criteria) == std::string::npos) {
continue;
}
c->Message(
Chat::White,
fmt::format(
"Class {}: {}",
class_id,
class_name
).c_str()
);
found_count++;
if (found_count == 20) {
break;
}
}
if (found_count == 20) {
c->Message(Chat::White, "20 Classes found... max reached.");
}
else {
auto class_message = (
found_count > 0 ?
(
found_count == 1 ?
"A Class was" :
fmt::format("{} Classes were", found_count)
) :
"No Classes were"
);
c->Message(
Chat::White,
fmt::format(
"{} found.",
class_message
).c_str()
);
}
}
}

View File

@ -0,0 +1,89 @@
#include "../client.h"
void command_findfaction(Client *c, const Seperator *sep)
{
int arguments = sep->argnum;
if (arguments == 0) {
c->Message(Chat::White, "Command Syntax: #findfaction [search criteria]");
return;
}
if (sep->IsNumber(1)) {
int faction_id = std::stoi(sep->arg[1]);
auto faction_name = content_db.GetFactionName(faction_id);
if (!faction_name.empty()) {
c->Message(
Chat::White,
fmt::format(
"Faction {}: {}",
faction_id,
faction_name
).c_str()
);
}
else {
c->Message(
Chat::White,
fmt::format(
"Faction ID {} was not found.",
faction_id
).c_str()
);
}
}
else {
std::string search_criteria = str_tolower(sep->argplus[1]);
int found_count = 0;
int max_faction_id = content_db.GetMaxFaction();
for (int faction_id = 0; faction_id < max_faction_id; faction_id++) {
std::string faction_name = content_db.GetFactionName(faction_id);
std::string faction_name_lower = str_tolower(faction_name);
if (faction_name.empty()) {
continue;
}
if (faction_name.find(search_criteria) == std::string::npos) {
continue;
}
c->Message(
Chat::White,
fmt::format(
"Faction {}: {}",
faction_id,
faction_name
).c_str()
);
found_count++;
if (found_count == 20) {
break;
}
}
if (found_count == 20) {
c->Message(Chat::White, "20 Factions found... max reached.");
}
else {
auto faction_message = (
found_count > 0 ?
(
found_count == 1 ?
"A Faction was" :
fmt::format("{} Factions were", found_count)
) :
"No Factions were"
);
c->Message(
Chat::White,
fmt::format(
"{} found.",
faction_message
).c_str()
);
}
}
}

View File

@ -0,0 +1,77 @@
#include "../client.h"
void command_findnpctype(Client *c, const Seperator *sep)
{
int arguments = sep->argnum;
if (!arguments) {
c->Message(Chat::White, "Usage: #findnpctype [Search Criteria]");
return;
}
std::string query;
std::string search_criteria = sep->arg[1];
if (sep->IsNumber(1)) {
query = fmt::format(
"SELECT id, name FROM npc_types WHERE id = {}",
search_criteria
);
}
else {
query = fmt::format(
"SELECT id, name FROM npc_types WHERE name LIKE '%%{}%%'",
search_criteria
);
}
auto results = content_db.QueryDatabase(query);
if (!results.Success() || !results.RowCount()) {
c->Message(
Chat::White,
fmt::format(
"No matches found for '{}'.",
search_criteria
).c_str()
);
return;
}
int found_count = 0;
for (auto row : results) {
int found_number = (found_count + 1);
if (found_count == 20) {
break;
}
c->Message(
Chat::White,
fmt::format(
"NPC {} | {} ({})",
found_number,
row[1],
row[0]
).c_str()
);
found_count++;
}
if (found_count == 20) {
c->Message(Chat::White, "20 NPCs were found, max reached.");
}
else {
auto npc_message = (
found_count == 1 ?
"An NPC was" :
fmt::format("{} NPCs were", found_count)
);
c->Message(
Chat::White,
fmt::format(
"{} found.",
npc_message
).c_str()
);
}
}

84
zone/gm_commands/findrace.cpp Executable file
View File

@ -0,0 +1,84 @@
#include "../client.h"
void command_findrace(Client *c, const Seperator *sep)
{
int arguments = sep->argnum;
if (arguments == 0) {
c->Message(Chat::White, "Command Syntax: #findrace [search criteria]");
return;
}
if (sep->IsNumber(1)) {
int race_id = std::stoi(sep->arg[1]);
std::string race_name = GetRaceIDName(race_id);
if (race_id >= RACE_HUMAN_1 && race_id <= RACE_PEGASUS_732) {
c->Message(
Chat::White,
fmt::format(
"Race {}: {}",
race_id,
race_name
).c_str()
);
}
else {
c->Message(
Chat::White,
fmt::format(
"Race ID {} was not found.",
race_id
).c_str()
);
}
}
else {
std::string search_criteria = str_tolower(sep->argplus[1]);
int found_count = 0;
for (int race_id = RACE_HUMAN_1; race_id <= RACE_PEGASUS_732; race_id++) {
std::string race_name = GetRaceIDName(race_id);
std::string race_name_lower = str_tolower(race_name);
if (search_criteria.length() > 0 && race_name_lower.find(search_criteria) == std::string::npos) {
continue;
}
c->Message(
Chat::White,
fmt::format(
"Race {}: {}",
race_id,
race_name
).c_str()
);
found_count++;
if (found_count == 20) {
break;
}
}
if (found_count == 20) {
c->Message(Chat::White, "20 Races found... max reached.");
}
else {
auto race_message = (
found_count > 0 ?
(
found_count == 1 ?
"A Race was" :
fmt::format("{} Races were", found_count)
) :
"No Races were"
);
c->Message(
Chat::White,
fmt::format(
"{} found.",
race_message
).c_str()
);
}
}
}

90
zone/gm_commands/findskill.cpp Executable file
View File

@ -0,0 +1,90 @@
#include "../client.h"
void command_findskill(Client *c, const Seperator *sep)
{
int arguments = sep->argnum;
if (arguments == 0) {
c->Message(Chat::White, "Command Syntax: #findskill [search criteria]");
return;
}
std::map<EQ::skills::SkillType, std::string> skills = EQ::skills::GetSkillTypeMap();
if (sep->IsNumber(1)) {
int skill_id = std::stoi(sep->arg[1]);
if (skill_id >= EQ::skills::Skill1HBlunt && skill_id < EQ::skills::SkillCount) {
for (auto skill : skills) {
if (skill_id == skill.first) {
c->Message(
Chat::White,
fmt::format(
"Skill {}: {}",
skill.first,
skill.second
).c_str()
);
break;
}
}
}
else {
c->Message(
Chat::White,
fmt::format(
"Skill ID {} was not found.",
skill_id
).c_str()
);
}
}
else {
std::string search_criteria = str_tolower(sep->argplus[1]);
if (!search_criteria.empty()) {
int found_count = 0;
for (auto skill : skills) {
std::string skill_name_lower = str_tolower(skill.second);
if (skill_name_lower.find(search_criteria) == std::string::npos) {
continue;
}
c->Message(
Chat::White,
fmt::format(
"Skill {}: {}",
skill.first,
skill.second
).c_str()
);
found_count++;
if (found_count == 20) {
break;
}
}
if (found_count == 20) {
c->Message(Chat::White, "20 Skills were found, max reached.");
}
else {
auto skill_message = (
found_count > 0 ?
(
found_count == 1 ?
"A Skill was" :
fmt::format("{} Skills were", found_count)
) :
"No Skills were"
);
c->Message(
Chat::White,
fmt::format(
"{} found.",
skill_message
).c_str()
);
}
}
}
}

129
zone/gm_commands/findspell.cpp Executable file
View File

@ -0,0 +1,129 @@
#include "../client.h"
void command_findspell(Client *c, const Seperator *sep)
{
if (SPDAT_RECORDS <= 0) {
c->Message(Chat::White, "Spells not loaded");
return;
}
int arguments = sep->argnum;
if (arguments == 0) {
c->Message(Chat::White, "Command Syntax: #findspell [search criteria]");
return;
}
if (sep->IsNumber(1)) {
int spell_id = std::stoi(sep->arg[1]);
if (!IsValidSpell(spell_id)) {
c->Message(
Chat::White,
fmt::format(
"Spell ID {} was not found.",
spell_id
).c_str()
);
}
else {
c->Message(
Chat::White,
fmt::format(
"Spell {}: {}",
spell_id,
spells[spell_id].name
).c_str()
);
}
}
else {
std::string search_criteria = str_tolower(sep->argplus[1]);
int found_count = 0;
for (int spell_id = 0; spell_id < SPDAT_RECORDS; spell_id++) {
auto current_spell = spells[spell_id];
if (current_spell.name[0] != 0) {
std::string spell_name = current_spell.name;
std::string spell_name_lower = str_tolower(spell_name);
if (search_criteria.length() > 0 && spell_name_lower.find(search_criteria) == std::string::npos) {
continue;
}
c->Message(
Chat::White,
fmt::format(
"Spell {}: {}",
spell_id,
spell_name
).c_str()
);
found_count++;
if (found_count == 20) {
break;
}
}
}
if (found_count == 20) {
c->Message(Chat::White, "20 Spells found... max reached.");
}
else {
auto spell_message = (
found_count > 0 ?
(
found_count == 1 ?
"A Spell was" :
fmt::format("{} Spells were", found_count)
) :
"No Spells were"
);
c->Message(
Chat::White,
fmt::format(
"{} found.",
spell_message
).c_str()
);
}
}
}
inline bool CastRestrictedSpell(int spellid)
{
switch (spellid) {
case SPELL_TOUCH_OF_VINITRAS:
case SPELL_DESPERATE_HOPE:
case SPELL_CHARM:
case SPELL_METAMORPHOSIS65:
case SPELL_JT_BUFF:
case SPELL_CAN_O_WHOOP_ASS:
case SPELL_PHOENIX_CHARM:
case SPELL_CAZIC_TOUCH:
case SPELL_AVATAR_KNOCKBACK:
case SPELL_SHAPECHANGE65:
case SPELL_SUNSET_HOME1218:
case SPELL_SUNSET_HOME819:
case SPELL_SHAPECHANGE75:
case SPELL_SHAPECHANGE80:
case SPELL_SHAPECHANGE85:
case SPELL_SHAPECHANGE90:
case SPELL_SHAPECHANGE95:
case SPELL_SHAPECHANGE100:
case SPELL_SHAPECHANGE25:
case SPELL_SHAPECHANGE30:
case SPELL_SHAPECHANGE35:
case SPELL_SHAPECHANGE40:
case SPELL_SHAPECHANGE45:
case SPELL_SHAPECHANGE50:
case SPELL_NPC_AEGOLISM:
case SPELL_SHAPECHANGE55:
case SPELL_SHAPECHANGE60:
case SPELL_COMMAND_OF_DRUZZIL:
case SPELL_SHAPECHANGE70:
return true;
default:
return false;
}
}

89
zone/gm_commands/findtask.cpp Executable file
View File

@ -0,0 +1,89 @@
#include "../client.h"
void command_findtask(Client *c, const Seperator *sep)
{
if (RuleB(TaskSystem, EnableTaskSystem)) {
int arguments = sep->argnum;
if (arguments == 0) {
c->Message(Chat::White, "Command Syntax: #findtask [search criteria]");
return;
}
if (sep->IsNumber(1)) {
auto task_id = std::stoul(sep->arg[1]);
auto task_name = task_manager->GetTaskName(task_id);
auto task_message = (
!task_name.empty() ?
fmt::format(
"Task {}: {}",
task_id,
task_name
).c_str() :
fmt::format(
"Task ID {} was not found.",
task_id
).c_str()
);
c->Message(
Chat::White,
task_message
);
}
else {
std::string search_criteria = str_tolower(sep->argplus[1]);
if (!search_criteria.empty()) {
int found_count = 0;
for (uint32 task_id = 1; task_id <= MAXTASKS; task_id++) {
auto task_name = task_manager->GetTaskName(task_id);
std::string task_name_lower = str_tolower(task_name);
if (task_name_lower.find(search_criteria) == std::string::npos) {
continue;
}
c->Message(
Chat::White,
fmt::format(
"Task {}: {}",
task_id,
task_name
).c_str()
);
found_count++;
if (found_count == 20) {
break;
}
}
if (found_count == 20) {
c->Message(Chat::White, "20 Tasks were found, max reached.");
}
else {
auto task_message = (
found_count > 0 ?
(
found_count == 1 ?
"A Task was" :
fmt::format("{} Tasks were", found_count)
) :
"No Tasks were"
);
c->Message(
Chat::White,
fmt::format(
"{} found.",
task_message
).c_str()
);
}
}
}
}
else {
c->Message(Chat::White, "This command cannot be used while the Task system is disabled.");
}
}

95
zone/gm_commands/findzone.cpp Executable file
View File

@ -0,0 +1,95 @@
#include "../client.h"
void command_findzone(Client *c, const Seperator *sep)
{
if (sep->arg[1][0] == 0) {
c->Message(Chat::White, "Usage: #findzone [search criteria]");
c->Message(Chat::White, "Usage: #findzone expansion [expansion number]");
return;
}
std::string query;
int id = atoi((const char *) sep->arg[1]);
std::string arg1 = sep->arg[1];
if (arg1 == "expansion") {
query = fmt::format(
"SELECT zoneidnumber, short_name, long_name, version FROM zone WHERE expansion = {}",
sep->arg[2]
);
}
else {
/**
* If id evaluates to 0, then search as if user entered a string
*/
if (id == 0) {
query = fmt::format(
"SELECT zoneidnumber, short_name, long_name, version FROM zone WHERE long_name LIKE '%{}%' OR `short_name` LIKE '%{}%'",
EscapeString(sep->arg[1]),
EscapeString(sep->arg[1])
);
}
else {
query = fmt::format(
"SELECT zoneidnumber, short_name, long_name, version FROM zone WHERE zoneidnumber = {}",
id
);
}
}
auto results = content_db.QueryDatabase(query);
if (!results.Success()) {
c->Message(Chat::White, "Error querying database.");
c->Message(Chat::White, query.c_str());
return;
}
int count = 0;
const int maxrows = 100;
for (auto row = results.begin(); row != results.end(); ++row) {
std::string zone_id = row[0];
std::string short_name = row[1];
std::string long_name = row[2];
int version = atoi(row[3]);
if (++count > maxrows) {
c->Message(Chat::White, "%i zones shown. Too many results.", maxrows);
break;
}
std::string command_zone = EQ::SayLinkEngine::GenerateQuestSaylink("#zone " + short_name, false, "zone");
std::string command_gmzone = EQ::SayLinkEngine::GenerateQuestSaylink(
fmt::format("#gmzone {} {}", short_name, version),
false,
"gmzone"
);
c->Message(
Chat::White,
fmt::format(
"[{}] [{}] [{}] ID ({}) Version ({}) [{}]",
(version == 0 ? command_zone : "zone"),
command_gmzone,
short_name,
zone_id,
version,
long_name
).c_str()
);
}
if (count <= maxrows) {
c->Message(
Chat::White,
"Query complete. %i rows shown. %s",
count,
(arg1 == "expansion" ? "(expansion search)" : ""));
}
else if (count == 0) {
c->Message(Chat::White, "No matches found for %s.", sep->arg[1]);
}
}

250
zone/gm_commands/fixmob.cpp Executable file
View File

@ -0,0 +1,250 @@
#include "../client.h"
void command_fixmob(Client *c, const Seperator *sep)
{
Mob *target = c->GetTarget();
const char *Usage = "Usage: #fixmob [race|gender|texture|helm|face|hair|haircolor|beard|beardcolor|heritage|tattoo|detail] [next|prev]";
if (!sep->arg[1]) {
c->Message(Chat::White, Usage);
}
else if (!target) {
c->Message(Chat::White, "Error: this command requires a target");
}
else {
uint32 Adjustment = 1; // Previous or Next
char codeMove = 0;
if (sep->arg[2]) {
char *command2 = sep->arg[2];
codeMove = (command2[0] | 0x20); // First character, lower-cased
if (codeMove == 'n') {
Adjustment = 1;
}
else if (codeMove == 'p') {
Adjustment = -1;
}
}
uint16 Race = target->GetRace();
uint8 Gender = target->GetGender();
uint8 Texture = 0xFF;
uint8 HelmTexture = 0xFF;
uint8 HairColor = target->GetHairColor();
uint8 BeardColor = target->GetBeardColor();
uint8 EyeColor1 = target->GetEyeColor1();
uint8 EyeColor2 = target->GetEyeColor2();
uint8 HairStyle = target->GetHairStyle();
uint8 LuclinFace = target->GetLuclinFace();
uint8 Beard = target->GetBeard();
uint32 DrakkinHeritage = target->GetDrakkinHeritage();
uint32 DrakkinTattoo = target->GetDrakkinTattoo();
uint32 DrakkinDetails = target->GetDrakkinDetails();
const char *ChangeType = nullptr; // If it's still nullptr after processing, they didn't send a valid command
uint32 ChangeSetting;
char *command = sep->arg[1];
if (strcasecmp(command, "race") == 0) {
if (Race == 1 && codeMove == 'p') {
Race = RuleI(NPC, MaxRaceID);
}
else if (Race >= RuleI(NPC, MaxRaceID) && codeMove != 'p') {
Race = 1;
}
else {
Race += Adjustment;
}
ChangeType = "Race";
ChangeSetting = Race;
}
else if (strcasecmp(command, "gender") == 0) {
if (Gender == 0 && codeMove == 'p') {
Gender = 2;
}
else if (Gender >= 2 && codeMove != 'p') {
Gender = 0;
}
else {
Gender += Adjustment;
}
ChangeType = "Gender";
ChangeSetting = Gender;
}
else if (strcasecmp(command, "texture") == 0) {
Texture = target->GetTexture();
if (Texture == 0 && codeMove == 'p') {
Texture = 25;
}
else if (Texture >= 25 && codeMove != 'p') {
Texture = 0;
}
else {
Texture += Adjustment;
}
ChangeType = "Texture";
ChangeSetting = Texture;
}
else if (strcasecmp(command, "helm") == 0) {
HelmTexture = target->GetHelmTexture();
if (HelmTexture == 0 && codeMove == 'p') {
HelmTexture = 25;
}
else if (HelmTexture >= 25 && codeMove != 'p') {
HelmTexture = 0;
}
else {
HelmTexture += Adjustment;
}
ChangeType = "HelmTexture";
ChangeSetting = HelmTexture;
}
else if (strcasecmp(command, "face") == 0) {
if (LuclinFace == 0 && codeMove == 'p') {
LuclinFace = 87;
}
else if (LuclinFace >= 87 && codeMove != 'p') {
LuclinFace = 0;
}
else {
LuclinFace += Adjustment;
}
ChangeType = "LuclinFace";
ChangeSetting = LuclinFace;
}
else if (strcasecmp(command, "hair") == 0) {
if (HairStyle == 0 && codeMove == 'p') {
HairStyle = 8;
}
else if (HairStyle >= 8 && codeMove != 'p') {
HairStyle = 0;
}
else {
HairStyle += Adjustment;
}
ChangeType = "HairStyle";
ChangeSetting = HairStyle;
}
else if (strcasecmp(command, "haircolor") == 0) {
if (HairColor == 0 && codeMove == 'p') {
HairColor = 24;
}
else if (HairColor >= 24 && codeMove != 'p') {
HairColor = 0;
}
else {
HairColor += Adjustment;
}
ChangeType = "HairColor";
ChangeSetting = HairColor;
}
else if (strcasecmp(command, "beard") == 0) {
if (Beard == 0 && codeMove == 'p') {
Beard = 11;
}
else if (Beard >= 11 && codeMove != 'p') {
Beard = 0;
}
else {
Beard += Adjustment;
}
ChangeType = "Beard";
ChangeSetting = Beard;
}
else if (strcasecmp(command, "beardcolor") == 0) {
if (BeardColor == 0 && codeMove == 'p') {
BeardColor = 24;
}
else if (BeardColor >= 24 && codeMove != 'p') {
BeardColor = 0;
}
else {
BeardColor += Adjustment;
}
ChangeType = "BeardColor";
ChangeSetting = BeardColor;
}
else if (strcasecmp(command, "heritage") == 0) {
if (DrakkinHeritage == 0 && codeMove == 'p') {
DrakkinHeritage = 6;
}
else if (DrakkinHeritage >= 6 && codeMove != 'p') {
DrakkinHeritage = 0;
}
else {
DrakkinHeritage += Adjustment;
}
ChangeType = "DrakkinHeritage";
ChangeSetting = DrakkinHeritage;
}
else if (strcasecmp(command, "tattoo") == 0) {
if (DrakkinTattoo == 0 && codeMove == 'p') {
DrakkinTattoo = 8;
}
else if (DrakkinTattoo >= 8 && codeMove != 'p') {
DrakkinTattoo = 0;
}
else {
DrakkinTattoo += Adjustment;
}
ChangeType = "DrakkinTattoo";
ChangeSetting = DrakkinTattoo;
}
else if (strcasecmp(command, "detail") == 0) {
if (DrakkinDetails == 0 && codeMove == 'p') {
DrakkinDetails = 7;
}
else if (DrakkinDetails >= 7 && codeMove != 'p') {
DrakkinDetails = 0;
}
else {
DrakkinDetails += Adjustment;
}
ChangeType = "DrakkinDetails";
ChangeSetting = DrakkinDetails;
}
// Hack to fix some races that base features from face
switch (Race) {
case 2: // Barbarian
if (LuclinFace > 10) {
LuclinFace -= ((DrakkinTattoo - 1) * 10);
}
LuclinFace += (DrakkinTattoo * 10);
break;
case 3: // Erudite
if (LuclinFace > 10) {
LuclinFace -= ((HairStyle - 1) * 10);
}
LuclinFace += (HairStyle * 10);
break;
case 5: // HighElf
case 6: // DarkElf
case 7: // HalfElf
if (LuclinFace > 10) {
LuclinFace -= ((Beard - 1) * 10);
}
LuclinFace += (Beard * 10);
break;
default:
break;
}
if (ChangeType == nullptr) {
c->Message(Chat::White, Usage);
}
else {
target->SendIllusionPacket(
Race, Gender, Texture, HelmTexture, HairColor, BeardColor,
EyeColor1, EyeColor2, HairStyle, LuclinFace, Beard, 0xFF,
DrakkinHeritage, DrakkinTattoo, DrakkinDetails
);
c->Message(Chat::White, "%s=%i", ChangeType, ChangeSetting);
}
}
}

53
zone/gm_commands/flag.cpp Executable file
View File

@ -0,0 +1,53 @@
#include "../client.h"
#include "../worldserver.h"
extern WorldServer worldserver;
void command_flag(Client *c, const Seperator *sep)
{
if (sep->arg[2][0] == 0) {
if (!c->GetTarget() || (c->GetTarget() && c->GetTarget() == c)) {
c->UpdateAdmin();
c->Message(Chat::White, "Refreshed your admin flag from DB.");
}
else if (c->GetTarget() && c->GetTarget() != c && c->GetTarget()->IsClient()) {
c->GetTarget()->CastToClient()->UpdateAdmin();
c->Message(Chat::White, "%s's admin flag has been refreshed.", c->GetTarget()->GetName());
c->GetTarget()->Message(Chat::White, "%s refreshed your admin flag.", c->GetName());
}
}
else if (!sep->IsNumber(1) || atoi(sep->arg[1]) < -2 || atoi(sep->arg[1]) > 255 || strlen(sep->arg[2]) == 0) {
c->Message(Chat::White, "Usage: #flag [status] [acctname]");
}
else if (c->Admin() < commandChangeFlags) {
//this check makes banning players by less than this level
//impossible, but i'll leave it in anyways
c->Message(Chat::White, "You may only refresh your own flag, doing so now.");
c->UpdateAdmin();
}
else {
if (atoi(sep->arg[1]) > c->Admin()) {
c->Message(Chat::White, "You cannot set people's status to higher than your own");
}
else if (atoi(sep->arg[1]) < 0 && c->Admin() < commandBanPlayers) {
c->Message(Chat::White, "You have too low of status to suspend/ban");
}
else if (!database.SetAccountStatus(sep->argplus[2], atoi(sep->arg[1]))) {
c->Message(Chat::White, "Unable to set GM Flag.");
}
else {
c->Message(Chat::White, "Set GM Flag on account.");
std::string user;
std::string loginserver;
ParseAccountString(sep->argplus[2], user, loginserver);
ServerPacket pack(ServerOP_FlagUpdate, 6);
*((uint32 *) pack.pBuffer) = database.GetAccountIDByName(user.c_str(), loginserver.c_str());
*((int16 *) &pack.pBuffer[4]) = atoi(sep->arg[1]);
worldserver.SendPacket(&pack);
}
}
}

157
zone/gm_commands/flagedit.cpp Executable file
View File

@ -0,0 +1,157 @@
#include "../client.h"
void command_flagedit(Client *c, const Seperator *sep)
{
//super-command for editing zone flags
if (sep->arg[1][0] == '\0' || !strcasecmp(sep->arg[1], "help")) {
c->Message(Chat::White, "Syntax: #flagedit [lockzone|unlockzone|listzones|give|take].");
c->Message(
Chat::White,
"...lockzone [zone id/short] [flag name] - Set the specified flag name on the zone, locking the zone"
);
c->Message(Chat::White, "...unlockzone [zone id/short] - Removes the flag requirement from the specified zone");
c->Message(Chat::White, "...listzones - List all zones which require a flag, and their flag's name");
c->Message(Chat::White, "...give [zone id/short] - Give your target the zone flag for the specified zone.");
c->Message(
Chat::White,
"...take [zone id/short] - Take the zone flag for the specified zone away from your target"
);
c->Message(Chat::White, "...Note: use #flags to view flags on a person");
return;
}
if (!strcasecmp(sep->arg[1], "lockzone")) {
uint32 zoneid = 0;
if (sep->arg[2][0] != '\0') {
zoneid = atoi(sep->arg[2]);
if (zoneid < 1) {
zoneid = ZoneID(sep->arg[2]);
}
}
if (zoneid < 1) {
c->Message(Chat::Red, "zone required. see help.");
return;
}
char flag_name[128];
if (sep->argplus[3][0] == '\0') {
c->Message(Chat::Red, "flag name required. see help.");
return;
}
database.DoEscapeString(flag_name, sep->argplus[3], 64);
flag_name[127] = '\0';
std::string query = StringFormat(
"UPDATE zone SET flag_needed = '%s' "
"WHERE zoneidnumber = %d AND version = %d",
flag_name, zoneid, zone->GetInstanceVersion());
auto results = content_db.QueryDatabase(query);
if (!results.Success()) {
c->Message(Chat::Red, "Error updating zone: %s", results.ErrorMessage().c_str());
return;
}
c->Message(Chat::Yellow, "Success! Zone %s now requires a flag, named %s", ZoneName(zoneid), flag_name);
return;
}
if (!strcasecmp(sep->arg[1], "unlockzone")) {
uint32 zoneid = 0;
if (sep->arg[2][0] != '\0') {
zoneid = atoi(sep->arg[2]);
if (zoneid < 1) {
zoneid = ZoneID(sep->arg[2]);
}
}
if (zoneid < 1) {
c->Message(Chat::Red, "zone required. see help.");
return;
}
std::string query = StringFormat(
"UPDATE zone SET flag_needed = '' "
"WHERE zoneidnumber = %d AND version = %d",
zoneid, zone->GetInstanceVersion());
auto results = content_db.QueryDatabase(query);
if (!results.Success()) {
c->Message(Chat::Yellow, "Error updating zone: %s", results.ErrorMessage().c_str());
return;
}
c->Message(Chat::Yellow, "Success! Zone %s no longer requires a flag.", ZoneName(zoneid));
return;
}
if (!strcasecmp(sep->arg[1], "listzones")) {
std::string query = "SELECT zoneidnumber, short_name, long_name, version, flag_needed "
"FROM zone WHERE flag_needed != ''";
auto results = content_db.QueryDatabase(query);
if (!results.Success()) {
return;
}
c->Message(Chat::White, "Zones which require flags:");
for (auto row = results.begin(); row != results.end(); ++row)
c->Message(
Chat::White,
"Zone %s (%s,%s) version %s requires key %s",
row[2],
row[0],
row[1],
row[3],
row[4]
);
return;
}
if (!strcasecmp(sep->arg[1], "give")) {
uint32 zoneid = 0;
if (sep->arg[2][0] != '\0') {
zoneid = atoi(sep->arg[2]);
if (zoneid < 1) {
zoneid = ZoneID(sep->arg[2]);
}
}
if (zoneid < 1) {
c->Message(Chat::Red, "zone required. see help.");
return;
}
Mob *t = c->GetTarget();
if (t == nullptr || !t->IsClient()) {
c->Message(Chat::Red, "client target required");
return;
}
t->CastToClient()->SetZoneFlag(zoneid);
return;
}
if (!strcasecmp(sep->arg[1], "give")) {
uint32 zoneid = 0;
if (sep->arg[2][0] != '\0') {
zoneid = atoi(sep->arg[2]);
if (zoneid < 1) {
zoneid = ZoneID(sep->arg[2]);
}
}
if (zoneid < 1) {
c->Message(Chat::Red, "zone required. see help.");
return;
}
Mob *t = c->GetTarget();
if (t == nullptr || !t->IsClient()) {
c->Message(Chat::Red, "client target required");
return;
}
t->CastToClient()->ClearZoneFlag(zoneid);
return;
}
c->Message(Chat::Yellow, "Invalid action specified. use '#flagedit help' for help");
}

16
zone/gm_commands/flags.cpp Executable file
View File

@ -0,0 +1,16 @@
#include "../client.h"
void command_flags(Client *c, const Seperator *sep)
{
Client *t = c;
if (c->Admin() >= minStatusToSeeOthersZoneFlags) {
Mob *tgt = c->GetTarget();
if (tgt != nullptr && tgt->IsClient()) {
t = tgt->CastToClient();
}
}
t->SendZoneFlagInfo(c);
}

40
zone/gm_commands/flymode.cpp Executable file
View File

@ -0,0 +1,40 @@
#include "../client.h"
void command_flymode(Client *c, const Seperator *sep)
{
Mob *t = c;
if (strlen(sep->arg[1]) == 1 && sep->IsNumber(1) && atoi(sep->arg[1]) >= 0 && atoi(sep->arg[1]) <= 5) {
if (c->GetTarget()) {
t = c->GetTarget();
}
int fm = atoi(sep->arg[1]);
t->SetFlyMode(static_cast<GravityBehavior>(fm));
t->SendAppearancePacket(AT_Levitate, fm);
if (sep->arg[1][0] == '0') {
c->Message(Chat::White, "Setting %s to Grounded", t->GetName());
}
else if (sep->arg[1][0] == '1') {
c->Message(Chat::White, "Setting %s to Flying", t->GetName());
}
else if (sep->arg[1][0] == '2') {
c->Message(Chat::White, "Setting %s to Levitating", t->GetName());
}
else if (sep->arg[1][0] == '3') {
c->Message(Chat::White, "Setting %s to In Water", t->GetName());
}
else if (sep->arg[1][0] == '4') {
c->Message(Chat::White, "Setting %s to Floating(Boat)", t->GetName());
}
else if (sep->arg[1][0] == '5') {
c->Message(Chat::White, "Setting %s to Levitating While Running", t->GetName());
}
}
else {
c->Message(Chat::White, "#flymode [0/1/2/3/4/5]");
}
}

42
zone/gm_commands/fov.cpp Executable file
View File

@ -0,0 +1,42 @@
#include "../client.h"
void command_fov(Client *c, const Seperator *sep)
{
if (c->GetTarget()) {
auto target = c->GetTarget();
std::string behind_message = (
c->BehindMob(
target,
c->GetX(),
c->GetY()
) ?
"behind" :
"not behind"
);
std::string gender_message = (
target->GetGender() == MALE ?
"he" :
(
target->GetGender() == FEMALE ?
"she" :
"it"
)
);
c->Message(
Chat::White,
fmt::format(
"You are {} {} ({}), {} has a heading of {}.",
behind_message,
target->GetCleanName(),
target->GetID(),
gender_message,
target->GetHeading()
).c_str()
);
}
else {
c->Message(Chat::White, "You must have a target to use this command.");
}
}

12
zone/gm_commands/freeze.cpp Executable file
View File

@ -0,0 +1,12 @@
#include "../client.h"
void command_freeze(Client *c, const Seperator *sep)
{
if (c->GetTarget() != 0) {
c->GetTarget()->SendAppearancePacket(AT_Anim, ANIM_FREEZE);
}
else {
c->Message(Chat::White, "ERROR: Freeze requires a target.");
}
}

14
zone/gm_commands/gassign.cpp Executable file
View File

@ -0,0 +1,14 @@
#include "../client.h"
void command_gassign(Client *c, const Seperator *sep)
{
if (sep->IsNumber(1) && c->GetTarget() && c->GetTarget()->IsNPC() &&
c->GetTarget()->CastToNPC()->GetSpawnPointID() > 0) {
int spawn2id = c->GetTarget()->CastToNPC()->GetSpawnPointID();
database.AssignGrid(c, atoi(sep->arg[1]), spawn2id);
}
else {
c->Message(Chat::White, "Usage: #gassign [num] - must have an npc target!");
}
}

181
zone/gm_commands/gearup.cpp Executable file
View File

@ -0,0 +1,181 @@
#include "../client.h"
#include "../../common/http/httplib.h"
#include "../../common/content/world_content_service.h"
void command_gearup(Client *c, const Seperator *sep)
{
std::string tool_table_name = "tool_gearup_armor_sets";
if (!database.DoesTableExist(tool_table_name)) {
c->Message(
Chat::Yellow,
fmt::format(
"Table [{}] does not exist. Downloading from Github and installing...",
tool_table_name
).c_str()
);
// http get request
httplib::Client cli("https://raw.githubusercontent.com");
cli.set_connection_timeout(0, 15000000); // 15 sec
cli.set_read_timeout(15, 0); // 15 seconds
cli.set_write_timeout(15, 0); // 15 seconds
int sourced_queries = 0;
std::string url = "/EQEmu/Server/master/utils/sql/git/optional/2020_07_20_tool_gearup_armor_sets.sql";
if (auto res = cli.Get(url.c_str())) {
if (res->status == 200) {
for (auto &s: SplitString(res->body, ';')) {
if (!trim(s).empty()) {
auto results = database.QueryDatabase(s);
if (!results.ErrorMessage().empty()) {
c->Message(
Chat::Yellow,
fmt::format(
"Error sourcing SQL [{}]", results.ErrorMessage()
).c_str()
);
return;
}
sourced_queries++;
}
}
}
}
else {
c->Message(
Chat::Yellow,
fmt::format(
"Error retrieving URL [{}]",
url
).c_str()
);
}
c->Message(
Chat::Yellow,
fmt::format(
"Table [{}] installed. Sourced [{}] queries",
tool_table_name, sourced_queries
).c_str()
);
}
std::string expansion_arg = sep->arg[1];
std::string expansion_filter;
if (expansion_arg.length() > 0) {
expansion_filter = fmt::format("and `expansion` = {}", expansion_arg);
}
auto results = database.QueryDatabase(
fmt::format(
SQL (
select
item_id,
slot
from
{}
where
`class` = {}
and `level` = {}
{}
order by score desc, expansion desc
),
tool_table_name,
c->GetClass(),
c->GetLevel(),
expansion_filter
)
);
int items_equipped = 0;
int items_already_have = 0;
std::set<int> equipped;
for (auto row = results.begin(); row != results.end(); ++row) {
int item_id = atoi(row[0]);
int slot_id = atoi(row[1]);
if (equipped.find(slot_id) != equipped.end()) {
if (slot_id == EQ::invslot::slotEar1) {
slot_id = EQ::invslot::slotEar2;
}
if (slot_id == EQ::invslot::slotFinger1) {
slot_id = EQ::invslot::slotFinger2;
}
if (slot_id == EQ::invslot::slotWrist1) {
slot_id = EQ::invslot::slotWrist2;
}
}
if (equipped.find(slot_id) == equipped.end()) {
const EQ::ItemData *item = database.GetItem(item_id);
bool has_item = (c->GetInv().HasItem(item_id, 1, invWhereWorn) != INVALID_INDEX);
bool can_wear_item = !c->CheckLoreConflict(item) && !has_item;
if (!can_wear_item) {
items_already_have++;
}
if (c->CastToMob()->CanClassEquipItem(item_id) && can_wear_item) {
equipped.insert(slot_id);
c->SummonItem(
item_id,
0, 0, 0, 0, 0, 0, 0, 0,
slot_id
);
items_equipped++;
}
}
}
c->Message(
Chat::White,
fmt::format(
"Equipped items [{}] already had [{}] items equipped",
items_equipped,
items_already_have
).c_str()
);
if (expansion_arg.empty()) {
results = database.QueryDatabase(
fmt::format(
SQL (
select
expansion
from
{}
where
class = {}
and level = {}
group by
expansion;
),
tool_table_name,
c->GetClass(),
c->GetLevel()
)
);
c->Message(Chat::White, "Choose armor from a specific era");
std::string message;
for (auto row = results.begin(); row != results.end(); ++row) {
int expansion = atoi(row[0]);
message += "[" + EQ::SayLinkEngine::GenerateQuestSaylink(
fmt::format("#gearup {}", expansion),
false,
Expansion::ExpansionName[expansion]
) + "] ";
if (message.length() > 2000) {
c->Message(Chat::White, message.c_str());
message = "";
}
}
if (message.length() > 0) {
c->Message(Chat::White, message.c_str());
}
}
}

17
zone/gm_commands/gender.cpp Executable file
View File

@ -0,0 +1,17 @@
#include "../client.h"
void command_gender(Client *c, const Seperator *sep)
{
Mob *t = c->CastToMob();
if (sep->IsNumber(1) && atoi(sep->arg[1]) >= 0 && atoi(sep->arg[1]) <= 500) {
if ((c->GetTarget()) && c->Admin() >= commandGenderOthers) {
t = c->GetTarget();
}
t->SendIllusionPacket(t->GetRace(), atoi(sep->arg[1]));
}
else {
c->Message(Chat::White, "Usage: #gender [0/1/2]");
}
}

View File

@ -0,0 +1,27 @@
#include "../client.h"
#include "../corpse.h"
void command_getplayerburiedcorpsecount(Client *c, const Seperator *sep)
{
Client *t = c;
if (c->GetTarget() && c->GetTarget()->IsClient() && c->GetGM()) {
t = c->GetTarget()->CastToClient();
}
else {
c->Message(Chat::White, "You must first select a target!");
return;
}
uint32 CorpseCount = database.GetCharacterBuriedCorpseCount(t->CharacterID());
if (CorpseCount > 0) {
c->Message(Chat::White, "Your target has a total of %u buried corpses.", CorpseCount);
}
else {
c->Message(Chat::White, "Your target doesn't have any buried corpses.");
}
return;
}

View File

@ -0,0 +1,13 @@
#include "../client.h"
void command_getvariable(Client *c, const Seperator *sep)
{
std::string tmp;
if (database.GetVariable(sep->argplus[1], tmp)) {
c->Message(Chat::White, "%s = %s", sep->argplus[1], tmp.c_str());
}
else {
c->Message(Chat::White, "GetVariable(%s) returned false", sep->argplus[1]);
}
}

52
zone/gm_commands/ginfo.cpp Executable file
View File

@ -0,0 +1,52 @@
#include "../client.h"
#include "../groups.h"
void command_ginfo(Client *c, const Seperator *sep)
{
Client *t;
if (c->GetTarget() && c->GetTarget()->IsClient()) {
t = c->GetTarget()->CastToClient();
}
else {
t = c;
}
Group *g = t->GetGroup();
if (!g) {
c->Message(Chat::White, "This client is not in a group");
return;
}
c->Message(
Chat::White,
"Player: %s is in Group #%lu: with %i members",
t->GetName(),
(unsigned long) g->GetID(),
g->GroupCount());
uint32 r;
for (r = 0; r < MAX_GROUP_MEMBERS; r++) {
if (g->members[r] == nullptr) {
if (g->membername[r][0] == '\0') {
continue;
}
c->Message(
Chat::White, "...Zoned Member: %s, Roles: %s %s %s", g->membername[r],
(g->MemberRoles[r] & RoleAssist) ? "Assist" : "",
(g->MemberRoles[r] & RoleTank) ? "Tank" : "",
(g->MemberRoles[r] & RolePuller) ? "Puller" : ""
);
}
else {
c->Message(
Chat::White, "...In-Zone Member: %s (0x%x) Roles: %s %s %s", g->membername[r], g->members[r],
(g->MemberRoles[r] & RoleAssist) ? "Assist" : "",
(g->MemberRoles[r] & RoleTank) ? "Tank" : "",
(g->MemberRoles[r] & RolePuller) ? "Puller" : ""
);
}
}
}

111
zone/gm_commands/giveitem.cpp Executable file
View File

@ -0,0 +1,111 @@
#include "../client.h"
void command_giveitem(Client *c, const Seperator *sep)
{
uint32 item_id = 0;
int16 charges = -1;
uint32 augment_one = 0;
uint32 augment_two = 0;
uint32 augment_three = 0;
uint32 augment_four = 0;
uint32 augment_five = 0;
uint32 augment_six = 0;
int arguments = sep->argnum;
std::string cmd_msg = sep->msg;
size_t link_open = cmd_msg.find('\x12');
size_t link_close = cmd_msg.find_last_of('\x12');
if (c->GetTarget()) {
if (!c->GetTarget()->IsClient()) {
c->Message(Chat::Red, "You can only give items to players with this command.");
return;
}
if (link_open != link_close && (cmd_msg.length() - link_open) > EQ::constants::SAY_LINK_BODY_SIZE) {
EQ::SayLinkBody_Struct link_body;
EQ::saylink::DegenerateLinkBody(
link_body,
cmd_msg.substr(link_open + 1, EQ::constants::SAY_LINK_BODY_SIZE));
item_id = link_body.item_id;
augment_one = link_body.augment_1;
augment_two = link_body.augment_2;
augment_three = link_body.augment_3;
augment_four = link_body.augment_4;
augment_five = link_body.augment_5;
augment_six = link_body.augment_6;
}
else if (sep->IsNumber(1)) {
item_id = atoi(sep->arg[1]);
}
else if (!sep->IsNumber(1)) {
c->Message(
Chat::Red,
"Usage: #giveitem [item id | link] [charges] [augment_one_id] [augment_two_id] [augment_three_id] [augment_four_id] [augment_five_id] [augment_six_id] (Charges are optional.)"
);
return;
}
Client *client_target = c->GetTarget()->CastToClient();
uint8 item_status = 0;
uint8 current_status = c->Admin();
const EQ::ItemData *item = database.GetItem(item_id);
if (item) {
item_status = item->MinStatus;
}
if (item_status > current_status) {
c->Message(
Chat::White,
fmt::format(
"Insufficient status to summon this item, current status is {}, required status is {}.",
current_status,
item_status
).c_str()
);
return;
}
if (arguments >= 2 && sep->IsNumber(2)) {
charges = atoi(sep->arg[2]);
}
if (arguments >= 3 && sep->IsNumber(3)) {
augment_one = atoi(sep->arg[3]);
}
if (arguments >= 4 && sep->IsNumber(4)) {
augment_two = atoi(sep->arg[4]);
}
if (arguments >= 5 && sep->IsNumber(5)) {
augment_three = atoi(sep->arg[5]);
}
if (arguments >= 6 && sep->IsNumber(6)) {
augment_four = atoi(sep->arg[6]);
}
if (arguments >= 7 && sep->IsNumber(7)) {
augment_five = atoi(sep->arg[7]);
}
if (arguments == 8 && sep->IsNumber(8)) {
augment_six = atoi(sep->arg[8]);
}
client_target->SummonItem(
item_id,
charges,
augment_one,
augment_two,
augment_three,
augment_four,
augment_five,
augment_six
);
}
else {
c->Message(Chat::Red, "You must target a client to give the item to.");
return;
}
}

33
zone/gm_commands/givemoney.cpp Executable file
View File

@ -0,0 +1,33 @@
#include "../client.h"
void command_givemoney(Client *c, const Seperator *sep)
{
if (!sep->IsNumber(1)) { //as long as the first one is a number, we'll just let atoi convert the rest to 0 or a number
c->Message(Chat::Red, "Usage: #Usage: #givemoney [pp] [gp] [sp] [cp]");
}
else if (c->GetTarget() == nullptr) {
c->Message(Chat::Red, "You must target a player to give money to.");
}
else if (!c->GetTarget()->IsClient()) {
c->Message(Chat::Red, "You can only give money to players with this command.");
}
else {
//TODO: update this to the client, otherwise the client doesn't show any weight change until you zone, move an item, etc
c->GetTarget()->CastToClient()->AddMoneyToPP(
atoi(sep->arg[4]),
atoi(sep->arg[3]),
atoi(sep->arg[2]),
atoi(sep->arg[1]),
true
);
c->Message(
Chat::White,
"Added %i Platinum, %i Gold, %i Silver, and %i Copper to %s's inventory.",
atoi(sep->arg[1]),
atoi(sep->arg[2]),
atoi(sep->arg[3]),
atoi(sep->arg[4]),
c->GetTarget()->GetName());
}
}

80
zone/gm_commands/globalview.cpp Executable file
View File

@ -0,0 +1,80 @@
#include "../client.h"
void command_globalview(Client *c, const Seperator *sep)
{
NPC *npcmob = nullptr;
if (c->GetTarget() && c->GetTarget()->IsNPC()) {
npcmob = c->GetTarget()->CastToNPC();
QGlobalCache *npc_c = nullptr;
QGlobalCache *char_c = nullptr;
QGlobalCache *zone_c = nullptr;
if (npcmob) {
npc_c = npcmob->GetQGlobals();
}
char_c = c->GetQGlobals();
zone_c = zone->GetQGlobals();
std::list<QGlobal> globalMap;
uint32 ntype = 0;
if (npcmob) {
ntype = npcmob->GetNPCTypeID();
}
if (npc_c) {
QGlobalCache::Combine(globalMap, npc_c->GetBucket(), ntype, c->CharacterID(), zone->GetZoneID());
}
if (char_c) {
QGlobalCache::Combine(globalMap, char_c->GetBucket(), ntype, c->CharacterID(), zone->GetZoneID());
}
if (zone_c) {
QGlobalCache::Combine(globalMap, zone_c->GetBucket(), ntype, c->CharacterID(), zone->GetZoneID());
}
auto iter = globalMap.begin();
uint32 gcount = 0;
c->Message(Chat::White, "Name, Value");
while (iter != globalMap.end()) {
c->Message(Chat::White, "%s %s", (*iter).name.c_str(), (*iter).value.c_str());
++iter;
++gcount;
}
c->Message(Chat::White, "%u globals loaded.", gcount);
}
else {
QGlobalCache *char_c = nullptr;
QGlobalCache *zone_c = nullptr;
char_c = c->GetQGlobals();
zone_c = zone->GetQGlobals();
std::list<QGlobal> globalMap;
uint32 ntype = 0;
if (char_c) {
QGlobalCache::Combine(globalMap, char_c->GetBucket(), ntype, c->CharacterID(), zone->GetZoneID());
}
if (zone_c) {
QGlobalCache::Combine(globalMap, zone_c->GetBucket(), ntype, c->CharacterID(), zone->GetZoneID());
}
auto iter = globalMap.begin();
uint32 gcount = 0;
c->Message(Chat::White, "Name, Value");
while (iter != globalMap.end()) {
c->Message(Chat::White, "%s %s", (*iter).name.c_str(), (*iter).value.c_str());
++iter;
++gcount;
}
c->Message(Chat::White, "%u globals loaded.", gcount);
}
}

27
zone/gm_commands/gm.cpp Executable file
View File

@ -0,0 +1,27 @@
#include "../client.h"
void command_gm(Client *c, const Seperator *sep)
{
bool state = atobool(sep->arg[1]);
Client *t = c;
if (c->GetTarget() && c->GetTarget()->IsClient()) {
t = c->GetTarget()->CastToClient();
}
if (sep->arg[1][0] != 0) {
t->SetGM(state);
c->Message(Chat::White, "%s is %s a GM.", t->GetName(), state ? "now" : "no longer");
}
else {
c->Message(Chat::White, "Usage: #gm [on/off]");
}
}
// there's no need for this, as /summon already takes care of it
// this command is here for reference but it is not added to the
// list above
//To whoever wrote the above: And what about /kill, /zone, /zoneserver, etc?
//There is a reason for the # commands: so that admins can specifically enable certain
//commands for their users. Some might want users to #summon but not to /kill. Cant do that if they are a GM

20
zone/gm_commands/gmspeed.cpp Executable file
View File

@ -0,0 +1,20 @@
#include "../client.h"
void command_gmspeed(Client *c, const Seperator *sep)
{
bool state = atobool(sep->arg[1]);
Client *t = c;
if (c->GetTarget() && c->GetTarget()->IsClient()) {
t = c->GetTarget()->CastToClient();
}
if (sep->arg[1][0] != 0) {
database.SetGMSpeed(t->AccountID(), state ? 1 : 0);
c->Message(Chat::White, "Turning GMSpeed %s for %s (zone to take effect)", state ? "On" : "Off", t->GetName());
}
else {
c->Message(Chat::White, "Usage: #gmspeed [on/off]");
}
}

88
zone/gm_commands/gmzone.cpp Executable file
View File

@ -0,0 +1,88 @@
#include "../client.h"
#include "../data_bucket.h"
void command_gmzone(Client *c, const Seperator *sep)
{
if (!sep->arg[1]) {
c->Message(Chat::White, "Usage");
c->Message(Chat::White, "-------");
c->Message(Chat::White, "#gmzone [zone_short_name] [zone_version=0]");
return;
}
std::string zone_short_name_string = sep->arg[1];
const char *zone_short_name = sep->arg[1];
auto zone_version = static_cast<uint32>(sep->arg[2] ? atoi(sep->arg[2]) : 0);
std::string identifier = "gmzone";
uint32 zone_id = ZoneID(zone_short_name);
uint32 duration = 100000000;
uint16 instance_id = 0;
if (zone_id == 0) {
c->Message(Chat::Red, "Invalid zone specified");
return;
}
if (sep->arg[3] && sep->arg[3][0]) {
identifier = sep->arg[3];
}
std::string bucket_key = StringFormat(
"%s-%s-%u-instance",
zone_short_name,
identifier.c_str(),
zone_version
);
std::string existing_zone_instance = DataBucket::GetData(bucket_key);
if (existing_zone_instance.length() > 0) {
instance_id = std::stoi(existing_zone_instance);
c->Message(Chat::Yellow, "Found already created instance (%s) (%u)", zone_short_name, instance_id);
}
if (instance_id == 0) {
if (!database.GetUnusedInstanceID(instance_id)) {
c->Message(Chat::Red, "Server was unable to find a free instance id.");
return;
}
if (!database.CreateInstance(instance_id, zone_id, zone_version, duration)) {
c->Message(Chat::Red, "Server was unable to create a new instance.");
return;
}
c->Message(
Chat::Yellow,
"New private GM instance %s was created with id %lu.",
zone_short_name,
(unsigned long) instance_id
);
DataBucket::SetData(bucket_key, std::to_string(instance_id));
}
if (instance_id > 0) {
float target_x = -1, target_y = -1, target_z = -1, target_heading = -1;
int16 min_status = AccountStatus::Player;
uint8 min_level = 0;
if (!content_db.GetSafePoints(
zone_short_name,
zone_version,
&target_x,
&target_y,
&target_z,
&target_heading,
&min_status,
&min_level
)) {
c->Message(Chat::Red, "Failed to find safe coordinates for specified zone");
}
c->Message(Chat::Yellow, "Zoning to private GM instance (%s) (%u)", zone_short_name, instance_id);
c->AssignToInstance(instance_id);
c->MovePC(zone_id, instance_id, target_x, target_y, target_z, target_heading, 1);
}
}

63
zone/gm_commands/goto.cpp Executable file
View File

@ -0,0 +1,63 @@
#include "../client.h"
void command_goto(Client *c, const Seperator *sep)
{
std::string arg1 = sep->arg[1];
bool goto_via_target_no_args = sep->arg[1][0] == '\0' && c->GetTarget();
bool goto_via_player_name = !sep->IsNumber(1) && !arg1.empty();
bool goto_via_x_y_z = sep->IsNumber(1) && sep->IsNumber(2) && sep->IsNumber(3);
if (goto_via_target_no_args) {
c->MovePC(
zone->GetZoneID(),
zone->GetInstanceID(),
c->GetTarget()->GetX(),
c->GetTarget()->GetY(),
c->GetTarget()->GetZ(),
c->GetTarget()->GetHeading()
);
}
else if (goto_via_player_name) {
/**
* Find them in zone first
*/
const char *player_name = sep->arg[1];
std::string player_name_string = sep->arg[1];
Client *client = entity_list.GetClientByName(player_name);
if (client) {
c->MovePC(
zone->GetZoneID(),
zone->GetInstanceID(),
client->GetX(),
client->GetY(),
client->GetZ(),
client->GetHeading()
);
c->Message(Chat::Yellow, "Goto player '%s' same zone", player_name_string.c_str());
}
else if (c->GotoPlayer(player_name_string)) {
c->Message(Chat::Yellow, "Goto player '%s' different zone", player_name_string.c_str());
}
else {
c->Message(Chat::Yellow, "Player '%s' not found", player_name_string.c_str());
}
}
else if (goto_via_x_y_z) {
c->MovePC(
zone->GetZoneID(),
zone->GetInstanceID(),
atof(sep->arg[1]),
atof(sep->arg[2]),
atof(sep->arg[3]),
(sep->arg[4] ? atof(sep->arg[4]) : c->GetHeading())
);
}
else {
c->Message(Chat::White, "Usage: #goto [x y z] [h]");
c->Message(Chat::White, "Usage: #goto [player_name]");
}
}

143
zone/gm_commands/grid.cpp Executable file
View File

@ -0,0 +1,143 @@
#include "../client.h"
void command_grid(Client *c, const Seperator *sep)
{
auto command_type = sep->arg[1];
auto zone_id = zone->GetZoneID();
if (strcasecmp("max", command_type) == 0) {
c->Message(
Chat::White,
fmt::format(
"Highest grid ID in this zone is {}.",
content_db.GetHighestGrid(zone_id)
).c_str()
);
}
else if (strcasecmp("add", command_type) == 0) {
auto grid_id = atoi(sep->arg[2]);
auto wander_type = atoi(sep->arg[3]);
auto pause_type = atoi(sep->arg[4]);
if (!content_db.GridExistsInZone(zone_id, grid_id)) {
content_db.ModifyGrid(c, false, grid_id, wander_type, pause_type, zone_id);
c->Message(
Chat::White,
fmt::format(
"Grid {} added to zone ID {} with wander type {} and pause type {}.",
grid_id,
zone_id,
wander_type,
pause_type
).c_str()
);
}
else {
c->Message(
Chat::White,
fmt::format(
"Grid {} already exists in zone ID {}.",
grid_id,
zone_id
).c_str()
);
return;
}
}
else if (strcasecmp("show", command_type) == 0) {
Mob *target = c->GetTarget();
if (!target || !target->IsNPC()) {
c->Message(Chat::White, "You need to target an NPC!");
return;
}
auto grid_id = target->CastToNPC()->GetGrid();
std::string query = fmt::format(
"SELECT `x`, `y`, `z`, `heading`, `number` "
"FROM `grid_entries` "
"WHERE `zoneid` = {} AND `gridid` = {} "
"ORDER BY `number`",
zone_id,
grid_id
);
auto results = content_db.QueryDatabase(query);
if (!results.Success()) {
c->Message(Chat::White, "Error querying database.");
c->Message(Chat::White, query.c_str());
}
if (results.RowCount() == 0) {
c->Message(Chat::White, "No grid found.");
return;
}
// Depop any node npc's already spawned
entity_list.DespawnGridNodes(grid_id);
// Spawn grid nodes
std::map<std::vector<float>, int32> zoffset;
for (auto row : results) {
glm::vec4 node_position = glm::vec4(atof(row[0]), atof(row[1]), atof(row[2]), atof(row[3]));
std::vector<float> node_loc{
node_position.x,
node_position.y,
node_position.z
};
// If we already have a node at this location, set the z offset
// higher from the existing one so we can see it. Adjust so if
// there is another at the same spot we adjust again.
auto search = zoffset.find(node_loc);
if (search != zoffset.end()) {
search->second = search->second + 3;
}
else {
zoffset[node_loc] = 0.0;
}
node_position.z += zoffset[node_loc];
NPC::SpawnGridNodeNPC(node_position, grid_id, atoi(row[4]), zoffset[node_loc]);
}
c->Message(
Chat::White,
fmt::format(
"Spawning nodes for grid {}.",
grid_id
).c_str()
);
}
else if (strcasecmp("hide", command_type) == 0) {
Mob *target = c->GetTarget();
if (!target || !target->IsNPC()) {
c->Message(Chat::White, "You need to target an NPC!");
return;
}
auto grid_id = target->CastToNPC()->GetGrid();
entity_list.DespawnGridNodes(grid_id);
c->Message(
Chat::White,
fmt::format(
"Depawning nodes for grid {}.",
grid_id
).c_str()
);
}
else if (strcasecmp("delete", command_type) == 0) {
auto grid_id = atoi(sep->arg[2]);
content_db.ModifyGrid(c, true, grid_id, 0, 0, zone_id);
c->Message(
Chat::White,
fmt::format(
"Grid {} deleted from zone ID {}.",
grid_id,
zone_id
).c_str()
);
}
else {
c->Message(Chat::White, "Usage: #grid [add|delete] [grid_id] [wander_type] [pause_type]");
c->Message(Chat::White, "Usage: #grid [max] - displays the highest grid ID used in this zone (for add)");
c->Message(Chat::White, "Usage: #grid [show] - displays wp nodes as boxes");
}
}

444
zone/gm_commands/guild.cpp Executable file
View File

@ -0,0 +1,444 @@
#include "../client.h"
#include "../worldserver.h"
extern WorldServer worldserver;
#include "../guild_mgr.h"
#include "../doors.h"
void command_guild(Client *c, const Seperator *sep)
{
int admin = c->Admin();
Mob *target = c->GetTarget();
if (strcasecmp(sep->arg[1], "help") == 0) {
c->Message(Chat::White, "GM Guild commands:");
c->Message(Chat::White, " #guild list - lists all guilds on the server");
c->Message(Chat::White, " #guild create {guildleader charname or CharID} guildname");
c->Message(Chat::White, " #guild delete guildID");
c->Message(Chat::White, " #guild rename guildID newname");
c->Message(Chat::White, " #guild set charname guildID (0=no guild)");
c->Message(Chat::White, " #guild setrank charname rank");
c->Message(Chat::White, " #guild setleader guildID {guildleader charname or CharID}");
}
else if (strcasecmp(sep->arg[1], "status") == 0 || strcasecmp(sep->arg[1], "stat") == 0) {
Client *client = 0;
if (sep->arg[2][0] != 0) {
client = entity_list.GetClientByName(sep->argplus[2]);
}
else if (target != 0 && target->IsClient()) {
client = target->CastToClient();
}
if (client == 0) {
c->Message(Chat::White, "You must target someone or specify a character name");
}
else if ((client->Admin() >= minStatusToEditOtherGuilds && admin < minStatusToEditOtherGuilds) &&
client->GuildID() != c->GuildID()) { // no peeping for GMs, make sure tell message stays the same
c->Message(Chat::White, "You must target someone or specify a character name.");
}
else {
if (client->IsInAGuild()) {
c->Message(Chat::White, "%s is not in a guild.", client->GetName());
}
else if (guild_mgr.IsGuildLeader(client->GuildID(), client->CharacterID())) {
c->Message(
Chat::White,
"%s is the leader of <%s> rank: %s",
client->GetName(),
guild_mgr.GetGuildName(client->GuildID()),
guild_mgr.GetRankName(client->GuildID(), client->GuildRank()));
}
else {
c->Message(
Chat::White,
"%s is a member of <%s> rank: %s",
client->GetName(),
guild_mgr.GetGuildName(client->GuildID()),
guild_mgr.GetRankName(client->GuildID(), client->GuildRank()));
}
}
}
else if (strcasecmp(sep->arg[1], "info") == 0) {
if (sep->arg[2][0] == 0 && c->IsInAGuild()) {
if (admin >= minStatusToEditOtherGuilds) {
c->Message(Chat::White, "Usage: #guildinfo guild_id");
}
else {
c->Message(Chat::White, "You're not in a guild");
}
}
else {
uint32 tmp = GUILD_NONE;
if (sep->arg[2][0] == 0) {
tmp = c->GuildID();
}
else if (admin >= minStatusToEditOtherGuilds) {
tmp = atoi(sep->arg[2]);
}
if (tmp != GUILD_NONE) {
guild_mgr.DescribeGuild(c, tmp);
}
}
}
else if (strcasecmp(sep->arg[1], "set") == 0) {
if (!sep->IsNumber(3)) {
c->Message(Chat::White, "Usage: #guild set charname guildgbid (0 = clear guildtag)");
}
else {
uint32 guild_id = atoi(sep->arg[3]);
if (guild_id == 0) {
guild_id = GUILD_NONE;
}
else if (!guild_mgr.GuildExists(guild_id)) {
c->Message(Chat::Red, "Guild %d does not exist.", guild_id);
return;
}
uint32 charid = database.GetCharacterID(sep->arg[2]);
if (charid == 0) {
c->Message(Chat::Red, "Unable to find character '%s'", charid);
return;
}
//we could do the checking we need for guild_mgr.CheckGMStatus, but im lazy right now
if (admin < minStatusToEditOtherGuilds) {
c->Message(Chat::Red, "Access denied.");
return;
}
if (guild_id == GUILD_NONE) {
LogGuilds("[{}]: Removing [{}] ([{}]) from guild with GM command", c->GetName(), sep->arg[2], charid);
}
else {
LogGuilds("[{}]: Putting [{}] ([{}]) into guild [{}] ([{}]) with GM command",
c->GetName(),
sep->arg[2],
charid,
guild_mgr.GetGuildName(guild_id),
guild_id);
}
if (!guild_mgr.SetGuild(charid, guild_id, GUILD_MEMBER)) {
c->Message(Chat::Red, "Error putting '%s' into guild %d", sep->arg[2], guild_id);
}
else {
c->Message(Chat::White, "%s has been put into guild %d", sep->arg[2], guild_id);
}
}
}
/*else if (strcasecmp(sep->arg[1], "setdoor") == 0 && admin >= minStatusToEditOtherGuilds) {
if (!sep->IsNumber(2))
c->Message(Chat::White, "Usage: #guild setdoor guildEQid (0 = delete guilddoor)");
else {
// guild doors
if((!guilds[atoi(sep->arg[2])].databaseID) && (atoi(sep->arg[2])!=0) )
{
c->Message(Chat::White, "These is no guild with this guildEQid");
}
else {
c->SetIsSettingGuildDoor(true);
c->Message(Chat::White, "Click on a door you want to become a guilddoor");
c->SetSetGuildDoorID(atoi(sep->arg[2]));
}
}
}*/
else if (strcasecmp(sep->arg[1], "setrank") == 0) {
int rank = atoi(sep->arg[3]);
if (!sep->IsNumber(3)) {
c->Message(Chat::White, "Usage: #guild setrank charname rank");
}
else if (rank < 0 || rank > GUILD_MAX_RANK) {
c->Message(Chat::White, "Error: invalid rank #.");
}
else {
uint32 charid = database.GetCharacterID(sep->arg[2]);
if (charid == 0) {
c->Message(Chat::Red, "Unable to find character '%s'", charid);
return;
}
//we could do the checking we need for guild_mgr.CheckGMStatus, but im lazy right now
if (admin < minStatusToEditOtherGuilds) {
c->Message(Chat::Red, "Access denied.");
return;
}
LogGuilds("[{}]: Setting [{}] ([{}])'s guild rank to [{}] with GM command",
c->GetName(),
sep->arg[2],
charid,
rank);
if (!guild_mgr.SetGuildRank(charid, rank)) {
c->Message(Chat::Red, "Error while setting rank %d on '%s'.", rank, sep->arg[2]);
}
else {
c->Message(Chat::White, "%s has been set to rank %d", sep->arg[2], rank);
}
}
}
else if (strcasecmp(sep->arg[1], "create") == 0) {
if (sep->arg[3][0] == 0) {
c->Message(Chat::White, "Usage: #guild create {guildleader charname or CharID} guild name");
}
else if (!worldserver.Connected()) {
c->Message(Chat::White, "Error: World server dirconnected");
}
else {
uint32 leader = 0;
if (sep->IsNumber(2)) {
leader = atoi(sep->arg[2]);
}
else if ((leader = database.GetCharacterID(sep->arg[2])) != 0) {
//got it from the db..
}
else {
c->Message(Chat::Red, "Unable to find char '%s'", sep->arg[2]);
return;
}
if (leader == 0) {
c->Message(Chat::White, "Guild leader not found.");
return;
}
uint32 tmp = guild_mgr.FindGuildByLeader(leader);
if (tmp != GUILD_NONE) {
c->Message(
Chat::White,
"Error: %s already is the leader of DB# %i '%s'.",
sep->arg[2],
tmp,
guild_mgr.GetGuildName(tmp));
}
else {
if (admin < minStatusToEditOtherGuilds) {
c->Message(Chat::Red, "Access denied.");
return;
}
uint32 id = guild_mgr.CreateGuild(sep->argplus[3], leader);
LogGuilds("[{}]: Creating guild [{}] with leader [{}] with GM command. It was given id [{}]",
c->GetName(),
sep->argplus[3],
leader,
(unsigned long) id);
if (id == GUILD_NONE) {
c->Message(Chat::White, "Guild creation failed.");
}
else {
c->Message(Chat::White, "Guild created: Leader: %i, number %i: %s", leader, id, sep->argplus[3]);
if (!guild_mgr.SetGuild(leader, id, GUILD_LEADER)) {
c->Message(
Chat::White,
"Unable to set guild leader's guild in the database. Your going to have to run #guild set"
);
}
}
}
}
}
else if (strcasecmp(sep->arg[1], "delete") == 0) {
if (!sep->IsNumber(2)) {
c->Message(Chat::White, "Usage: #guild delete guildID");
}
else if (!worldserver.Connected()) {
c->Message(Chat::White, "Error: World server dirconnected");
}
else {
uint32 id = atoi(sep->arg[2]);
if (!guild_mgr.GuildExists(id)) {
c->Message(Chat::White, "Guild %d does not exist!", id);
return;
}
if (admin < minStatusToEditOtherGuilds) {
//this person is not allowed to just edit any guild, check this guild's min status.
if (c->GuildID() != id) {
c->Message(Chat::Red, "Access denied to edit other people's guilds");
return;
}
else if (!guild_mgr.CheckGMStatus(id, admin)) {
c->Message(Chat::Red, "Access denied to edit your guild with GM commands.");
return;
}
}
LogGuilds("[{}]: Deleting guild [{}] ([{}]) with GM command", c->GetName(),
guild_mgr.GetGuildName(id), id);
if (!guild_mgr.DeleteGuild(id)) {
c->Message(Chat::White, "Guild delete failed.");
}
else {
c->Message(Chat::White, "Guild %d deleted.", id);
}
}
}
else if (strcasecmp(sep->arg[1], "rename") == 0) {
if ((!sep->IsNumber(2)) || sep->arg[3][0] == 0) {
c->Message(Chat::White, "Usage: #guild rename guildID newname");
}
else if (!worldserver.Connected()) {
c->Message(Chat::White, "Error: World server dirconnected");
}
else {
uint32 id = atoi(sep->arg[2]);
if (!guild_mgr.GuildExists(id)) {
c->Message(Chat::White, "Guild %d does not exist!", id);
return;
}
if (admin < minStatusToEditOtherGuilds) {
//this person is not allowed to just edit any guild, check this guild's min status.
if (c->GuildID() != id) {
c->Message(Chat::Red, "Access denied to edit other people's guilds");
return;
}
else if (!guild_mgr.CheckGMStatus(id, admin)) {
c->Message(Chat::Red, "Access denied to edit your guild with GM commands.");
return;
}
}
LogGuilds("[{}]: Renaming guild [{}] ([{}]) to [{}] with GM command", c->GetName(),
guild_mgr.GetGuildName(id), id, sep->argplus[3]);
if (!guild_mgr.RenameGuild(id, sep->argplus[3])) {
c->Message(Chat::White, "Guild rename failed.");
}
else {
c->Message(Chat::White, "Guild %d renamed to %s", id, sep->argplus[3]);
}
}
}
else if (strcasecmp(sep->arg[1], "setleader") == 0) {
if (sep->arg[3][0] == 0 || !sep->IsNumber(2)) {
c->Message(Chat::White, "Usage: #guild setleader guild_id {guildleader charname or CharID}");
}
else if (!worldserver.Connected()) {
c->Message(Chat::White, "Error: World server dirconnected");
}
else {
uint32 leader = 0;
if (sep->IsNumber(2)) {
leader = atoi(sep->arg[2]);
}
else if ((leader = database.GetCharacterID(sep->arg[2])) != 0) {
//got it from the db..
}
else {
c->Message(Chat::Red, "Unable to find char '%s'", sep->arg[2]);
return;
}
uint32 tmpdb = guild_mgr.FindGuildByLeader(leader);
if (leader == 0) {
c->Message(Chat::White, "New leader not found.");
}
else if (tmpdb != 0) {
c->Message(Chat::White, "Error: %s already is the leader of guild # %i", sep->arg[2], tmpdb);
}
else {
uint32 id = atoi(sep->arg[2]);
if (!guild_mgr.GuildExists(id)) {
c->Message(Chat::White, "Guild %d does not exist!", id);
return;
}
if (admin < minStatusToEditOtherGuilds) {
//this person is not allowed to just edit any guild, check this guild's min status.
if (c->GuildID() != id) {
c->Message(Chat::Red, "Access denied to edit other people's guilds");
return;
}
else if (!guild_mgr.CheckGMStatus(id, admin)) {
c->Message(Chat::Red, "Access denied to edit your guild with GM commands.");
return;
}
}
LogGuilds("[{}]: Setting leader of guild [{}] ([{}]) to [{}] with GM command", c->GetName(),
guild_mgr.GetGuildName(id), id, leader);
if (!guild_mgr.SetGuildLeader(id, leader)) {
c->Message(Chat::White, "Guild leader change failed.");
}
else {
c->Message(Chat::White, "Guild leader changed: guild # %d, Leader: %s", id, sep->argplus[3]);
}
}
}
}
else if (strcasecmp(sep->arg[1], "list") == 0) {
if (admin < minStatusToEditOtherGuilds) {
c->Message(Chat::Red, "Access denied.");
return;
}
guild_mgr.ListGuilds(c);
}
else {
c->Message(Chat::White, "Unknown guild command, try #guild help");
}
}
/*
bool helper_guild_edit(Client *c, uint32 dbid, uint32 eqid, uint8 rank, const char* what, const char* value) {
struct GuildRankLevel_Struct grl;
strcpy(grl.rankname, guild_mgr.GetRankName(eqid, rank));
grl.demote = guilds[eqid].rank[rank].demote;
grl.heargu = guilds[eqid].rank[rank].heargu;
grl.invite = guilds[eqid].rank[rank].invite;
grl.motd = guilds[eqid].rank[rank].motd;
grl.promote = guilds[eqid].rank[rank].promote;
grl.remove = guilds[eqid].rank[rank].remove;
grl.speakgu = guilds[eqid].rank[rank].speakgu;
grl.warpeace = guilds[eqid].rank[rank].warpeace;
if (strcasecmp(what, "title") == 0) {
if (strlen(value) > 100)
c->Message(Chat::White, "Error: Title has a maxium length of 100 characters.");
else
strcpy(grl.rankname, value);
}
else if (rank == 0)
c->Message(Chat::White, "Error: Rank 0's permissions can not be changed.");
else {
if (!(strlen(value) == 1 && (value[0] == '0' || value[0] == '1')))
return false;
if (strcasecmp(what, "demote") == 0)
grl.demote = (value[0] == '1');
else if (strcasecmp(what, "heargu") == 0)
grl.heargu = (value[0] == '1');
else if (strcasecmp(what, "invite") == 0)
grl.invite = (value[0] == '1');
else if (strcasecmp(what, "motd") == 0)
grl.motd = (value[0] == '1');
else if (strcasecmp(what, "promote") == 0)
grl.promote = (value[0] == '1');
else if (strcasecmp(what, "remove") == 0)
grl.remove = (value[0] == '1');
else if (strcasecmp(what, "speakgu") == 0)
grl.speakgu = (value[0] == '1');
else if (strcasecmp(what, "warpeace") == 0)
grl.warpeace = (value[0] == '1');
else
c->Message(Chat::White, "Error: Permission name not recognized.");
}
if (!database.EditGuild(dbid, rank, &grl))
c->Message(Chat::White, "Error: database.EditGuild() failed");
return true;
}*/

View File

@ -0,0 +1,8 @@
#include "../client.h"
#include "../guild_mgr.h"
void command_guildapprove(Client *c, const Seperator *sep)
{
guild_mgr.AddMemberApproval(atoi(sep->arg[1]), c);
}

View File

@ -0,0 +1,13 @@
#include "../client.h"
#include "../guild_mgr.h"
void command_guildcreate(Client *c, const Seperator *sep)
{
if (strlen(sep->argplus[1]) > 4 && strlen(sep->argplus[1]) < 16) {
guild_mgr.AddGuildApproval(sep->argplus[1], c);
}
else {
c->Message(Chat::White, "Guild name must be more than 4 characters and less than 16.");
}
}

14
zone/gm_commands/guildlist.cpp Executable file
View File

@ -0,0 +1,14 @@
#include "../client.h"
#include "../guild_mgr.h"
void command_guildlist(Client *c, const Seperator *sep)
{
GuildApproval *tmp = guild_mgr.FindGuildByIDApproval(atoi(sep->arg[1]));
if (tmp) {
tmp->ApprovedMembers(c);
}
else {
c->Message(Chat::White, "Could not find reference id.");
}
}

37
zone/gm_commands/hair.cpp Executable file
View File

@ -0,0 +1,37 @@
#include "../client.h"
void command_hair(Client *c, const Seperator *sep)
{
Mob *target = c->GetTarget();
if (!sep->IsNumber(1)) {
c->Message(Chat::White, "Usage: #hair [number of hair style]");
}
else if (!target) {
c->Message(Chat::White, "Error: this command requires a target");
}
else {
uint16 Race = target->GetRace();
uint8 Gender = target->GetGender();
uint8 Texture = 0xFF;
uint8 HelmTexture = 0xFF;
uint8 HairColor = target->GetHairColor();
uint8 BeardColor = target->GetBeardColor();
uint8 EyeColor1 = target->GetEyeColor1();
uint8 EyeColor2 = target->GetEyeColor2();
uint8 HairStyle = atoi(sep->arg[1]);
uint8 LuclinFace = target->GetLuclinFace();
uint8 Beard = target->GetBeard();
uint32 DrakkinHeritage = target->GetDrakkinHeritage();
uint32 DrakkinTattoo = target->GetDrakkinTattoo();
uint32 DrakkinDetails = target->GetDrakkinDetails();
target->SendIllusionPacket(
Race, Gender, Texture, HelmTexture, HairColor, BeardColor,
EyeColor1, EyeColor2, HairStyle, LuclinFace, Beard, 0xFF,
DrakkinHeritage, DrakkinTattoo, DrakkinDetails
);
c->Message(Chat::White, "Hair = %i", atoi(sep->arg[1]));
}
}

37
zone/gm_commands/haircolor.cpp Executable file
View File

@ -0,0 +1,37 @@
#include "../client.h"
void command_haircolor(Client *c, const Seperator *sep)
{
Mob *target = c->GetTarget();
if (!sep->IsNumber(1)) {
c->Message(Chat::White, "Usage: #haircolor [number of hair color]");
}
else if (!target) {
c->Message(Chat::White, "Error: this command requires a target");
}
else {
uint16 Race = target->GetRace();
uint8 Gender = target->GetGender();
uint8 Texture = 0xFF;
uint8 HelmTexture = 0xFF;
uint8 HairColor = atoi(sep->arg[1]);
uint8 BeardColor = target->GetBeardColor();
uint8 EyeColor1 = target->GetEyeColor1();
uint8 EyeColor2 = target->GetEyeColor2();
uint8 HairStyle = target->GetHairStyle();
uint8 LuclinFace = target->GetLuclinFace();
uint8 Beard = target->GetBeard();
uint32 DrakkinHeritage = target->GetDrakkinHeritage();
uint32 DrakkinTattoo = target->GetDrakkinTattoo();
uint32 DrakkinDetails = target->GetDrakkinDetails();
target->SendIllusionPacket(
Race, Gender, Texture, HelmTexture, HairColor, BeardColor,
EyeColor1, EyeColor2, HairStyle, LuclinFace, Beard, 0xFF,
DrakkinHeritage, DrakkinTattoo, DrakkinDetails
);
c->Message(Chat::White, "Hair Color = %i", atoi(sep->arg[1]));
}
}

20
zone/gm_commands/haste.cpp Executable file
View File

@ -0,0 +1,20 @@
#include "../client.h"
void command_haste(Client *c, const Seperator *sep)
{
// #haste command to set client attack speed. Takes a percentage (100 = twice normal attack speed)
if (sep->arg[1][0] != 0) {
uint16 Haste = atoi(sep->arg[1]);
if (Haste > 85) {
Haste = 85;
}
c->SetExtraHaste(Haste);
// SetAttackTimer must be called to make this take effect, so player needs to change
// the primary weapon.
c->Message(Chat::White, "Haste set to %d%% - Need to re-equip primary weapon before it takes effect", Haste);
}
else {
c->Message(Chat::White, "Usage: #haste [percentage]");
}
}

15
zone/gm_commands/hatelist.cpp Executable file
View File

@ -0,0 +1,15 @@
#include "../client.h"
void command_hatelist(Client *c, const Seperator *sep)
{
Mob *target = c->GetTarget();
if (target == nullptr) {
c->Message(Chat::White, "Error: you must have a target.");
return;
}
c->Message(Chat::White, "Display hate list for %s..", target->GetName());
target->PrintHateListToClient(c);
}

21
zone/gm_commands/heal.cpp Executable file
View File

@ -0,0 +1,21 @@
#include "../client.h"
void command_heal(Client *c, const Seperator *sep)
{
auto target = c->GetTarget() ? c->GetTarget() : c;
target->Heal();
if (c != target) {
c->Message(
Chat::White,
fmt::format(
"Healed {} ({}) to full.",
target->GetCleanName(),
target->GetID()
).c_str()
);
}
else {
c->Message(Chat::White, "Healed yourself to full.");
}
}

37
zone/gm_commands/helm.cpp Executable file
View File

@ -0,0 +1,37 @@
#include "../client.h"
void command_helm(Client *c, const Seperator *sep)
{
Mob *target = c->GetTarget();
if (!sep->IsNumber(1)) {
c->Message(Chat::White, "Usage: #helm [number of helm texture]");
}
else if (!target) {
c->Message(Chat::White, "Error: this command requires a target");
}
else {
uint16 Race = target->GetRace();
uint8 Gender = target->GetGender();
uint8 Texture = 0xFF;
uint8 HelmTexture = atoi(sep->arg[1]);
uint8 HairColor = target->GetHairColor();
uint8 BeardColor = target->GetBeardColor();
uint8 EyeColor1 = target->GetEyeColor1();
uint8 EyeColor2 = target->GetEyeColor2();
uint8 HairStyle = target->GetHairStyle();
uint8 LuclinFace = target->GetLuclinFace();
uint8 Beard = target->GetBeard();
uint32 DrakkinHeritage = target->GetDrakkinHeritage();
uint32 DrakkinTattoo = target->GetDrakkinTattoo();
uint32 DrakkinDetails = target->GetDrakkinDetails();
target->SendIllusionPacket(
Race, Gender, Texture, HelmTexture, HairColor, BeardColor,
EyeColor1, EyeColor2, HairStyle, LuclinFace, Beard, 0xFF,
DrakkinHeritage, DrakkinTattoo, DrakkinDetails
);
c->Message(Chat::White, "Helm = %i", atoi(sep->arg[1]));
}
}

37
zone/gm_commands/heritage.cpp Executable file
View File

@ -0,0 +1,37 @@
#include "../client.h"
void command_heritage(Client *c, const Seperator *sep)
{
Mob *target = c->GetTarget();
if (!sep->IsNumber(1)) {
c->Message(Chat::White, "Usage: #heritage [number of Drakkin heritage]");
}
else if (!target) {
c->Message(Chat::White, "Error: this command requires a target");
}
else {
uint16 Race = target->GetRace();
uint8 Gender = target->GetGender();
uint8 Texture = 0xFF;
uint8 HelmTexture = 0xFF;
uint8 HairColor = target->GetHairColor();
uint8 BeardColor = target->GetBeardColor();
uint8 EyeColor1 = target->GetEyeColor1();
uint8 EyeColor2 = target->GetEyeColor2();
uint8 HairStyle = target->GetHairStyle();
uint8 LuclinFace = target->GetLuclinFace();
uint8 Beard = target->GetBeard();
uint32 DrakkinHeritage = atoi(sep->arg[1]);
uint32 DrakkinTattoo = target->GetDrakkinTattoo();
uint32 DrakkinDetails = target->GetDrakkinDetails();
target->SendIllusionPacket(
Race, Gender, Texture, HelmTexture, HairColor, BeardColor,
EyeColor1, EyeColor2, HairStyle, LuclinFace, Beard, 0xFF,
DrakkinHeritage, DrakkinTattoo, DrakkinDetails
);
c->Message(Chat::White, "Heritage = %i", atoi(sep->arg[1]));
}
}

35
zone/gm_commands/heromodel.cpp Executable file
View File

@ -0,0 +1,35 @@
#include "../client.h"
void command_heromodel(Client *c, const Seperator *sep)
{
if (sep->argnum < 1) {
c->Message(Chat::White, "Usage: #heromodel [hero forge model] [ [slot] ] (example: #heromodel 63)");
}
else if (c->GetTarget() == nullptr) {
c->Message(Chat::Red, "You must have a target to do a wear change for Hero's Forge Models.");
}
else {
uint32 hero_forge_model = atoi(sep->arg[1]);
if (sep->argnum > 1) {
uint8 wearslot = (uint8) atoi(sep->arg[2]);
c->GetTarget()->SendTextureWC(wearslot, 0, hero_forge_model, 0, 0, 0);
}
else {
if (hero_forge_model > 0) {
// Conversion to simplify the command arguments
// Hero's Forge model is actually model * 1000 + texture * 100 + wearslot
// Hero's Forge Model slot 7 is actually for Robes, but it still needs to use wearslot 1 in the packet
hero_forge_model *= 100;
for (uint8 wearslot = 0; wearslot < 7; wearslot++) {
c->GetTarget()->SendTextureWC(wearslot, 0, (hero_forge_model + wearslot), 0, 0, 0);
}
}
else {
c->Message(Chat::Red, "Hero's Forge Model must be greater than 0.");
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More