1
0
Emagi 5ef2458026 Rule support for R_Combat, MaxChaseDistance and info struct float max_chase_distance
Rule support for R_Combat, MaxChaseDistance to restrict by server or zone the max chase distance instead of hardcoded 80.0.
Additionally GetInfoStruct float max_chase_distance added.

info struct takes precident when set greater than 0.0 for the max chase distance, otherwise we check the rule being greater than 0.0, otherwise we use the default 80 in the hardcode define
2025-05-06 19:48:01 -04:00

539 lines
27 KiB
C++

/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "../../common/debug.h"
#include "../../common/Log.h"
#include "../../common/database.h"
#include "Rules.h"
extern RuleManager rule_manager;
Rule::Rule() {
category = 0;
type = 0;
strncpy(value, "", sizeof(value));
strncpy(combined, "NONE", sizeof(combined));
}
Rule::Rule(int32 category, int32 type, const char *value, const char *combined) {
this->category = category;
this->type = type;
strncpy(this->value, value, sizeof(this->value));
strncpy(this->combined, combined, sizeof(this->combined));
}
Rule::Rule (Rule *rule_in) {
category = rule_in->GetCategory();
type = rule_in->GetType();
strncpy(value, rule_in->GetValue(), sizeof(value));
strncpy(combined, rule_in->GetCombined(), sizeof(combined));
}
Rule::~Rule() {
}
RuleSet::RuleSet() {
id = 0;
memset(name, 0, sizeof(name));
m_rules.SetName("RuleSet::rules");
}
RuleSet::RuleSet(RuleSet *in_rule_set) {
assert(in_rule_set);
map<int32, map<int32, Rule *> > * in_rules = in_rule_set->GetRules();
map<int32, map<int32, Rule *> >::iterator itr;
map<int32, Rule *>::iterator itr2;
Rule * rule;
m_rules.SetName("RuleSet::rules");
id = in_rule_set->GetID();
strncpy(name, in_rule_set->GetName(), sizeof(name));
for (itr = in_rules->begin(); itr != in_rules->end(); itr++) {
for (itr2 = itr->second.begin(); itr2 != itr->second.end(); itr2++) {
rule = itr2->second;
rules[rule->GetCategory()][rule->GetType()] = new Rule(rule);
}
}
}
RuleSet::~RuleSet() {
ClearRules();
}
void RuleSet::CopyRulesInto(RuleSet *in_rule_set) {
assert(in_rule_set);
map<int32, map<int32, Rule *> > * in_rules = in_rule_set->GetRules();
map<int32, map<int32, Rule *> >::iterator itr;
map<int32, Rule *>::iterator itr2;
Rule * rule;
ClearRules();
m_rules.writelock(__FUNCTION__, __LINE__);
for (itr = in_rules->begin(); itr != in_rules->end(); itr++) {
for (itr2 = itr->second.begin(); itr2 != itr->second.end(); itr2++) {
rule = itr2->second;
rules[rule->GetCategory()][rule->GetType()] = new Rule(rule);
}
}
m_rules.releasewritelock(__FUNCTION__, __LINE__);
}
void RuleSet::AddRule(Rule *rule) {
int32 category, type;
assert(rule);
category = rule->GetCategory();
type = rule->GetType();
m_rules.writelock(__FUNCTION__, __LINE__);
if (rules[category].count(type) == 0)
rules[category][type] = rule;
else
rules[category][type]->SetValue(rule->GetValue());
m_rules.releasewritelock(__FUNCTION__, __LINE__);
}
Rule * RuleSet::GetRule(int32 category, int32 type) {
Rule *ret = 0;
m_rules.readlock(__FUNCTION__, __LINE__);
if (rules[category].count(type) > 0)
ret = rules[category][type];
m_rules.releasereadlock(__FUNCTION__, __LINE__);
if (!ret)
ret = rule_manager.GetBlankRule();
LogWrite(RULESYS__DEBUG, 5, "Rules", "Rule: %s, Value: %s", ret->GetCombined(), ret->GetValue());
return ret;
}
Rule * RuleSet::GetRule(const char *category, const char *type) {
map<int32, map<int32, Rule *> >::iterator itr;
map<int32, Rule *>::iterator itr2;
char combined[256];
Rule *ret = 0;
snprintf(combined, sizeof(combined), "%s:%s", category, type);
// Zero terminate ([max - 1] = 0) to prevent a warning/error
combined[255] = 0;
m_rules.readlock(__FUNCTION__, __LINE__);
for (itr = rules.begin(); itr != rules.end(); itr++) {
for (itr2 = itr->second.begin(); itr2 != itr->second.end(); itr2++) {
if (!strcmp(itr2->second->GetCombined(), combined)) {
ret = itr2->second;
break;
}
}
}
m_rules.releasereadlock(__FUNCTION__, __LINE__);
return ret;
}
void RuleSet::ClearRules() {
map<int32, map<int32, Rule *> >::iterator itr;
map<int32, Rule *>::iterator itr2;
m_rules.writelock(__FUNCTION__, __LINE__);
for (itr = rules.begin(); itr != rules.end(); itr++) {
for (itr2 = itr->second.begin(); itr2 != itr->second.end(); itr2++)
safe_delete(itr2->second);
}
rules.clear();
m_rules.releasewritelock(__FUNCTION__, __LINE__);
}
RuleManager::RuleManager() {
m_rule_sets.SetName("RuleManager::rule_sets");
m_global_rule_set.SetName("RuleManager::global_rule_set");
m_zone_rule_sets.SetName("RuleManager::zone_rule_sets");
Init();
}
RuleManager::~RuleManager() {
Flush();
}
void RuleManager::Init()
{
#define RULE_INIT(category, type, value) rules[category][type] = new Rule(category, type, value, #category ":" #type)
/* CLIENT */
RULE_INIT(R_Client, ShowWelcomeScreen, "0");
RULE_INIT(R_Client, GroupSpellsTimer, "1000");
RULE_INIT(R_Client, QuestQueueTimer, "50"); // in milliseconds
/* FACTION */
RULE_INIT(R_Faction, AllowFactionBasedCombat, "1");
/* GUILD */
RULE_INIT(R_Guild, MaxLevel, "50");
RULE_INIT(R_Guild, MaxPlayers, "-1");
/* PLAYER */
RULE_INIT(R_Player, MaxLevel, "50");
RULE_INIT(R_Player, MaxLevelOverrideStatus, "100");
RULE_INIT(R_Player, VitalityAmount, ".5");
RULE_INIT(R_Player, VitalityFrequency, "3600");
RULE_INIT(R_Player, XPMultiplier, "1.0");
RULE_INIT(R_Player, TSXPMultiplier, "1.0");
RULE_INIT(R_Player, MaxAA, "320");
RULE_INIT(R_Player, MaxClassAA, "100");
RULE_INIT(R_Player, MaxSubclassAA, "100");
RULE_INIT(R_Player, MaxShadowsAA, "70");
RULE_INIT(R_Player, MaxHeroicAA, "50");
RULE_INIT(R_Player, MaxTradeskillAA, "40");
RULE_INIT(R_Player, MaxPrestigeAA, "25");
RULE_INIT(R_Player, MaxTradeskillPrestigeAA, "25");
RULE_INIT(R_Player, MinLastNameLevel, "20");
RULE_INIT(R_Player, MaxLastNameLength, "20");
RULE_INIT(R_Player, MinLastNameLength, "4");
RULE_INIT(R_Player, DisableHouseAlignmentRequirement, "1");
RULE_INIT(R_Player, MentorItemDecayRate, ".05"); // 5% per level lost when mentoring
RULE_INIT(R_Player, TemporaryItemLogoutTime, "1800.0"); // time in seconds (double) for temporary item to decay after being logged out for a period of time, 30 min is the default
RULE_INIT(R_Player, HeirloomItemShareExpiration, "172800.0"); // 2 days ('48 hours') in seconds
RULE_INIT(R_Player, SwimmingSkillMinSpeed, "20");
RULE_INIT(R_Player, SwimmingSkillMaxSpeed, "200");
RULE_INIT(R_Player, SwimmingSkillMinBreathLength, "30");
RULE_INIT(R_Player, SwimmingSkillMaxBreathLength, "1000");
RULE_INIT(R_Player, AutoSkillUpBaseSkills, "0"); // when set to 1 we auto skill to max value on levelling up for armor,shield,class,weapon skills
RULE_INIT(R_Player, MaxWeightStrengthMultiplier, "2.0"); // multiplier for strength to add to max weight, eg 25 str * 2.0 = 50 max weight + base weight
RULE_INIT(R_Player, BaseWeight, "50"); // base weight per class, added to max weight with the strength multiplier
RULE_INIT(R_Player, WeightPercentImpact, "0.01"); // overweight in stone speed impact (.01 = 1% per 1 stone)
RULE_INIT(R_Player, WeightPercentCap, "0.95"); // cap total impact for being overweight (.95 = 95%)
RULE_INIT(R_Player, CoinWeightPerStone, "40.0"); // coin weight per stone, 40.0 = 40 coins per 1 stone (per DoF client hover over)
RULE_INIT(R_Player, WeightInflictsSpeed, "1"); // whether weight will inflict speed, 1 = on, 0 = off
RULE_INIT(R_Player, LevelMasterySkillMultiplier, "5"); // multiplier for adventure level / recommended level when applying mastery damage to determine if they are in mastery range
RULE_INIT(R_Player, TraitTieringSelection, "1"); // when set to true limited to single trait per group, otherwise you can freely select from any group
RULE_INIT(R_Player, ClassicTraitLevelTable, "1"); // uses built in table based on Prima Guide, see Traits.cpp for more, otherwise uses the levels below
RULE_INIT(R_Player, TraitFocusSelectLevel, "9"); // x levels to receive new trait of focus, eg level/rule, level 10, rule value 5, 10/5 = 2 focus traits available at level 10
RULE_INIT(R_Player, TraitTrainingSelectLevel, "10"); // x levels to receive new trait of focus
RULE_INIT(R_Player, TraitRaceSelectLevel, "10"); // x levels to receive new trait of focus
RULE_INIT(R_Player, TraitCharacterSelectLevel, "10"); // x levels to receive new trait of focus
RULE_INIT(R_Player, StartHPBase, "40");
RULE_INIT(R_Player, StartPowerBase, "45");
RULE_INIT(R_Player, StartHPLevelMod, "2.0");
RULE_INIT(R_Player, StartPowerLevelMod, "2.1");
RULE_INIT(R_Player, AllowPlayerEquipCombat, "1");
RULE_INIT(R_Player, MaxTargetCommandDistance, "50.0"); // max distance allowed for /target command when target name is not in group
RULE_INIT(R_Player, MinSkillMultiplierValue, "30"); // min skill we use as a multiplier to note the max skill allowed by the node
RULE_INIT(R_Player, HarvestSkillUpMultiplier, "2.0"); /* multiplier for node to take the "min skill" max and use a multiplier to offset the max skill allowed to skill up on node.
** Eg. 50 min skill on node, 50*1.5=75, no one with higher than 75 skill gets a skill up
*/
/* PVP */
RULE_INIT(R_PVP, AllowPVP, "0");
RULE_INIT(R_PVP, LevelRange, "4");
RULE_INIT(R_PVP, InvisPlayerDiscoveryRange, "20"); // value > 0 sets radius inner to see, = 0 means always seen, -1 = never seen
RULE_INIT(R_PVP, PVPMitigationModByLevel, "25"); // gives a bonus to mitigation for PVP combat to offset the percentage level * mod (default 25)
RULE_INIT(R_PVP, PVPType, "0"); // 0 = FFA, 1 = PVPAlignment (Bind zone), 2 = Alignment (assigned via LUA function SetAlignment)
/* COMBAT */
RULE_INIT(R_Combat, MaxCombatRange, "4.0");
RULE_INIT(R_Combat, DeathExperienceDebt, "50.00"); // divide by 100, 50/100 = .5% debt per pve death
RULE_INIT(R_Combat, PVPDeathExperienceDebt, "25.00"); // divide by 100, 25/100 = .25% debt per pvp death
RULE_INIT(R_Combat, GroupExperienceDebt, "0"); // set to 1 means we will share debt between the group
RULE_INIT(R_Combat, ExperienceToDebt, "50.00"); // percentage of xp earned to debt vs obtained xp 50/100 = 50% to debt
RULE_INIT(R_Combat, ExperienceDebtRecoveryPercent, "5.00"); // recovery percentage per period of time, 5/100 = 5% recovered (so if .5% debt, .5*.05 = .025, .5-.025=.475% debt left)
RULE_INIT(R_Combat, ExperienceDebtRecoveryPeriod, "600"); // every 10 minutes (x*60 seconds) recover ExperienceDebtRecoveryPercent
RULE_INIT(R_Combat, EnableSpiritShards, "1");
RULE_INIT(R_Combat, SpiritShardSpawnScript, "SpawnScripts/Generic/SpiritShard.lua");
RULE_INIT(R_Combat, ShardDebtRecoveryPercent, "25.00"); // recovered percentage of debt upon obtainig shard, 25/100 means 25%. If there is .5 DeathExperienceDebt, .5*25% = .125, .5 - .125 = .375
RULE_INIT(R_Combat, ShardRecoveryByRadius, "1"); // allow shards to auto pick up by radius, not requiring to click/right click the shard
RULE_INIT(R_Combat, ShardLifetime, "86400"); // default: 86400 seconds (one day)
RULE_INIT(R_Combat, EffectiveMitigationCapLevel, "80"); // level multiplier for max effective cap, level * 80 (default)
RULE_INIT(R_Combat, CalculatedMitigationCapLevel, "100"); // The cap to calculate your mitigation from is [level*100].
RULE_INIT(R_Combat, MitigationLevelEffectivenessMax, "1.5"); // ratio victim level / attacker level for max effectiveness, when victim is higher level cap can reach 1.5
RULE_INIT(R_Combat, MitigationLevelEffectivenessMin, ".5"); // ratio victim level / attacker level for min effectiveness
RULE_INIT(R_Combat, MaxMitigationAllowed, ".75"); // percentage max mitigation allowed, eg. 75% of damage can be mitigated max in PVE
RULE_INIT(R_Combat, MaxMitigationAllowedPVP, ".75"); // percentage max mitigation allowed, eg. 75% of damage can be mitigated max in PVP
RULE_INIT(R_Combat, StrengthNPC, "10"); // divider for strength NPC only str/x = additional dmg to low/high dmg
RULE_INIT(R_Combat, StrengthOther, "25"); // divider for strength other than NPC str/x = additional dmg to low/high dmg
RULE_INIT(R_Combat, MaxSkillBonusByLevel, "1.5"); // Level * 1.5 = max bonus skill allowed
RULE_INIT(R_Combat, LockedEncounterNoAttack, "1"); // when set to 1, players/group members not part of the encounter cannot attack until /yell
RULE_INIT(R_Combat, MaxChaseDistance, "0.0"); // Default is 0, uses hard coded define MAX_CHASE_DISTANCE of 80.0. If set then this is an override for zone/server level.
/* SPAWN */
RULE_INIT(R_Spawn, SpeedMultiplier, "300"); // note: this value was 1280 until 6/1/2009, then was 600 til Sep 2009, when it became 300...?
RULE_INIT(R_Spawn, ClassicRegen, "0");
RULE_INIT(R_Spawn, HailMovementPause, "5000"); // time in milliseconds the spawn is paused on hail
RULE_INIT(R_Spawn, HailDistance, "5"); // max distance to hail a spawn/npc
RULE_INIT(R_Spawn, UseHardCodeWaterModelType, "1"); // uses alternate method of setting water type by model type (hardcoded) versus relying on just DB
RULE_INIT(R_Spawn, UseHardCodeFlyingModelType, "1"); // uses alternate method of setting flying type by model type (hardcoded) versus relying on just DB
/* TIMER */
/* UI */
RULE_INIT(R_UI, MaxWhoResults, "20");
RULE_INIT(R_UI, MaxWhoOverrideStatus, "200");
/* WORLD */
RULE_INIT(R_World, DefaultStartingZoneID, "1");
RULE_INIT(R_World, EnablePOIDiscovery, "0");
RULE_INIT(R_World, GamblingTokenItemID, "2");
RULE_INIT(R_World, GuildAutoJoin, "0");
RULE_INIT(R_World, GuildAutoJoinID, "1");
RULE_INIT(R_World, GuildAutoJoinDefaultRankID, "7");
RULE_INIT(R_World, MaxPlayers, "-1");
RULE_INIT(R_World, MaxPlayersOverrideStatus, "100");
RULE_INIT(R_World, ServerLocked, "0");
RULE_INIT(R_World, ServerLockedOverrideStatus, "10");
RULE_INIT(R_World, SyncZonesWithLogin, "1");
RULE_INIT(R_World, SyncEquipWithLogin, "1");
RULE_INIT(R_World, UseBannedIPsTable, "0");
RULE_INIT(R_World, LinkDeadTimer, "120000"); // default: 2 minutes
RULE_INIT(R_World, RemoveDisconnectedClientsTimer, "30000"); // default: 30 seconds
RULE_INIT(R_World, PlayerCampTimer, "20"); // default: 20 seconds
RULE_INIT(R_World, GMCampTimer, "1"); // default: 1 second
RULE_INIT(R_World, AutoAdminPlayers, "0"); // default: No
RULE_INIT(R_World, AutoAdminGMs, "0"); // default: No
RULE_INIT(R_World, AutoAdminStatusValue, "10"); // default: 10 (CSR)
RULE_INIT(R_World, DuskTime, "20:00"); // default: 8pm
RULE_INIT(R_World, DawnTime, "8:00"); // default: 8am
RULE_INIT(R_World, ThreadedLoad, "0"); // default: no threaded loading
RULE_INIT(R_World, TradeskillSuccessChance, "87.0"); // default: 87% chance of success while crafting
RULE_INIT(R_World, TradeskillCritSuccessChance, "2.0"); // default: 2% chance of critical success while crafting
RULE_INIT(R_World, TradeskillFailChance, "10.0"); // default: 10% chance of failure while crafting
RULE_INIT(R_World, TradeskillCritFailChance, "1.0"); // default: 1% chance of critical failure while crafting
RULE_INIT(R_World, TradeskillEventChance, "15.0"); // default: 15% chance of a tradeskill event while crafting
RULE_INIT(R_World, EditorURL, "www.eq2emulator.net"); // default: www.eq2emulator.net
RULE_INIT(R_World, EditorIncludeID, "0"); // default: 0 (0 = disabled, 1 = enabled)
RULE_INIT(R_World, EditorOfficialServer, "0"); // default: 0 (0 = disabled, 1 = enabled)
RULE_INIT(R_World, SavePaperdollImage, "1"); // default: true
RULE_INIT(R_World, SaveHeadshotImage, "1"); // default: true
RULE_INIT(R_World, SendPaperdollImagesToLogin, "1"); // default: true
RULE_INIT(R_World, TreasureChestDisabled, "0"); // default: false
RULE_INIT(R_World, StartingZoneLanguages, "0"); // default: 0 (0 = Live Like, 1 = Starting City Based)
RULE_INIT(R_World, StartingZoneRuleFlag, "0"); // default: 0 - match any options available, just based on version/other fields (will not force qc/outpost)
// 1 - force split zones on alignment/deity despite client selection (queens colony/overlord outpost)
// 4 - send to 'new' starting zones, won't support old clients
// 8 - (isle of refuge)
RULE_INIT(R_World, EnforceRacialAlignment, "1");
RULE_INIT(R_World, MemoryCacheZoneMaps, "0"); // 0 disables caching the zone maps in memory, too many individual/unique zones entered may cause a lot of memory build up
RULE_INIT(R_World, AutoLockEncounter, "0"); // When set to 0 we require player to attack to lock the encounter, otherwise if 1 then npc can auto lock encounter
RULE_INIT(R_World, DisplayItemTiers, "1"); // Display item tiers when set to 1, otherwise do not
RULE_INIT(R_World, LoreAndLegendAccept, "0"); // default: 0 - L&L quests accepted only through starter books. 1 - L&L quests can be started by examining bodyparts.
//INSERT INTO `ruleset_details`(`id`, `ruleset_id`, `rule_category`, `rule_type`, `rule_value`, `description`) VALUES (NULL, '1', 'R_World', '', '', '')
/* ZONE */
RULE_INIT(R_Zone, MaxPlayers, "100");
RULE_INIT(R_Zone, MinZoneLevelOverrideStatus, "1");
RULE_INIT(R_Zone, MinZoneAccessOverrideStatus, "100");
RULE_INIT(R_Zone, WeatherEnabled, "1"); // default: 1 (0 = disabled, 1 = enabled)
RULE_INIT(R_Zone, WeatherType, "0"); // default: 1 (0 = normal, 1 = dynamic, 2 = random, 3 = chaotic)
RULE_INIT(R_Zone, MinWeatherSeverity, "0.0"); // default: 0.0 or no weather
RULE_INIT(R_Zone, MaxWeatherSeverity, "1.0"); // default: 1.0 or hard rain (range 0.0 - 1.0, rain starts at 0.75)
RULE_INIT(R_Zone, WeatherChangeFrequency, "300"); // default: 5 minutes
RULE_INIT(R_Zone, WeatherChangePerInterval, "0.02"); // default: 0.02 (slight changes)
RULE_INIT(R_Zone, WeatherChangeChance, "20"); // default: 20% (in whole percents)
RULE_INIT(R_Zone, WeatherDynamicMaxOffset, "0.08"); // default: 0.08 - dynamic weather changes can only change this max amount
RULE_INIT(R_Zone, SpawnUpdateTimer, "50"); // default: 50ms - how often to check for spawn update sends
RULE_INIT(R_Zone, CheckAttackNPC, "2000"); // default: 2 seconds, how often to for NPCs to attack eachother
RULE_INIT(R_Zone, CheckAttackPlayer, "2000"); // default: 2 seconds, how often to check for NPCs to attack players
RULE_INIT(R_Zone, HOTime, "10.0"); // default: 10 seconds, time to complete the HO wheel before it expires
/* ZONE TIMERS */
RULE_INIT(R_Zone, RegenTimer, "6000");
RULE_INIT(R_Zone, ClientSaveTimer, "60000");
RULE_INIT(R_Zone, ShutdownDelayTimer, "120000");
RULE_INIT(R_Zone, WeatherTimer, "60000"); // default: 1 minute
RULE_INIT(R_Zone, SpawnDeleteTimer, "30000"); // default: 30 seconds, how long a spawn pointer is held onto after being removed from the world before deleting it
RULE_INIT(R_Zone, UseMapUnderworldCoords, "1"); // use maps lowest Y coordinate to establish underworld markers
RULE_INIT(R_Zone, MapUnderworldCoordOffset, "-200.0"); // adds (or in the case of negative value subtracts) so that the underworld marker is lower when map is using its lowest Y coordinate
RULE_INIT(R_Zone, SharedZoneMaxPlayers, "30"); // max players in a shared zone (non instanced) before splitting to another zone, city_zone flagged are exempt
RULE_INIT(R_Loot, LootRadius, "5.0");
RULE_INIT(R_Loot, AutoDisarmChest, "1");
RULE_INIT(R_Loot, ChestTriggerRadiusGroup, "10.0"); // radius at which chest will trigger against group members
RULE_INIT(R_Loot, ChestUnlockedTimeDrop, "1200"); // time in seconds, 20 minutes by default, triggers only if AllowChestUnlockByDropTime is 1
RULE_INIT(R_Loot, AllowChestUnlockByDropTime, "1"); // when set to 1 we will start a countdown timer to allow anyone to loot once ChestUnlockedTimeDrop elapsed
RULE_INIT(R_Loot, ChestUnlockedTimeTrap, "600"); // time in seconds, 10 minutes by default
RULE_INIT(R_Loot, AllowChestUnlockByTrapTime, "1"); // when set to 1 we will allow unlocking the chest to all players after the trap is triggered (or chest is open) and period ChestUnlockedTimeTrap elapsed
RULE_INIT(R_Loot, SkipLootGrayMob, "1");
RULE_INIT(R_Loot, LootDistributionTime, "120"); // time in seconds that we allow the group to determine their loot decision (lotto/need/greed/decline).
RULE_INIT(R_Spells, NoInterruptBaseChance, "50");
RULE_INIT(R_Spells, EnableFizzleSpells, "1"); // enables/disables the 'fizzling' of spells based on can_fizzle in the spells table. This also enables increasing specialized skills for classes based on spells/abilities.
RULE_INIT(R_Spells, DefaultFizzleChance, "10.0"); // default percentage x / 100, eg 10% is 10.0
RULE_INIT(R_Spells, FizzleMaxSkill, "1.2"); // 1.0 is 100%, 1.2 is 120%, so you get 120% your max skill against a spell, no fizzle
RULE_INIT(R_Spells, FizzleDefaultSkill, ".2"); // offset against MaxSkill to average out to 100%, default of .2f so we don't go over the threshold if no skill
RULE_INIT(R_Spells, EnableCrossZoneGroupBuffs, "0"); // enables/disables allowing cross zone group buffs
RULE_INIT(R_Spells, EnableCrossZoneTargetBuffs, "0"); // enables/disables allowing cross zone target buffs
RULE_INIT(R_Spells, PlayerSpellSaveStateWaitInterval, "100"); // time in milliseconds we wait before performing a save when the spell save trigger is activated, allows additional actions to take place until the cap is hit
RULE_INIT(R_Spells, PlayerSpellSaveStateCap, "1000"); // sets a maximum wait time before we queue a spell state save to the DB, given a lot can go on in a short period with players especially in combat, maybe good to have this at a higher interval.
RULE_INIT(R_Spells, RequirePreviousTierScribe, "0"); // requires step up apprentice -> apprentice (handcrafted?) -> journeyman (handcrafted?) -> adept -> expert -> master
RULE_INIT(R_Spells, CureSpellID, "110003"); // Base Cure spell that was used after they removed cure types
RULE_INIT(R_Spells, CureCurseSpellID, "110004"); // Curse Spell ID in the spells database
RULE_INIT(R_Spells, CureNoxiousSpellID, "110005"); // Noxious/Poison Spell ID in the spells database
RULE_INIT(R_Spells, CureMagicSpellID, "210006"); // Magic/Elemental Spell ID in the spells database
RULE_INIT(R_Spells, CureTraumaSpellID, "0"); // Trauma/Mental Spell ID in the spells database
RULE_INIT(R_Spells, CureArcaneSpellID, "0"); // Arcane/Heat Spell ID in the spells database
RULE_INIT(R_Spells, MinistrationSkillID, "366253016"); // ministration skill id used to map power reduction rule MinistrationPowerReductionMax
RULE_INIT(R_Spells, MinistrationPowerReductionMax, "15.0"); // max percentage of power reduction for spells with ministration mastery skill (default is 15.0 for 15%)
RULE_INIT(R_Spells, MinistrationPowerReductionSkill, "25"); // divides by integer value to establish how much skill req for higher power reduction
RULE_INIT(R_Spells, MasterSkillReduceSpellResist, "25"); // divides by integer value to establish how much skill bonus for reducing spell resistance on target
RULE_INIT(R_Spells, UseClassicSpellLevel, "0"); // Uses fractional spell levels (eg. you gain spells inbetween levels).
RULE_INIT(R_Expansion, GlobalExpansionFlag, "0");
RULE_INIT(R_Expansion, GlobalHolidayFlag, "0");
RULE_INIT(R_World, DatabaseVersion, "0");
//devn00b
RULE_INIT(R_Discord, DiscordEnabled, "0"); //Enable/Disable built in discord bot.
RULE_INIT(R_Discord, DiscordWebhookURL, "None"); //Webhook url used for server -> discord messages.
RULE_INIT(R_Discord, DiscordBotToken, "None"); //Bot token used to connect to discord and provides discord -> server messages.
RULE_INIT(R_Discord, DiscordChannel, "Discord"); // in-game channel used for server -> discord messages.
RULE_INIT(R_Discord, DiscordListenChan, "0"); // Discord ChannelID used for discord->server messages.
#undef RULE_INIT
}
void RuleManager::Flush(bool reinit)
{
map<int32, map<int32, Rule*> >::iterator itr;
map<int32, Rule*>::iterator itr2;
for (itr = rules.begin(); itr != rules.end(); itr++) {
for (itr2 = itr->second.begin(); itr2 != itr->second.end(); itr2++)
safe_delete(itr2->second);
}
rules.clear();
ClearRuleSets();
ClearZoneRuleSets();
if (reinit)
Init();
}
void RuleManager::LoadCodedDefaultsIntoRuleSet(RuleSet *rule_set) {
map<int32, map<int32, Rule *> >::iterator itr;
map<int32, Rule *>::iterator itr2;
assert(rule_set);
for (itr = rules.begin(); itr != rules.end(); itr++) {
for (itr2 = itr->second.begin(); itr2 != itr->second.end(); itr2++)
rule_set->AddRule(new Rule(itr2->second));
}
}
bool RuleManager::AddRuleSet(RuleSet *rule_set) {
bool ret = false;
int32 id;
assert(rule_set);
id = rule_set->GetID();
m_rule_sets.writelock(__FUNCTION__, __LINE__);
if (rule_sets.count(id) == 0) {
rule_sets[id] = rule_set;
ret = true;
}
m_rule_sets.releasewritelock(__FUNCTION__, __LINE__);
return ret;
}
int32 RuleManager::GetNumRuleSets() {
int32 ret;
m_rule_sets.readlock(__FUNCTION__, __LINE__);
ret = rule_sets.size();
m_rule_sets.releasereadlock(__FUNCTION__, __LINE__);
return ret;
}
void RuleManager::ClearRuleSets() {
map<int32, RuleSet *>::iterator itr;
m_rule_sets.writelock(__FUNCTION__, __LINE__);
for (itr = rule_sets.begin(); itr != rule_sets.end(); itr++)
safe_delete(itr->second);
rule_sets.clear();
m_rule_sets.releasewritelock(__FUNCTION__, __LINE__);
}
bool RuleManager::SetGlobalRuleSet(int32 rule_set_id) {
if (rule_sets.count(rule_set_id) == 0)
return false;
global_rule_set.CopyRulesInto(rule_sets[rule_set_id]);
return true;
}
Rule * RuleManager::GetGlobalRule(int32 category, int32 type) {
return global_rule_set.GetRule(category, type);
}
Rule * RuleManager::GetGlobalRule(const char* category, const char* type) {
return global_rule_set.GetRule(category, type);
}
bool RuleManager::SetZoneRuleSet(int32 zone_id, int32 rule_set_id) {
bool ret = true;
RuleSet *rule_set;
m_rule_sets.readlock(__FUNCTION__, __LINE__);
if (rule_sets.count(rule_set_id) == 0)
ret = false;
rule_set = rule_sets[rule_set_id];
if (ret) {
m_zone_rule_sets.writelock(__FUNCTION__, __LINE__);
zone_rule_sets[zone_id] = rule_set;
m_zone_rule_sets.releasewritelock(__FUNCTION__, __LINE__);
}
m_rule_sets.releasereadlock(__FUNCTION__, __LINE__);
return ret;
}
Rule * RuleManager::GetZoneRule(int32 zone_id, int32 category, int32 type) {
Rule *ret = 0;
/* first try to get the zone rule */
if(zone_id) {
m_zone_rule_sets.readlock(__FUNCTION__, __LINE__);
if (zone_rule_sets.count(zone_id) > 0)
ret = zone_rule_sets[zone_id]->GetRule(category, type);
m_zone_rule_sets.releasereadlock(__FUNCTION__, __LINE__);
}
if(!ret) {
ret = GetGlobalRule(category, type);
}
return ret;
}
void RuleManager::ClearZoneRuleSets() {
m_zone_rule_sets.writelock(__FUNCTION__, __LINE__);
zone_rule_sets.clear();
m_zone_rule_sets.releasewritelock(__FUNCTION__, __LINE__);
}