One word about the previous hooks (and some coming others) : I did not indent the hook code as should normally be. the reason is that it avoids getting changes in diffs on all the regular code I enclosed in "ifs".
|
Hook 3 : More item bonuses computation
Index: bonuses.cpp
================================================== ================= RCS file: /cvsroot/eqemulator/EQEmuCVS/Source/zone/bonuses.cpp,v retrieving revision 1.7.2.15 diff -u -b -B -r1.7.2.15 bonuses.cpp --- bonuses.cpp 21 Feb 2007 16:04:20 -0000 1.7.2.15 +++ bonuses.cpp 2 Mar 2008 09:06:47 -0000 @@ -25,6 +25,7 @@ #include "../common/skills.h" #include "../common/bodytypes.h" #include "../common/classes.h" +#include "../common/rulesys.h" #include <math.h> #include <assert.h> #ifndef WIN32 @@ -277,6 +278,9 @@ for(i = 0; i < MAX_AUGMENT_SLOTS; i++) { AddItemBonuses(inst->GetAugment(i),newbon); } + + if(RuleH(Character, PostAddItemBonuses) != NULL) + ((Hook_Character_PostAddItemBonuses) RuleH(Character, PostAddItemBonuses))(inst, newbon); } void Client::CalcEdibleBonuses(StatBonuses* newbon) { |
Hook 4 : Tweak skill-up chance
Index: client.cpp
================================================== ================= RCS file: /cvsroot/eqemulator/EQEmuCVS/Source/zone/client.cpp,v retrieving revision 1.36.2.51 diff -u -b -B -r1.36.2.51 client.cpp --- client.cpp 21 Feb 2007 16:04:20 -0000 1.36.2.51 +++ client.cpp 2 Mar 2008 09:08:20 -0000 @@ -1654,9 +1654,15 @@ if (skillval < maxskill) { // the higher your current skill level, the harder it is - sint16 Chance = 10 + chancemodi + ((252 - skillval) / 20); + sint16 Chance; +if(RuleH(Character, ChanceOfSkillIncrease) != NULL) + Chance = ((Hook_Character_ChanceOfSkillIncrease) RuleH(Character, ChanceOfSkillIncrease))(skillid, skillval, maxskill, chancemodi); +else +{ + Chance = 10 + chancemodi + ((252 - skillval) / 20); if (Chance < 1) Chance = 1; // Make it always possible +} if(MakeRandomFloat(0, 99) < Chance) { SetSkill(skillid, GetRawSkill(skillid) + 1); |
Hook 5 : Tweak AC calculation
Index: client_mods.cpp
================================================== ================= RCS file: /cvsroot/eqemulator/EQEmuCVS/Source/zone/client_mods.cpp,v retrieving revision 1.6.4.19 diff -u -b -B -r1.6.4.19 client_mods.cpp --- client_mods.cpp 21 Feb 2007 16:04:20 -0000 1.6.4.19 +++ client_mods.cpp 2 Mar 2008 09:11:32 -0000 @@ -28,6 +28,7 @@ #include "../common/moremath.h" #include "../common/guilds.h" #include "../common/logsys.h" +#include "../common/rulesys.h" #include "StringIDs.h" #include "NpcAI.h" @@ -714,7 +715,10 @@ // AC from spells are not included (cant even cast spells yet..) sint16 Client::CalcAC() { - // new formula +if(RuleH(Character, CalcAC) != NULL) + AC = ((Hook_Character_CalcAC) RuleH(Character, CalcAC))(GetLevel(), GetSkill(DEFENSE), itembonuses.AC, spellbonuses.AC); +else +{ // new formula int avoidance = 0; avoidance = (acmod() + ((GetSkill(DEFENSE)*16)/9)); if (avoidance < 0) @@ -749,8 +753,8 @@ //spell AC bonuses are added directly to natural total displayed += spellbonuses.AC; - AC = displayed; +} return(AC); } |
Hook 6 : Tweak Mana pool computation
Index: client_process.cpp
================================================== ================= RCS file: /cvsroot/eqemulator/EQEmuCVS/Source/zone/client_process.cpp,v retrieving revision 1.50.2.23 diff -u -b -B -r1.50.2.23 client_process.cpp --- client_process.cpp 21 Feb 2007 16:04:21 -0000 1.50.2.23 +++ client_process.cpp 2 Mar 2008 09:13:34 -0000 @@ -1466,7 +1466,13 @@ return; int32 level=GetLevel(); int32 regen = 0; - if (IsSitting()) { //this should be changed so we dont med while camping, etc... + +if(RuleH(Character, ManaRegen) != NULL) +{ regen = ((Hook_Character_ManaRegen) RuleH(Character, ManaRegen))(IsSitting(), GetLevel(), GetMaxMana(), GetINT(), GetSkill(MEDITATE), itembonuses.ManaRegen, spellbonuses.ManaRegen); + medding = IsSitting() && HasSkill(MEDITATE); +} +else +{ if (IsSitting()) { //this should be changed so we dont med while camping, etc... if(HasSkill(MEDITATE)) { medding = true; regen = (((GetSkill(MEDITATE)/10)+(level-(level/4)))/4)+4; @@ -1480,12 +1486,13 @@ medding = false; regen = 2+spellbonuses.ManaRegen+itembonuses.ManaRegen+(le vel/5); } +} regen += GetAA(aaMentalClarity); regen += GetAA(aaBodyAndMindRejuvenation); regen = (regen * RuleI(Character, ManaRegenMultiplier)) / 100; SetMana(GetMana() + regen); |
Hook 7 : Pre-XP change hook and Tweak XP per level value
Index: exp.cpp
================================================== ================= RCS file: /cvsroot/eqemulator/EQEmuCVS/Source/zone/exp.cpp,v retrieving revision 1.2.2.14 diff -u -b -B -r1.2.2.14 exp.cpp --- exp.cpp 16 Jan 2007 04:04:53 -0000 1.2.2.14 +++ exp.cpp 2 Mar 2008 09:17:01 -0000 @@ -34,7 +34,6 @@ void Client::AddEXP(int32 add_exp, int8 conlevel, bool resexp) { if (m_epp.perAA<0 || m_epp.perAA>100) m_epp.perAA=0; // stop exploit with sanity check - int32 add_aaxp; if(resexp) { add_aaxp = 0; @@ -117,6 +116,8 @@ return; // Must be invalid class/race } + if(RuleH(XP, PreChange) != NULL) + ((Hook_XP_PreChange) RuleH(XP, PreChange))(this, set_exp, set_aaxp, isrezzexp, m_pp.exp, m_pp.expAA); if ((set_exp + set_aaxp) > (m_pp.exp+m_pp.expAA)) { if (isrezzexp) @@ -312,7 +320,10 @@ uint32 Client::GetEXPForLevel(int16 check_level) { - int16 check_levelm1 = check_level-1; +if(RuleH(Character, EXPForLevel) != NULL) + return ((Hook_Character_EXPForLevel) RuleH(Character, EXPForLevel))(check_level, GetBaseRace(), GetClass()); +else +{ int16 check_levelm1 = check_level-1; float mod; if (check_level < 31) mod = 1.0; @@ -368,6 +379,7 @@ return(uint32(base * mod)); } +} void Group::SplitExp(uint32 exp, Mob* other) { if( other->CastToNPC()->MerchantType != 0 ) // Ensure NPC isn't a merchant |
Hooks 8 : Tweak fizzle and resist chance
Index: spells.cpp
================================================== ================= RCS file: /cvsroot/eqemulator/EQEmuCVS/Source/zone/spells.cpp,v retrieving revision 1.14.2.44 diff -u -b -B -r1.14.2.44 spells.cpp --- spells.cpp 21 Feb 2007 16:04:23 -0000 1.14.2.44 +++ spells.cpp 2 Mar 2008 09:24:51 -0000 @@ -480,7 +480,8 @@ } bool Client::CheckFizzle(int16 spell_id) -{ +{ float fizzlechance, diff; + // GMs don't fizzle if (GetGM()) return(true); @@ -516,7 +517,12 @@ //is there any sort of focus that affects fizzling? - // neotokyo: this is my try to get something going +if(RuleH(Spells, FizzleChance) != NULL) +{ fizzlechance = ((Hook_Spells_FizzleChance) RuleH(Spells, FizzleChance))(this, spells, spell_id); + diff = 0; +} +else +{ // neotokyo: this is my try to get something going int par_skill; int act_skill; @@ -556,7 +562,7 @@ // > 0 --> skill is lower, higher chance of fizzle // < 0 --> skill is better, lower chance of fizzle // the max that diff can be is +- 235 - float diff = par_skill + spells[spell_id].basediff - act_skill; + diff = par_skill + spells[spell_id].basediff - act_skill; // if you have high int/wis you fizzle less, you fizzle more if you are stupid if (GetCasterClass() == 'W') @@ -566,10 +572,11 @@ // base fizzlechance is lets say 5%, we can make it lower for AA skills or whatever float basefizzle = 10; - float fizzlechance = basefizzle - specialize + diff / 5.0; + fizzlechance = basefizzle - specialize + diff / 5.0; // always at least 5% chance to fail or succeed fizzlechance = fizzlechance < 5 ? 5 : (fizzlechance > 95 ? 95 : fizzlechance); +} float fizzle_roll = MakeRandomFloat(0, 100); mlog(SPELLS__CASTING, "Check Fizzle %s spell %d fizzlechance: %0.2f%% diff: %0.2f roll: %0.2f", GetName(), spell_id, fizzlechance, diff, fizzle_roll); @@ -2717,7 +2724,24 @@ break; } - // value in spell to adjust base resist by +if(RuleH(Spells, FinalResistChance) != NULL) +{ struct _Hook_Spells_FinalResistChance_Parameters Parameters; + Parameters.AttackerIsClient = caster->IsClient(); + Parameters.AttackerLevel = caster->GetLevel(); + Parameters.AttackerCha = caster->GetCHA(); + if(Parameters.AttackerIsClient) + Parameters.AttackerMeditation = caster->GetSkill(MEDITATE); + Parameters.DefenderIsClient = this->IsClient(); + Parameters.DefenderLevel = this->GetLevel(); + Parameters.DefenderResist = resist; + Parameters.spells = spells; + Parameters.spell_id = spell_id; + resistchance = ((Hook_Spells_FinalResistChance) RuleH(Spells, FinalResistChance))(&Parameters); + if(caster->IsClient()) + caster->CastToClient()->CheckIncreaseSkill(MEDITATE); +} +else +{ // value in spell to adjust base resist by if(spell_id != 0) resist += spells[spell_id].ResistDiff; @@ -2743,7 +2767,7 @@ resistchance -= (lvldiff)*0.8; } } - +} /*The idea is we come up with 3 ranges of numbers and a roll between 0 and 100 [[[Empty Space above the resistchance line]]] - If the roll lands up here the spell wasn't resisted, the lower the resist chance the larger this range is [[[Space between resistchance line and full resist chance line]]] - If the roll ends up here then the spell is resisted but only partially, we take the roll in porportion to where it landed in this range to det how |
common/default_hooks.h
I forgot the default_hooks.h file that contains the hook function declaractions. It is required for the changes in the rulexxx files to compile :
#ifndef DEFAULT_RULES_H_ #define DEFAULT_RULES_H_ /** A hook can be a function pointer of any type. So we define it as void *. * Hooks are cast to their actual function type when they are called. */ typedef void *Hook; /** Macro used to check the compliance of hook functions with the definition of the hook. * It ensures the hook function has the correct signature. * It can be very useful to avoid mistakes, and when a hook signature changes. * The compiler can then issue an error. * If no signature check is done, a badly-defined hook function will probably crash the server. * usage: add a line after the hook function definition (in the *.cpp file) * CheckHookSignature(CharacterCreation, ChangeCreationInfo, default_CharacterCreation_ChangeCreationInfo); */ #define CheckHookSignature(cat, rule, hook) \ static Hook_##cat##_##rule CheckSignature_##hook = hook /************************************************** ******************************************/ /* Common hooks. Only hooks implemented in both the world and zone must go in this section. */ /************************************************** ******************************************/ /** */ typedef double (*Hook_Random_RandomFloat)(double low, double high); /************************************************** ***************************************/ /* World-related hooks. Only hooks (and includes) used in World must go to this section. */ /************************************************** ***************************************/ #ifdef WORLD #include "../common/eq_packet_structs.h" /** Called during character creation right after the CharCreate structure has been checked for correctness. * Allows the world builder to tweak the values sent by the client prior to the actual character creation. */ typedef void (*Hook_CharacterCreation_ChangeCreationInfo)(CharC reate_Struct *cc); #endif /* WORLD */ /************************************************** ***************************************/ /* Zone-related hooks. Only hooks (and includes) used in Zone must go to this section. */ /************************************************** ***************************************/ #ifdef ZONE #include "../zone/client.h" typedef struct _Hook_Attack_ToHitChance_Parameters { bool IsPvp; bool AttackerIsClient; int8 AttackerLevel; sint16 AttackerDex; uint16 AttackerWeaponSkill; /* not applicable if !AttackerIsClient */ uint16 AttackerOffense; /* not applicable if !AttackerIsClient */ bool DefenderIsClient; int8 DefenderLevel; sint16 DefenderAgi; uint16 DefenderDefense; /* not applicable if !DefenderIsClient */ } *Hook_Attack_ToHitChance_Parameters; /** Called during the function checking whether an attack actualy hits. * Computes the percentage chance of hitting based on level, weapon skill, DEX and AGI. * The regular rules will be used for the rest of the hit chance (mods, AAs etc). * 'Paramters' contains all information available for the computation. */ typedef float (*Hook_Attack_ToHitChance)(Hook_Attack_ToHitChance _Parameters Parameters); typedef struct _Hook_Attack_ClientDamageRange_Parameters { sint16 AttackerStr; int8 AttackerLevel; int AttackerWeaponDamage; int AttackerWeaponDelay; int8 DefenderLevel; int MinHit; /* output only */ int MaxHit; /* output only */ } *Hook_Attack_ClientDamageRange_Parameters; /** * 'Parameters' contains all information available for the computation. */ typedef void (*Hook_Attack_ClientDamageRange)(Hook_Attack_Clien tDamageRange_Parameters Parameters); typedef struct _Hook_Attack_NpcDamageRange_Parameters { sint16 AttackerStr; int8 AttackerLevel; int AttackerMaxDamage; int AttackerDelay; int8 DefenderLevel; int MinHit; /* output only */ int MaxHit; /* output only */ } *Hook_Attack_NpcDamageRange_Parameters; /** * 'Parameters' contains all information available for the computation. */ typedef void (*Hook_Attack_NpcDamageRange)(Hook_Attack_NpcDamag eRange_Parameters Parameters); typedef struct _Hook_Attack_Mitigation_Parameters { bool AttackerIsClient; int8 AttackerLevel; uint16 AttackerOffense; /* not applicable if !AttackerIsClient */ bool DefenderIsClient; int8 DefenderLevel; sint16 DefenderAC; uint16 DefenderDefense; /* not applicable if !DefenderIsClient */ sint32 Damage; /* input-output */ } *Hook_Attack_Mitigation_Parameters; /** * 'Parameters' contains all information available for the computation. */ typedef void (*Hook_Attack_Mitigation)(Hook_Attack_Mitigation_P arameters Parameters); /** Called at the end of the function where the bonuses given by an item are cumulated to the current item bonuses a character receives. * 'inst' is the item to evaluate. * 'newbon' is the current set of bonuses received from items by the character. */ typedef void (*Hook_Character_PostAddItemBonuses)(const ItemInst *inst, StatBonuses* newbon); /** */ typedef sint16 (*Hook_Character_CalcAC)(uint8 Level, uint16 Defense, sint16 ItemsAC, sint16 SpellsAC); /** */ typedef uint32 (*Hook_Character_EXPForLevel)(uint8 Level, int16 CharacterRace, int8 CharacterClass); /** */ typedef int32 (*Hook_Character_ManaRegen)(bool IsSitting, uint8 Level, sint32 MaxMana, sint16 Int, uint16 MeditateSkill, sint32 ItemsManaRegen, sint32 SpellsManaRegen); /** */ typedef sint16 (*Hook_Character_ChanceOfSkillIncrease)(SkillType skillid, int CurrentSkill, int MaxSkill, int chancemodi); /** Called right before the fizzle roll is made, to compute the percentage of chance to fizzle. * 'ThisClient' is the character casting the spell. * 'spell_id' is the ID of the spell being cast. * The check whether the caster can never fizzle due to AAs has already been done. */ typedef float (*Hook_Spells_FizzleChance)(Client *ThisClient, const SPDat_Spell_Struct *spells, int16 spell_id); typedef struct _Hook_Spells_FinalResistChance_Parameters { bool AttackerIsClient; int8 AttackerLevel; sint16 AttackerCha; uint16 AttackerMeditation; /* not applicable if !AttackerIsClient */ bool DefenderIsClient; int8 DefenderLevel; sint16 DefenderResist; const SPDat_Spell_Struct *spells; int16 spell_id; } *Hook_Spells_FinalResistChance_Parameters; /** */ typedef float (*Hook_Spells_FinalResistChance)(Hook_Spells_Final ResistChance_Parameters Parameters); /** Called during exprience change, before the new XP values are set. Ideal place to show a custom message with the numeric XP values. * The XP for the current client is going to be set to 'set_exp' and 'set_aaxp'. * The client currently has 'orig_exp' XP and 'orig_aaxp'. * 'isrezzexp' indicates whether this is XP regained after a rez. * The hook cannot affect the XP change in any way. The XP will be changed normally after the hook returns. */ typedef void (*Hook_XP_PreChange)(Client *ThisClient, int32 set_exp, int32 set_aaxp, bool isrezzexp, int32 orig_exp, int32 orig_aaxp); #endif /* ZONE */ #endif /*DEFAULT_RULES_H_*/ |
Implementing the hooks
What has been explained since the beginning of this post is still still somewhat applicable, with some changes. To implement one (or more) hooks you need to :
- create a shared library with the hook functions implementation. You want to separate "world" and "zone", so it means two shared libraries (in my case hero_world and hero_zone). - add an entry in the rule_values database for each hook to activate |
World Hooks
Here is my code for the hero_world.dll library (hero_world_Hooks.cpp) :
#include "../common/debug.h" #include "../common/default_Hooks.h" #include "../common/classes.h" #include "../common/races.h" #ifdef WIN32 #define exportfunc extern "C" __declspec(dllexport) #else #define exportfunc extern "C" #endif /** Makes all newly-created characters Rangers - It is the class chosen for heroes as it can cast spells * and have dual-wield. After all, aren't all rangers heroes ? */ exportfunc void hero_world_CharacterCreation_ChangeCreationInfo(Ch arCreate_Struct *cc) { cc->class_ = RANGER; /* Adjust the stats to provide a similar amount of points per race. * Good or neutral races get 535 points total, evil races 555. */ switch(cc->race) { case BARBARIAN: break; case DARK_ELF: cc->CHA += 23; break; case DWARF: cc->CHA += 7; break; case ERUDITE: cc->CHA += 5; break; case FROGLOK: cc->CHA -= 15; break; case GNOME: cc->CHA += 10; break; case HALF_ELF: cc->CHA += 10; break; case HALFLING: cc->CHA += 3; break; case HIGH_ELF: cc->AGI -= 7; break; case HUMAN: cc->CHA += 10; break; case IKSAR: break; case OGRE: cc->CHA += 1; break; case TROLL: cc->DEX += 10; cc->STA += 18; break; case VAHSHIR: cc->DEX += 10; break; case WOOD_ELF: break; default: printf("unknown race %d\n", cc->race); } } CheckHookSignature(CharacterCreation, ChangeCreationInfo, hero_world_CharacterCreation_ChangeCreationInfo); Enlarge one column in the database to allow specifying looong values : ALTER TABLE rule_values MODIFY rule_value VARCHAR(256); The hook is activated with the following SQL query in the database : INSERT INTO rule_values VALUES ('1','(world) CharacterCreation:ChangeCreationInfo','hero_world: hero_world_CharacterCreation_ChangeCreationInfo'); The entry name is of the form "(world) <hook>" for world hooks. The value is the name of the shared library (no extension, for Unix compatibility) then the name of the function implementing the hook. |
Zone Hooks
There are many more zone hooks. They are implemented in hero_zone_Hooks.cpp, which generates the hero_world.dll shared library.
I removed a couple hooks of mine as they rely on other non-hook related changes on my server. Those custom hooks are of course only there as examples. You do not want them on your own server :) #include "../common/debug.h" #include "../common/default_Hooks.h" #include "../common/MiscFunctions.h" #include <math.h> #ifdef WIN32 #define exportfunc extern "C" __declspec(dllexport) #else #define exportfunc extern "C" #endif #define SkillRegulationMod (+20) #define StatRegulationMod (-50) #define ZeroIfNegative(x) ((x) < 0 ? 0 : (x)) /** The to-hit chance is computed as : * 100 - 100 * (DEF AGI + StatRegulationMod) / ( (DEF AGI + StatRegulationMod) + (ATK DEX + StatRegulationMod) + (ATK Skill + SkillRegulationMod) ) * If one of the opponent is not a client then its skill is equal to (Level + 1) * 5. */ exportfunc float hero_zone_Attack_ToHitChance(Hook_Attack_ToHitChan ce_Parameters Parameters) { float Result; uint16 AttackerWeaponSkill; //printf("Bulle-ToHit-Hook-01 : PVP=%d / ATK CLT=%d / ATK LVL=%d / ATK DEX=%d / ATK WEA=%d / ATK OFF=%d\n", Parameters->IsPvp, Parameters->AttackerIsClient, Parameters->AttackerLevel, Parameters->AttackerDex, Parameters->AttackerIsClient?Parameters->AttackerWeaponSkill : -1, Parameters->AttackerIsClient?Parameters->AttackerOffense : -1); //printf("Bulle-ToHit-Hook-02 : PVP=%d / DEF CLT=%d / DEF LVL=%d / DEF AGI=%d / DEF OFF=%d\n", Parameters->IsPvp, Parameters->DefenderIsClient, Parameters->DefenderLevel, Parameters->DefenderAgi, Parameters->AttackerIsClient?Parameters->DefenderDefense : -1); if(Parameters->AttackerIsClient) AttackerWeaponSkill = Parameters->AttackerWeaponSkill; else AttackerWeaponSkill = (Parameters->AttackerLevel + 1) * 5; Result = 100.0 - 100.0 * ZeroIfNegative(Parameters->DefenderAgi + StatRegulationMod) / ( ZeroIfNegative(Parameters->DefenderAgi + StatRegulationMod) + ZeroIfNegative(Parameters->AttackerDex + StatRegulationMod) + ZeroIfNegative(AttackerWeaponSkill + SkillRegulationMod) / 2 + 1 /* avoids division by zero */ ); printf("Bulle-ToHit-Hook-03 : to hit=%f\n", Result); return Result; } CheckHookSignature(Attack, ToHitChance, hero_zone_Attack_ToHitChance); /** The damage range is computed as : * MinHit = (ATK STR + StatRegulationMod) * ATK WEAP DLY / 100 * MaxHit = MinHit + 3 * ATK WEAP DMG */ exportfunc void hero_zone_Attack_ClientDamageRange(Hook_Attack_Cli entDamageRange_Parameters Parameters) { //printf("Bulle-ClientDamageRange-Hook-01 : ATK STR=%d / ATK LVL=%d / ATK DLY=%d / ATK DMG=%d / DEF LVL=%d\n", Parameters->AttackerStr, Parameters->AttackerLevel, Parameters->AttackerWeaponDelay, Parameters->AttackerWeaponDamage, Parameters->DefenderLevel); Parameters->MinHit = (int) (ZeroIfNegative(Parameters->AttackerStr + StatRegulationMod) * Parameters->AttackerWeaponDelay / 100.0); Parameters->MaxHit = Parameters->MinHit + 3 * Parameters->AttackerWeaponDamage; printf("Bulle-ClientDamageRange-Hook-02 : min_hit=%d max_hit=%d\n", Parameters->MinHit, Parameters->MaxHit); } CheckHookSignature(Attack, ClientDamageRange, hero_zone_Attack_ClientDamageRange); /** The damage range is computed as : * MinHit = (ATK STR + StatRegulationMod) * ATK DLY / 100 * MaxHit = MinHit + 2 * ATK MAXDMG */ exportfunc void hero_zone_Attack_NpcDamageRange(Hook_Attack_NpcDam ageRange_Parameters Parameters) { //printf("Bulle-NpcDamageRange-Hook-01 : ATK STR=%d / ATK LVL=%d / ATK DLY=%d / ATK MAXDMG=%d / DEF LVL=%d\n", Parameters->AttackerStr, Parameters->AttackerLevel, Parameters->AttackerDelay, Parameters->AttackerMaxDamage, Parameters->DefenderLevel); Parameters->MinHit = (int) (ZeroIfNegative(Parameters->AttackerStr + StatRegulationMod) * Parameters->AttackerDelay / 100.0); Parameters->MaxHit = Parameters->MinHit + 2 * Parameters->AttackerMaxDamage; printf("Bulle-NpcDamageRange-Hook-02 : min_hit=%d max_hit=%d\n", Parameters->MinHit, Parameters->MaxHit); } CheckHookSignature(Attack, NpcDamageRange, hero_zone_Attack_NpcDamageRange); exportfunc void hero_zone_Attack_Mitigation(Hook_Attack_Mitigation _Parameters Parameters) { sint32 InitialDamage = Parameters->Damage; float Mitigation; uint16 AttackerOffense, DefenderDefense; double AdjustedDefenderAC; //printf("Bulle-Mitigation-Hook-01 : ATK CLT=%d / ATK LVL=%d / ATK OFF=%d / DEF CLT=%d / DEF LVL=%d / DEF AC=%d / DEF DEF=%d\n", Parameters->AttackerIsClient, Parameters->AttackerLevel, Parameters->AttackerIsClient ? Parameters->AttackerOffense : -1, Parameters->DefenderIsClient, Parameters->DefenderLevel, Parameters->DefenderAC, Parameters->DefenderIsClient ? Parameters->DefenderDefense : -1); if(Parameters->AttackerIsClient) AttackerOffense = Parameters->AttackerOffense; else AttackerOffense = (Parameters->AttackerLevel + 1) * 5; if(Parameters->DefenderIsClient) { DefenderDefense = Parameters->DefenderDefense; AdjustedDefenderAC = Parameters->DefenderAC; } else { DefenderDefense = (Parameters->DefenderLevel + 1 )* 5; AdjustedDefenderAC = pow(Parameters->DefenderAC * 1.0, 0.9); } Mitigation = (AdjustedDefenderAC + ZeroIfNegative(DefenderDefense + SkillRegulationMod) * 1.25) / (AdjustedDefenderAC + ZeroIfNegative(DefenderDefense + SkillRegulationMod) * 1.25 + ZeroIfNegative(AttackerOffense + SkillRegulationMod) * 5); Parameters->Damage = (int) ((1.0 - Mitigation) * InitialDamage); printf("Bulle-Mitigation-Hook-02 : dmgbfr=%d mitig=%f dmgaft=%d\n", InitialDamage, Mitigation, Parameters->Damage); } CheckHookSignature(Attack, Mitigation, hero_zone_Attack_Mitigation); exportfunc sint16 hero_zone_Character_CalcAC(uint8 Level, uint16 Defense, sint16 ItemsAC, sint16 SpellsAC) { sint16 Result = ItemsAC + SpellsAC; return Result; } CheckHookSignature(Character, CalcAC, hero_zone_Character_CalcAC); exportfunc uint32 hero_zone_Character_EXPForLevel(uint8 Level, int16 CharacterRace, int8 CharacterClass) { uint32 Result = 100.0 * pow(1.2, Level + 10); printf("Bulle-EXPForLevel-Hook-01 : level=%d XP=%d\n", Level, Result); return Result; } CheckHookSignature(Character, EXPForLevel, hero_zone_Character_EXPForLevel); exportfunc int32 hero_zone_Character_ManaRegen(bool IsSitting, uint8 Level, sint32 MaxMana, sint16 Int, uint16 MeditateSkill, sint32 ItemsManaRegen, sint32 SpellsManaRegen) { sint16 Result; Result = MaxMana * Int / 4000; if(!IsSitting) Result = Result / 10; Result += 2 + ItemsManaRegen + SpellsManaRegen; //printf("Bulle-ManaRegen-Hook-01 : regen=%d\n", Result); return Result; } CheckHookSignature(Character, ManaRegen, hero_zone_Character_ManaRegen); /** Base chance is a linear function such that base chance is 25% when skill is 0, and 0% when skill is 250. * The final chance is the base chance plus the chance modifier, or 5%, whichever is greater. */ exportfunc sint16 hero_zone_Character_ChanceOfSkillIncrease(SkillTyp e skillid, int CurrentSkill, int MaxSkill, int chancemodi) { sint16 Result; Result = (25 * (250 - CurrentSkill) + 1250) / 300 + chancemodi; if(Result < 5) Result = 5; printf("Bulle-ChanceOfSkillIncrease-Hook-01 : skill=%d chance=%d\n", CurrentSkill, Result); return Result; } CheckHookSignature(Character, ChanceOfSkillIncrease, hero_zone_Character_ChanceOfSkillIncrease); exportfunc float hero_zone_Spells_FinalResistChance(Hook_Spells_Fin alResistChance_Parameters Parameters) { float Result; uint16 AttackerMeditation; if(Parameters->AttackerIsClient) AttackerMeditation = Parameters->AttackerMeditation; else AttackerMeditation = (Parameters->AttackerLevel + 1) * 5; Result = 100.0 * Parameters->DefenderResist / (1 + ZeroIfNegative(1.0 * Parameters->DefenderResist + (Parameters->AttackerCha + StatRegulationMod) + (AttackerMeditation + SkillRegulationMod) - Parameters->spells[Parameters->spell_id].ResistDiff)); printf("Bulle-Resist-Hook-01 : resist=%f\n", Result); return Result; } CheckHookSignature(Spells, FinalResistChance, hero_zone_Spells_FinalResistChance); /** Displays numeric XP value gains (or loss). */ exportfunc void hero_zone_XP_PreChange(Client *ThisClient, int32 set_exp, int32 set_aaxp, bool isrezzexp, int32 orig_exp, int32 orig_aaxp) { if(set_exp - orig_exp > 0) ThisClient->Message(15, "You have gained %d XP.", set_exp - orig_exp); else if(set_exp - orig_exp < 0) ThisClient->Message(15, "You have lost %d XP.", set_exp - orig_exp); if(set_aaxp - orig_aaxp > 0) ThisClient->Message(15, "You have gained %d AA XP.", set_aaxp - orig_aaxp); else if(set_aaxp - orig_aaxp < 0) ThisClient->Message(15, "You have lost %d AA XP.", set_aaxp - orig_aaxp); //printf("Bulle-XPPreChange-Hook-01 : XP:%d->%d AA:%d->%d\n", orig_exp, set_exp, orig_aaxp, set_aaxp); } CheckHookSignature(XP, PreChange, hero_zone_XP_PreChange); |
SQL code to activate the zone hooks
INSERT INTO rule_values VALUES ('1','(zone) Attack:ToHitChance','hero_zone:hero_zone_Attack_To HitChance');
INSERT INTO rule_values VALUES ('1','(zone) Attack:ClientDamageRange','hero_zone:hero_zone_Att ack_ClientDamageRange'); INSERT INTO rule_values VALUES ('1','(zone) Attack:NpcDamageRange','hero_zone:hero_zone_Attack _NpcDamageRange'); INSERT INTO rule_values VALUES ('1','(zone) Attack:Mitigation','hero_zone:hero_zone_Attack_Mit igation'); INSERT INTO rule_values VALUES ('1','(zone) Character:CalcAC','hero_zone:hero_zone_Character_C alcAC'); INSERT INTO rule_values VALUES ('1','(zone) Character:EXPForLevel','hero_zone:hero_zone_Charac ter_EXPForLevel'); INSERT INTO rule_values VALUES ('1','(zone) Character:ManaRegen','hero_zone:hero_zone_Characte r_ManaRegen'); INSERT INTO rule_values VALUES ('1','(zone) Character:ChanceOfSkillIncrease','hero_zone:hero_z one_Character_ChanceOfSkillIncrease'); INSERT INTO rule_values VALUES ('1','(zone) XP:PreChange','hero_zone:hero_zone_XP_PreChange'); INSERT INTO rule_values VALUES ('1','(zone) Spells:FinalResistChance','hero_zone:hero_zone_Spe lls_FinalResistChance'); |
Now you can probably understand why I was so quiet about the topic :)
This code submission is quite huge, I will understand if noone can find the time to try it out (especially as I may have introduced errors when porting the code back to CVS from my SVN repository, and weeding out the other unnecessary change I made). If I make other interesting changes to the server I will make sure to post them somewhere else. Now after all this effort it is Zebu server time ;-) Bulle |
All times are GMT -4. The time now is 10:39 PM. |
Powered by vBulletin®, Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.