From 2d1805c9837684267c50f6f385735cf68af5d958 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 17 May 2013 12:20:49 -0500 Subject: [PATCH 01/12] Mod function updates - better documentation --- zone/attack.cpp | 11 +- zone/client.h | 5 +- zone/mob.h | 4 +- zone/mod_functions.cpp | 773 +++++++++++++++++++++++++++++++++++++-- zone/npc.h | 2 +- zone/special_attacks.cpp | 4 +- 6 files changed, 762 insertions(+), 37 deletions(-) diff --git a/zone/attack.cpp b/zone/attack.cpp index c08382838..8547ca3c6 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -1871,7 +1871,7 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool damage = (max_dmg+eleBane); } - damage = mod_npc_damage(damage, skillinuse, Hand, &weapon_inst, other); + damage = mod_npc_damage(damage, skillinuse, Hand, weapon, other); int32 hate = damage; if(IsPet()) @@ -2115,10 +2115,13 @@ void NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillType attack_ski Group *kg = entity_list.GetGroupByClient(give_exp_client); Raid *kr = entity_list.GetRaidByClient(give_exp_client); + int32 finalxp = EXP_FORMULA; + finalxp = give_exp_client->mod_client_xp(finalxp, this); + if(kr) { if(!IsLdonTreasure) { - kr->SplitExp((EXP_FORMULA), this); + kr->SplitExp((finalxp), this); if(killerMob && (kr->IsRaidMember(killerMob->GetName()) || kr->IsRaidMember(killerMob->GetUltimateOwner()->GetName()))) killerMob->TrySpellOnKill(killed_level,spell); } @@ -2159,7 +2162,7 @@ void NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillType attack_ski else if (give_exp_client->IsGrouped() && kg != nullptr) { if(!IsLdonTreasure) { - kg->SplitExp((EXP_FORMULA), this); + kg->SplitExp((finalxp), this); if(killerMob && (kg->IsGroupMember(killerMob->GetName()) || kg->IsGroupMember(killerMob->GetUltimateOwner()->GetName()))) killerMob->TrySpellOnKill(killed_level,spell); } @@ -2208,7 +2211,7 @@ void NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillType attack_ski if(GetOwner() && GetOwner()->IsClient()){ } else { - give_exp_client->AddEXP((EXP_FORMULA), conlevel); // Pyro: Comment this if NPC death crashes zone + give_exp_client->AddEXP((finalxp), conlevel); // Pyro: Comment this if NPC death crashes zone if(killerMob && (killerMob->GetID() == give_exp_client->GetID() || killerMob->GetUltimateOwner()->GetID() == give_exp_client->GetID())) killerMob->TrySpellOnKill(killed_level,spell); } diff --git a/zone/client.h b/zone/client.h index 52d298b61..3be422a2b 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1112,8 +1112,8 @@ public: int16 GetActCHA() { return( min(GetMaxCHA(), GetCHA()) ); } void LoadAccountFlags(); void SetAccountFlag(std::string flag, std::string val); - std::string GetAccountFlag(std::string flag); float GetDamageMultiplier(SkillType); - int mod_client_damage(int damage, SkillType skillinuse, int hand, ItemInst* weapon, Mob* other); + std::string GetAccountFlag(std::string flag); + int mod_client_damage(int damage, SkillType skillinuse, int hand, const ItemInst* weapon, Mob* other); bool mod_client_message(char* message, uint8 chan_num); bool mod_can_increase_skill(SkillType skillid, Mob* against_who); int16 mod_increase_skill_chance(int16 chance, Mob* against_who); @@ -1129,6 +1129,7 @@ public: void mod_client_death_npc(Mob* killerMob); void mod_client_death_duel(Mob* killerMob); void mod_client_death_env(); + int32 mod_client_xp(int32 in_exp, NPC *npc); protected: friend class Mob; diff --git a/zone/mob.h b/zone/mob.h index b300eb9b6..d83f2aa90 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -805,8 +805,8 @@ public: int32 mod_monk_special_damage(int32 ndamage, SkillType skill_type); int32 mod_backstab_damage(int32 ndamage); int mod_archery_bonus_chance(int bonuschance, const ItemInst* RangeWeapon); - uint32 mod_archery_bonus_damage(uint32 MaxDmg); - int32 mod_archery_damage(int32 TotalDmg, bool hasbonus); + uint32 mod_archery_bonus_damage(uint32 MaxDmg, const ItemInst* RangeWeapon); + int32 mod_archery_damage(int32 TotalDmg, bool hasbonus, const ItemInst* RangeWeapon); uint16 mod_throwing_damage(uint16 MaxDmg); int32 mod_cast_time(int32 cast_time); int mod_buff_duration(int res, Mob* caster, Mob* target, uint16 spell_id); diff --git a/zone/mod_functions.cpp b/zone/mod_functions.cpp index af228ed9e..a6088ee02 100644 --- a/zone/mod_functions.cpp +++ b/zone/mod_functions.cpp @@ -23,33 +23,504 @@ extern WorldServer worldserver; using namespace std; +#define DW_STATBASE 70 + void Zone::mod_init() { return; } void Zone::mod_repop() { return; } -void NPC::mod_prespawn(Spawn2 *sp) { return; } -int NPC::mod_npc_damage(int damage, SkillType skillinuse, int hand, ItemInst* weapon, Mob* other) { return(damage); } +void NPC::mod_prespawn(Spawn2 *sp) { + //The spawn has to have 1 kill to qualify + if(sp->GetKillCount() < 1) { return; } + //Ignore existing bosses + if(lastname[0] == '[') { return; } + //5% chance to elevate + if(MakeRandomInt(0, 100) > 5) { return; } + + //Let everything else happen in perl. Our job here is to set the last name + int npcscore = GetScore(); + std::string bosstag = "<"; + int lvs = (int)(npcscore/10); + for(int x = 0; x < 10; x++) + { + if(x < lvs) { bosstag += "+"; } + else { bosstag += "="; } + } + bosstag += ">"; + strn0cpy(lastname, bosstag.c_str(), sizeof(lastname)); + + TempName("DYNBOSS"); +} + +//Base damage from NPC::Attack +int NPC::mod_npc_damage(int damage, SkillType skillinuse, int hand, const Item_Struct* weapon, Mob* other) { + float chbonus; + int lbonus; + +// if(!IsPet() || !GetOwner()) { return(damage); } +// if(!GetOwner()->IsClient()) { return(damage); } + + //Client pet power bonuses + if(GetOwner() && GetOwner()->IsClient()) + { + chbonus = (float)((float)GetOwner()->CastToClient()->GetActCHA() - DW_STATBASE) / 100; + chbonus += 1; + + if(GetOwner()->GetLevel() > 50) + { + lbonus = GetOwner()->GetLevel() - 50; + damage += lbonus * (20 * lbonus); + } + + if(weapon) + { + damage += (int)ceil(((float)weapon->Damage / (float)weapon->Delay) * (float)GetLevel()); + } + + damage = (int)ceil( (float)damage * chbonus ); + return(damage); + } + + //Regular NPC damage - test for debuffs that currently do nothing. + //str, sta, agi, dex, AC, ATK + return(damage); +} + void NPC::mod_npc_killed_merit(Mob* c) { return; } void NPC::mod_npc_killed(Mob* oos) { return; } -int Client::mod_client_damage(int damage, SkillType skillinuse, int hand, ItemInst* weapon, Mob* other) { return(damage); } +//Base damage from Client::Attack - can cover myriad skill types +int Client::mod_client_damage(int damage, SkillType skillinuse, int hand, const ItemInst* weapon, Mob* other) { + float dmult = 1.1f; + float cdex = (float)GetActDEX() - DW_STATBASE; + float cstr = (float)GetActSTR() - DW_STATBASE; + float cagi = (float)GetActAGI() - DW_STATBASE; + float csta = (float)GetActSTA() - DW_STATBASE; + + float cmax = ((float)GetLevel() * 2) + 150; + if(GetLevel() > 49) { cmax = 10000; } + + if(cdex > cmax) { cdex = cmax; } + if(cstr > cmax) { cstr = cmax; } + if(cagi > cmax) { cagi = cmax; } + if(csta > cmax) { csta = cmax; } + + switch(skillinuse) + { + case ARCHERY: + dmult += cdex / 600; + dmult += csta / 600; + + if(GetClass() == RANGER) + { + dmult += cdex / 1000; + } + break; + + case KICK: + case HAND_TO_HAND: + case BACKSTAB: + case _1H_BLUNT: + case _1H_SLASHING: + case PIERCING: + case THROWING: + if(GetClass() == MONK || GetClass() == BEASTLORD) + { + if(GetRace() == BARBARIAN || GetRace() == TROLL || GetRace() == OGRE) + { + dmult += cstr / 320; + dmult += csta / 320; + dmult += cdex / 150; + //2.325 + } + else + { + dmult += cdex / 400; + dmult += csta / 200; + dmult += cstr / 200; + //2.25 + } + } + else + { + dmult += cdex / 400; + dmult += cstr / 200; + dmult += csta / 200; + //2.25 + } + break; + + case BASH: + if(GetClass() == WARRIOR) + { + dmult += csta / 100; + dmult += cstr / 100; + } + else + { + dmult += csta / 150; + dmult += cstr / 150; + } + break; + + case _2H_SLASHING: + case _2H_BLUNT: + case FRENZY: + if(GetClass() == BERSERKER) + { + dmult += csta / 100; + dmult += cstr / 100; + } + else + { + dmult += csta / 150; + dmult += cstr / 150; + } + break; + + default: + dmult += cstr / 200; + dmult += csta / 200; + break; + } + + if(GetLevel() > 50) + { + float lbonus = GetLevel() - 50; + dmult += lbonus * 0.2; + } + + int final = (int)((float)damage * dmult); + + if(skillinuse == ARCHERY) + { + final += (GetSkill(ARCHERY) + (GetLevel() * 2)) / 2; + if(weapon) //We should always have a weapon here + { + final = (int)((float)final * (float)(0.6 + ((float)weapon->GetItem()->Delay / 100))); + } + } + + return(final); +} + + +//message is char[4096], don't screw it up. bool Client::mod_client_message(char* message, uint8 chan_num) { return(true); } //Potentially dangerous string handling here -bool Client::mod_can_increase_skill(SkillType skillid, Mob* against_who) { return(false); } -int16 Client::mod_increase_skill_chance(int16 chance, Mob* against_who) { return(chance); } -int Client::mod_bindwound_percent(int max_percent, Mob* bindmob) { return(max_percent); } -int Client::mod_bindwound_hp(int bindhps, Mob* bindmob) { return(bindhps); } -int Client::mod_client_haste(int h) { return(h); } + +//Skillup override. When this is called the regular skillup check has failed. Return false to proceed with default behavior. +//This will NOT allow a client to increase skill past a cap. +bool Client::mod_can_increase_skill(SkillType skillid, Mob* against_who) { + //Let people skillup on golem training dummies. + if(against_who->GetRace() == 405) { return(true); } + return(false); +} + +//chance of general skill increase, rolled against 0-99 where higher chance is better. +int16 Client::mod_increase_skill_chance(int16 chance, Mob* against_who) { + float cint = (float)GetActINT() - DW_STATBASE; + float cwis = (float)GetActWIS() - DW_STATBASE; + + float bonus = (cint + (cwis / 2)) / 10; + + if(bonus < 0) { bonus = 0; } + + return( (int)((float)chance * bonus) ); +} + +//Max percent of health you can bind wound starting with default value for class, item, and AA bonuses +int Client::mod_bindwound_percent(int max_percent, Mob* bindmob) { + return(max_percent + 20); +} + +//Final bind HP value after bonuses +int Client::mod_bindwound_hp(int bindhps, Mob* bindmob) { + if(GetSkill(BIND_WOUND) > 200) + { + bindhps += GetSkill(BIND_WOUND) * 2; + } + else + { + bindhps += GetSkill(BIND_WOUND); + } + + if(GetLevel() > 50) + { + float bonus = ((GetLevel() - 50) / 10) + 1; + bindhps += (int)( (float)bindhps * bonus ); + } + + return(bindhps); +} + +//Client haste as calculated by default formulas - In percent from 0-100 +int Client::mod_client_haste(int h) { + float agibase = (float)GetActAGI() - DW_STATBASE; + float agibonus = 0; + + if(agibase > 0) + { + agibonus = agibase; + + float l1, l2, l3; + + switch(GetClass()) + { + case ROGUE: + case MONK: + l1 = 1.5; + l2 = 2.0; + l3 = 2.5; + break; + + default: + l1 = 1.0; + l2 = 1.5; + l3 = 2.0; + } + + if(GetLevel() > 19) { agibonus = agibase * l1; } + if(GetLevel() > 39) { agibonus = agibase * l2; } + if(GetLevel() > 59) { agibonus = agibase * l3; } + } + + h += (int)(agibonus / 10); + return(h); +} + void Client::mod_consider(Mob* tmob, Consider_Struct* con) { return; } bool Client::mod_saylink(const std::string&, bool silentsaylink) { return(true); } -int16 Client::mod_pet_power(int16 act_power, uint16 spell_id) { return(act_power); } -float Client::mod_tradeskill_chance(float chance, DBTradeskillRecipe_Struct *spec) { return(chance); } -float Client::mod_tradeskill_skillup(float chance_stage2) { return(chance_stage2); } -int32 Client::mod_tribute_item_value(int32 pts) { return(pts); } + +//Client pet power as calculated by default formulas and bonuses +int16 Client::mod_pet_power(int16 act_power, uint16 spell_id) { + act_power += (int)(((float)GetActCHA() - DW_STATBASE) /2 ) + GetLevel(); + return(act_power); +} + +//Chance to combine rolled against a random 0-99 where higher is better. +float Client::mod_tradeskill_chance(float chance, DBTradeskillRecipe_Struct *spec) { + chance += 10; + return(chance); +} + +//Chance to skillup rolled against a random 0-99 where higher is better. +float Client::mod_tradeskill_skillup(float chance_stage2) { + float cint = (float)CastToClient()->GetActINT() - DW_STATBASE; + float cwis = (float)CastToClient()->GetActWIS() - DW_STATBASE; + + float bonus = (cint + (cwis / 2)) / 10; + + if(bonus < 0) { bonus = 0; } + return(chance_stage2 + bonus); +} + +//Tribute value override +int32 Client::mod_tribute_item_value(int32 pts) { + return(0); +} + +//Death reporting void Client::mod_client_death_npc(Mob* killerMob) { return; } void Client::mod_client_death_duel(Mob* killerMob) { return; } void Client::mod_client_death_env() { return; } -int Mob::mod_effect_value(int effect_value, uint16 spell_id, int effect_type, Mob* caster) { return(effect_value); } -float Mob::mod_hit_chance(float chancetohit, SkillType skillinuse, Mob* attacker) { return(chancetohit); } +//Calculated xp before consider modifier +int32 Client::mod_client_xp(int32 in_xp, NPC *npc) { + float xpmult = 2.0f; + + if(GetLevel() > 5) + { + xpmult = 1.5f; + } + if(GetLevel() > 10) + { + xpmult = 1.25f; + } + if(GetLevel() > 15) + { + xpmult = 1.0f; + } + + return( (int32)((float)in_xp * xpmult) ); +} + +//effect_vallue - Spell effect value as calculated by default formulas. You will want to ignore effects that don't lend themselves to scaling - pet ID's, gate coords, etc. +int Mob::mod_effect_value(int effect_value, uint16 spell_id, int effect_type, Mob* caster) { + if(IsClient()) { return(effect_value); } + if(!caster) { return(effect_value); } + if(!caster->IsClient()) { return(effect_value); } + + float mult = 1.0f; + float spbonus = 0.0f; + float spadd = 0.0f; + + if(caster->GetClass() == BARD) + { + spbonus = (float)(caster->CastToClient()->GetActCHA() - DW_STATBASE) / 150; + spbonus += (float)(caster->CastToClient()->GetActINT() - DW_STATBASE) / 150; + } + else if(caster->GetCasterClass() == 'W') + { + spbonus = (float)(caster->CastToClient()->GetActWIS() - DW_STATBASE) / 400; + spbonus += (float)(caster->CastToClient()->GetActSTA() - DW_STATBASE) / 400; + } + else if(caster->GetCasterClass() == 'I') + { + spbonus = (float)(caster->CastToClient()->GetActINT() - DW_STATBASE) / 400; + spbonus += (float)(caster->CastToClient()->GetActDEX() - DW_STATBASE) / 400; + } + else + { + //No proc/click bonuses for non casters + return(effect_value); + } + + //Add a fixed value to help things like bard songs, dots, and other low effect value spells + spadd = (mult + spbonus) * ((float)caster->GetLevel() / 10); + if(caster->GetLevel() > 50) + { + float lbonus = caster->GetLevel() - 50; + spadd += spadd * (lbonus / 2); + } + + switch(effect_type) + { + case SE_CriticalHitChance: + case SE_SpellCritChance: + case SE_CrippBlowChance: + case SE_AvoidMeleeChance: + case SE_RiposteChance: + case SE_DodgeChance: + case SE_ParryChance: + case SE_DualWieldChance: + case SE_DoubleAttackChance: + case SE_MovementSpeed: + case SE_AttackSpeed4: + case SE_AttackSpeed3: + case SE_AttackSpeed2: + case SE_AttackSpeed: + if(caster->GetLevel() < 30) { spbonus = spbonus / 2; } + if(caster->GetLevel() >= 30 && caster->GetLevel() < 46) { spbonus = spbonus / 1.5; } + mult += spbonus; + //No fixed bonus on these types + spadd = 0; + break; + + case SE_CurrentHPOnce: + case SE_CurrentHP: + if(caster->GetLevel() < 30) { spbonus = spbonus / 2; } + if(caster->GetLevel() >= 30 && caster->GetLevel() < 46) { spbonus = spbonus / 1.5; } + mult += spbonus; + break; + + case SE_DamageShield: + case SE_Stun: + case SE_ArmorClass: + case SE_ATK: + case SE_STR: + case SE_DEX: + case SE_AGI: + case SE_STA: + case SE_INT: + case SE_WIS: + case SE_CHA: + case SE_CurrentMana: + case SE_Lull: + case SE_AddFaction: + case SE_Stamina: + case SE_ChangeFrenzyRad: + case SE_DiseaseCounter: + case SE_PoisonCounter: + case SE_ResistFire: + case SE_ResistCold: + case SE_ResistPoison: + case SE_ResistDisease: + case SE_ResistMagic: + case SE_Rune: + case SE_TotalHP: + case SE_TossUp: + case SE_ManaPool: + case SE_HealOverTime: + case SE_CastingLevel: + case SE_Hunger: + case SE_CurseCounter: + case SE_HealRate: + case SE_ImprovedDamage: + case SE_ImprovedHeal: + case SE_SpellResistReduction: + case SE_IncreaseSpellHaste: + case SE_IncreaseSpellDuration: + case SE_IncreaseRange: + case SE_AllStats: + case SE_MeleeLifetap: + case SE_AllInstrumentMod: + case SE_ResistSpellChance: + case SE_ResistFearChance: + case SE_HitChance: + case SE_DamageModifier: + case SE_MinDamageModifier: + case SE_IncreaseBlockChance: + case SE_CurrentEndurance: + case SE_EndurancePool: + case SE_CurrentEnduranceOnce: + case SE_MaxHPChange: + case SE_Accuracy: + case SE_BardAEDot: + case SE_CurrentManaOnce: + case SE_FactionMod: + case SE_CorruptionCounter: + case SE_ResistCorruption: + mult += spbonus; + break; + + default: + return(effect_value); + break; + } + + //Shroud of the bear + if(caster->FindBuff(5045)) + { + spadd = spadd * -1; + mult = 1.0f; + } + + if(effect_value > 0) { effect_value += (int)ceil(spadd); } + else { effect_value -= (int)ceil(spadd); } + + effect_value *= mult; + + return( (int)(ceil(effect_value)) ); +} + +//chancetohit - 0 to 100 percent - set over 1000 for a guaranteed hit +float Mob::mod_hit_chance(float chancetohit, SkillType skillinuse, Mob* attacker) { + if(!IsClient()) + { + //Factor NPC debuffs + return(chancetohit); + } + + int divisor; + + switch(GetClass()) + { + case MONK: + case ROGUE: + divisor = 8; + divisor -= (GetLevel() / 100) * 2; + break; + + default: + divisor = 8; + } + + float hitmod = ((float)CastToClient()->GetActDEX() - DW_STATBASE) / divisor; + hitmod += ((float)CastToClient()->GetActAGI() - DW_STATBASE) / divisor; + if(hitmod < 0) { hitmod = -5; } + + return(chancetohit + hitmod); +} + float Mob::mod_riposte_chance(float ripostechance, Mob* attacker) { return(ripostechance); } float Mob::mod_block_chance(float blockchance, Mob* attacker) { return(blockchance); } float Mob::mod_parry_chance(float parrychance, Mob* attacker) { return(parrychance); } @@ -57,16 +528,266 @@ float Mob::mod_dodge_chance(float dodgechance, Mob* attacker) { return(dodgechan float Mob::mod_monk_weight(float monkweight, Mob* attacker) { return(monkweight); } float Mob::mod_mitigation_rating(float mitigation_rating, Mob* attacker) { return(mitigation_rating); } float Mob::mod_attack_rating(float attack_rating, Mob* defender) { return(attack_rating); } -int32 Mob::mod_kick_damage(int32 dmg) { return(dmg); } -int32 Mob::mod_bash_damage(int32 dmg) { return(dmg); } -int32 Mob::mod_frenzy_damage(int32 dmg) { return(dmg); } -int32 Mob::mod_monk_special_damage(int32 ndamage, SkillType skill_type) { return(ndamage); } -int32 Mob::mod_backstab_damage(int32 ndamage) { return(ndamage); } + +//Kick damage after all other bonuses are applied +int32 Mob::mod_kick_damage(int32 dmg) { + if(!IsClient()) { return(dmg); } + + ItemInst *item = CastToClient()->GetInv().GetItem(SLOT_FEET); + if(item) + { + dmg += item->GetItem()->AC; + for(int i = 0; i < MAX_AUGMENT_SLOTS; ++i) + { + ItemInst *aug = item->GetAugment(i); + if(aug) + { + dmg += aug->GetItem()->AC; + } + } + } + dmg += GetLevel() / 4; + dmg = CastToClient()->mod_client_damage(dmg, KICK, 0, nullptr, nullptr); + + return(dmg); +} + +//Slam and bash damage after all other bonuses are applied +int32 Mob::mod_bash_damage(int32 dmg) { + if(!IsClient()) { return(dmg); } + + float lmult = (((float)GetLevel() * 2 ) / 100) + 1; + bool foundshield = false; + + ItemInst *item = CastToClient()->GetInv().GetItem(SLOT_SECONDARY); + if(item) + { + if(item->GetItem()->ItemType == ItemTypeShield) + { + foundshield = true; + dmg += item->GetItem()->AC * lmult; + for(int i = 0; i < MAX_AUGMENT_SLOTS; ++i) + { + ItemInst *aug = item->GetAugment(i); + if(aug) + { + dmg += aug->GetItem()->AC; + } + } + } + } + + if(!foundshield) //This is from a slam + { + item = CastToClient()->GetInv().GetItem(SLOT_SHOULDER); + if(item) + { + if(item->GetItem()->ItemType == ItemTypeArmor) + { + dmg += item->GetItem()->AC * lmult; + for(int i = 0; i < MAX_AUGMENT_SLOTS; ++i) + { + ItemInst *aug = item->GetAugment(i); + if(aug) + { + dmg += aug->GetItem()->AC; + } + } + } + } + } + + dmg += GetLevel() / 4; + dmg = CastToClient()->mod_client_damage(dmg, BASH, 0, nullptr, nullptr); + + return(dmg); +} + +//Frenzy damage after all other bonuses are applied +int32 Mob::mod_frenzy_damage(int32 dmg) { + if(!IsClient()) { return(dmg); } + + dmg = CastToClient()->mod_client_damage(dmg, FRENZY, 0, nullptr, nullptr); + return(dmg); +} + +//Special attack damage after all other bonuses are applied. +int32 Mob::mod_monk_special_damage(int32 ndamage, SkillType skill_type) { + if(!IsClient()) { return(ndamage); } + + ndamage = CastToClient()->mod_client_damage(ndamage, KICK, 0, nullptr, nullptr); + return(ndamage); +} + +//ndamage - Backstab damage as calculated by default formulas +int32 Mob::mod_backstab_damage(int32 ndamage) { + if(!IsClient()) { return(ndamage); } + + float cdex = (float)CastToClient()->GetActDEX() - DW_STATBASE; + float cstr = (float)CastToClient()->GetActSTR() - DW_STATBASE; + float cagi = (float)CastToClient()->GetActAGI() - DW_STATBASE; + float bsm = 1.0f; + + bsm += (cdex / 200) + ((float)GetLevel() / 100); + bsm += cstr / 300; + bsm += cagi / 300; + + if(GetLevel() > 50) + { + float lbonus = GetLevel() - 50; + bsm += (lbonus * 0.1); + } + + return( (int32)((float)ndamage * bsm) ); +} + +//Chance for 50+ archery bonus damage if Combat:UseArcheryBonusRoll is true. Base is Combat:ArcheryBonusChance int Mob::mod_archery_bonus_chance(int bonuschance, const ItemInst* RangeWeapon) { return(bonuschance); } -uint32 Mob::mod_archery_bonus_damage(uint32 MaxDmg) { return(MaxDmg); } -int32 Mob::mod_archery_damage(int32 TotalDmg, bool hasbonus) { return(TotalDmg); } -uint16 Mob::mod_throwing_damage(uint16 MaxDmg) { return(MaxDmg); } -int32 Mob::mod_cast_time(int32 cast_time) { return(cast_time); } -int Mob::mod_buff_duration(int res, Mob* caster, Mob* target, uint16 spell_id) { return(res); } -int Mob::mod_spell_stack(uint16 spellid1, int caster_level1, Mob* caster1, uint16 spellid2, int caster_level2, Mob* caster2) { return(2); } -int Mob::mod_spell_resist(int resist_chance, int level_mod, int resist_modifier, int target_resist, uint8 resist_type, uint16 spell_id, Mob* caster) { return(resist_chance + level_mod + resist_modifier + target_resist); } + +//Archery bonus damage +uint32 Mob::mod_archery_bonus_damage(uint32 MaxDmg, const ItemInst* RangeWeapon) { return(MaxDmg); } + +//Final archery damage including bonus if it was applied. +int32 Mob::mod_archery_damage(int32 TotalDmg, bool hasbonus, const ItemInst* RangeWeapon) { + if(!IsClient()) { return(TotalDmg); } + + TotalDmg += (GetLevel() * 2); + TotalDmg = CastToClient()->mod_client_damage(TotalDmg, ARCHERY, 0, RangeWeapon, nullptr); + + return(TotalDmg); +} + +//Thrown weapon damage after all other calcs +uint16 Mob::mod_throwing_damage(uint16 MaxDmg) { + if(!IsClient()) { return(MaxDmg); } + + MaxDmg = CastToClient()->mod_client_damage(MaxDmg, THROWING, 0, nullptr, nullptr); + return(MaxDmg); +} + +int32 Mob::mod_cast_time(int32 cast_time) { + if(!IsClient()) { return(cast_time); } + + float ctmod = 1; + float cdex = (float)CastToClient()->GetActDEX() - DW_STATBASE; + float ccast = 0; + + if(GetCasterClass() == 'W') + { + ccast = (float)CastToClient()->GetActWIS() - DW_STATBASE; + } + if(GetCasterClass() == 'I') + { + ccast = (float)CastToClient()->GetActINT() - DW_STATBASE; + } + if(ccast < 0.0001) { return(cast_time); } + + ctmod += cdex / 185; + ctmod += ccast / 185; + + if(GetLevel() > 50) + { + float lbonus = GetLevel() - 50; + ctmod += (lbonus * 0.1); + } + + return( (int32)((float)cast_time / ctmod) ); +} + +//res - Default buff duration formula +int Mob::mod_buff_duration(int res, Mob* caster, Mob* target, uint16 spell_id) { + if(!IsClient()) { return(res); } + + float cmult = 1; + + if(GetClass() == BARD) + { + cmult = (float)(CastToClient()->GetActCHA() - DW_STATBASE) / 200; + } + else if(GetCasterClass() == 'W') + { + cmult = (float)(CastToClient()->GetActWIS() - DW_STATBASE) / 200; + } + else if(GetCasterClass() == 'I') + { + cmult = (float)(CastToClient()->GetActINT() - DW_STATBASE) / 200; + } + + cmult += (float)(CastToClient()->GetActSTA() - DW_STATBASE) / 400; + + if(cmult < 1) { cmult = 1; } + + return( (int)((float)res * cmult) ); +} + +//Spell stack override - If this returns anything < 2, it will ignore all other stacking rules. +// See spells.cpp: Mob::CheckStackConflict +// 0 - No conflict +// 1 - Overwrite, spellid1 is replaced by spellid2 +// -1 - Blocked, spellid2 will not land +// 2 - Default stacking behavior +int Mob::mod_spell_stack(uint16 spellid1, int caster_level1, Mob* caster1, uint16 spellid2, int caster_level2, Mob* caster2) { + + if(IsEffectInSpell(spellid1, SE_Illusion) && IsEffectInSpell(spellid2, SE_Illusion)) + { + return(1); + } + return(2); +} + +//Sum of various resists rolled against a value of 200. +int Mob::mod_spell_resist(int resist_chance, int level_mod, int resist_modifier, int target_resist, uint8 resist_type, uint16 spell_id, Mob* caster) { + int final = resist_chance + level_mod + resist_modifier + target_resist; + + int temp_level_diff = GetLevel() - caster->GetLevel(); + if(temp_level_diff > 15 && caster->GetLevel() < 46) + { + if(caster->IsClient()) + { + if(caster->CastToClient()->GetAAXP() < 100) + { + return(0); + } + } + } + + if(final > 185) { final = 185; } // Cap resist so it's always possible to land a spell (unless we hit the client level diff max). + if(!IsClient()) { return(final); } + + float resistmod = 1.0f; + + //Make charisma a part of all resists + resistmod += ((float)CastToClient()->GetActCHA() - DW_STATBASE) / 20; + + //The other half is the casting stat + if(GetClass() == BARD) + { + resistmod += ((float)CastToClient()->GetActCHA() - DW_STATBASE) / 20; + } + else if(GetCasterClass() == 'W') + { + resistmod += ((float)CastToClient()->GetActWIS() - DW_STATBASE) / 20; + } + else if(GetCasterClass() == 'I') + { + resistmod += ((float)CastToClient()->GetActINT() - DW_STATBASE) / 20; + } + + final += resistmod; + + if(caster->GetLevel() > 50) + { + final -= (int)( (caster->GetLevel() - 50) * 20 ); + } + + //Let the client be highly resistant to their own AoE + if( + (spells[spell_id].targettype == ST_AECaster || spells[spell_id].targettype == ST_AETarget) && + caster->CastToClient()->CharacterID() == CastToClient()->CharacterID() + ) + { + final = 185; + } + + return(final); +} diff --git a/zone/npc.h b/zone/npc.h index cd9b2baaa..d33dd4a3c 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -457,7 +457,7 @@ public: uint32 GetSpawnKillCount(); int GetScore(); void mod_prespawn(Spawn2 *sp); - int mod_npc_damage(int damage, SkillType skillinuse, int hand, ItemInst* weapon, Mob* other); + int mod_npc_damage(int damage, SkillType skillinuse, int hand, const Item_Struct* weapon, Mob* other); void mod_npc_killed_merit(Mob* c); void mod_npc_killed(Mob* oos); diff --git a/zone/special_attacks.cpp b/zone/special_attacks.cpp index 4950e3b35..29e86cdd4 100644 --- a/zone/special_attacks.cpp +++ b/zone/special_attacks.cpp @@ -904,7 +904,7 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item { MaxDmg *= (float)2; hate *= (float)2; - MaxDmg = mod_archery_bonus_damage(MaxDmg); + MaxDmg = mod_archery_bonus_damage(MaxDmg, RangeWeapon); mlog(COMBAT__RANGED, "Ranger. Double damage success roll, doubling damage to %d", MaxDmg); Message_StringID(MT_CritMelee, BOW_DOUBLE_DAMAGE); @@ -937,7 +937,7 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item TotalDmg += other->GetAdditionalDamage(this, 0, true, ARCHERY); TotalDmg += (itembonuses.HeroicDEX / 10) + (TotalDmg * other->GetSkillDmgTaken(ARCHERY) / 100) + GetSkillDmgAmt(ARCHERY); - TotalDmg = mod_archery_damage(TotalDmg, dobonus); + TotalDmg = mod_archery_damage(TotalDmg, dobonus, RangeWeapon); TryCriticalHit(other, ARCHERY, TotalDmg); other->AddToHateList(this, hate, 0, false); From 1b9647f57ecd7b96190dd727c4b47e29662c86bb Mon Sep 17 00:00:00 2001 From: root Date: Fri, 17 May 2013 12:27:18 -0500 Subject: [PATCH 02/12] Updated mod_functions with DC examples --- zone/client.h | 2 +- zone/mod_functions.cpp | 2 +- zone/mod_functions_base.cpp | 78 ++++++++++++++++++++++++++++++++++--- zone/tribute.cpp | 2 +- 4 files changed, 76 insertions(+), 8 deletions(-) diff --git a/zone/client.h b/zone/client.h index 3be422a2b..1da5b1551 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1125,7 +1125,7 @@ public: int16 mod_pet_power(int16 act_power, uint16 spell_id); float mod_tradeskill_chance(float chance, DBTradeskillRecipe_Struct *spec); float mod_tradeskill_skillup(float chance_stage2); - int32 mod_tribute_item_value(int32 pts); + int32 mod_tribute_item_value(int32 pts, const ItemInst* item); void mod_client_death_npc(Mob* killerMob); void mod_client_death_duel(Mob* killerMob); void mod_client_death_env(); diff --git a/zone/mod_functions.cpp b/zone/mod_functions.cpp index a6088ee02..6d6d6cbbb 100644 --- a/zone/mod_functions.cpp +++ b/zone/mod_functions.cpp @@ -314,7 +314,7 @@ float Client::mod_tradeskill_skillup(float chance_stage2) { } //Tribute value override -int32 Client::mod_tribute_item_value(int32 pts) { +int32 Client::mod_tribute_item_value(int32 pts, const ItemInst* item) { return(0); } diff --git a/zone/mod_functions_base.cpp b/zone/mod_functions_base.cpp index af228ed9e..94750a184 100644 --- a/zone/mod_functions_base.cpp +++ b/zone/mod_functions_base.cpp @@ -23,33 +23,71 @@ extern WorldServer worldserver; using namespace std; +//All functions that modify a value are passed the value as it was computed by default formulas and bonuses. In most cases this should be the final value that will be used. + +//These are called when a zone boots or is repopped void Zone::mod_init() { return; } void Zone::mod_repop() { return; } +//Pre-spawn hook called from the NPC object to be spawned void NPC::mod_prespawn(Spawn2 *sp) { return; } -int NPC::mod_npc_damage(int damage, SkillType skillinuse, int hand, ItemInst* weapon, Mob* other) { return(damage); } + +//Base damage from NPC::Attack +int NPC::mod_npc_damage(int damage, SkillType skillinuse, int hand, const Item_Struct* weapon, Mob* other) { return(damage); } void NPC::mod_npc_killed_merit(Mob* c) { return; } void NPC::mod_npc_killed(Mob* oos) { return; } -int Client::mod_client_damage(int damage, SkillType skillinuse, int hand, ItemInst* weapon, Mob* other) { return(damage); } +//Base damage from Client::Attack - can cover myriad skill types +int Client::mod_client_damage(int damage, SkillType skillinuse, int hand, const ItemInst* weapon, Mob* other) { return(final); } + +//message is char[4096], don't screw it up. bool Client::mod_client_message(char* message, uint8 chan_num) { return(true); } //Potentially dangerous string handling here + +//Skillup override. When this is called the regular skillup check has failed. Return false to proceed with default behavior. +//This will NOT allow a client to increase skill past a cap. bool Client::mod_can_increase_skill(SkillType skillid, Mob* against_who) { return(false); } + +//chance of general skill increase, rolled against 0-99 where higher chance is better. int16 Client::mod_increase_skill_chance(int16 chance, Mob* against_who) { return(chance); } + +//Max percent of health you can bind wound starting with default value for class, item, and AA bonuses int Client::mod_bindwound_percent(int max_percent, Mob* bindmob) { return(max_percent); } + +//Final bind HP value after bonuses int Client::mod_bindwound_hp(int bindhps, Mob* bindmob) { return(bindhps); } + +//Client haste as calculated by default formulas - In percent from 0-100 int Client::mod_client_haste(int h) { return(h); } + void Client::mod_consider(Mob* tmob, Consider_Struct* con) { return; } bool Client::mod_saylink(const std::string&, bool silentsaylink) { return(true); } + +//Client pet power as calculated by default formulas and bonuses int16 Client::mod_pet_power(int16 act_power, uint16 spell_id) { return(act_power); } + +//Chance to combine rolled against a random 0-99 where higher is better. float Client::mod_tradeskill_chance(float chance, DBTradeskillRecipe_Struct *spec) { return(chance); } + +//Chance to skillup rolled against a random 0-99 where higher is better. float Client::mod_tradeskill_skillup(float chance_stage2) { return(chance_stage2); } -int32 Client::mod_tribute_item_value(int32 pts) { return(pts); } + +//Item Tribute value override -- Need to pass the item, duh. +int32 Client::mod_tribute_item_value(int32 pts, const ItemInst* item) { return(pts); } + +//Death reporting void Client::mod_client_death_npc(Mob* killerMob) { return; } void Client::mod_client_death_duel(Mob* killerMob) { return; } void Client::mod_client_death_env() { return; } +//Calculated xp before consider modifier +int32 Client::mod_client_xp(int32 in_xp, NPC *npc) { return(in_xp); } + +//effect_vallue - Spell effect value as calculated by default formulas. You will want to ignore effects that don't lend themselves to scaling - pet ID's, gate coords, etc. int Mob::mod_effect_value(int effect_value, uint16 spell_id, int effect_type, Mob* caster) { return(effect_value); } + +//chancetohit - 0 to 100 percent - set over 1000 for a guaranteed hit float Mob::mod_hit_chance(float chancetohit, SkillType skillinuse, Mob* attacker) { return(chancetohit); } + float Mob::mod_riposte_chance(float ripostechance, Mob* attacker) { return(ripostechance); } float Mob::mod_block_chance(float blockchance, Mob* attacker) { return(blockchance); } float Mob::mod_parry_chance(float parrychance, Mob* attacker) { return(parrychance); } @@ -57,16 +95,46 @@ float Mob::mod_dodge_chance(float dodgechance, Mob* attacker) { return(dodgechan float Mob::mod_monk_weight(float monkweight, Mob* attacker) { return(monkweight); } float Mob::mod_mitigation_rating(float mitigation_rating, Mob* attacker) { return(mitigation_rating); } float Mob::mod_attack_rating(float attack_rating, Mob* defender) { return(attack_rating); } + +//Kick damage after all other bonuses are applied int32 Mob::mod_kick_damage(int32 dmg) { return(dmg); } + +//Slam and bash damage after all other bonuses are applied int32 Mob::mod_bash_damage(int32 dmg) { return(dmg); } + +//Frenzy damage after all other bonuses are applied int32 Mob::mod_frenzy_damage(int32 dmg) { return(dmg); } + +//Special attack damage after all other bonuses are applied. int32 Mob::mod_monk_special_damage(int32 ndamage, SkillType skill_type) { return(ndamage); } + +//ndamage - Backstab damage as calculated by default formulas int32 Mob::mod_backstab_damage(int32 ndamage) { return(ndamage); } + +//Chance for 50+ archery bonus damage if Combat:UseArcheryBonusRoll is true. Base is Combat:ArcheryBonusChance int Mob::mod_archery_bonus_chance(int bonuschance, const ItemInst* RangeWeapon) { return(bonuschance); } -uint32 Mob::mod_archery_bonus_damage(uint32 MaxDmg) { return(MaxDmg); } -int32 Mob::mod_archery_damage(int32 TotalDmg, bool hasbonus) { return(TotalDmg); } + +//Archery bonus damage +uint32 Mob::mod_archery_bonus_damage(uint32 MaxDmg, const ItemInst* RangeWeapon) { return(MaxDmg); } + +//Final archery damage including bonus if it was applied. +int32 Mob::mod_archery_damage(int32 TotalDmg, bool hasbonus, const ItemInst* RangeWeapon) { return(TotalDmg); } + +//Thrown weapon damage after all other calcs uint16 Mob::mod_throwing_damage(uint16 MaxDmg) { return(MaxDmg); } + int32 Mob::mod_cast_time(int32 cast_time) { return(cast_time); } + +//res - Default buff duration formula int Mob::mod_buff_duration(int res, Mob* caster, Mob* target, uint16 spell_id) { return(res); } + +//Spell stack override - If this returns anything < 2, it will ignore all other stacking rules. +// See spells.cpp: Mob::CheckStackConflict +// 0 - No conflict +// 1 - Overwrite, spellid1 is replaced by spellid2 +// -1 - Blocked, spellid2 will not land +// 2 - Default stacking behavior int Mob::mod_spell_stack(uint16 spellid1, int caster_level1, Mob* caster1, uint16 spellid2, int caster_level2, Mob* caster2) { return(2); } + +//Sum of various resists rolled against a value of 200. int Mob::mod_spell_resist(int resist_chance, int level_mod, int resist_modifier, int target_resist, uint8 resist_type, uint16 spell_id, Mob* caster) { return(resist_chance + level_mod + resist_modifier + target_resist); } diff --git a/zone/tribute.cpp b/zone/tribute.cpp index 9d864a72d..b536ecdf9 100644 --- a/zone/tribute.cpp +++ b/zone/tribute.cpp @@ -252,7 +252,7 @@ int32 Client::TributeItem(uint32 slot, uint32 quantity) { //figure out what its worth int32 pts = inst->GetItem()->Favor; - pts = mod_tribute_item_value(pts); + pts = mod_tribute_item_value(pts, m_inv[slot]); if(pts < 1) { Message(13, "This item is worthless for favor."); From 7b21e3be722f9747fd33c55a1e304a98421d8360 Mon Sep 17 00:00:00 2001 From: Tabasco Date: Sat, 18 May 2013 11:21:19 -0500 Subject: [PATCH 03/12] Added server man quest events and command parsing. --- zone/embparser.cpp | 3 + zone/embparser.h | 1 + zone/mod_functions.cpp | 146 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 139 insertions(+), 11 deletions(-) diff --git a/zone/embparser.cpp b/zone/embparser.cpp index b27293de4..6d01e8b37 100644 --- a/zone/embparser.cpp +++ b/zone/embparser.cpp @@ -589,6 +589,9 @@ void PerlembParser::EventCommon(QuestEventID event, uint32 objid, const char * d safe_delete_array(hi_decl); } } + + mod_quest_event(event, objid, data, npcmob, iteminst, mob, extradata, global, packagename); + //do any event-specific stuff... switch (event) { case EVENT_SAY: { diff --git a/zone/embparser.h b/zone/embparser.h index 2181f6db0..43f52c303 100644 --- a/zone/embparser.h +++ b/zone/embparser.h @@ -144,6 +144,7 @@ public: virtual void SendCommands(const char * pkgprefix, const char *event, uint32 npcid, Mob* other, Mob* mob, ItemInst* iteminst); int HasQuestFile(uint32 npcid); + void mod_quest_event(QuestEventID event, uint32 objid, const char * data, NPC* npcmob, ItemInst* iteminst, Mob* mob, uint32 extradata, bool global, std::string packagename); #ifdef EMBPERL_COMMANDS void ExecCommand(Client *c, Seperator *sep); diff --git a/zone/mod_functions.cpp b/zone/mod_functions.cpp index 6d6d6cbbb..fe1b8e937 100644 --- a/zone/mod_functions.cpp +++ b/zone/mod_functions.cpp @@ -13,6 +13,8 @@ #include "client.h" #include "worldserver.h" #include "QuestParserCollection.h" +#include "event_codes.h" +#include "embparser.h" #include #include @@ -25,8 +27,29 @@ using namespace std; #define DW_STATBASE 70 -void Zone::mod_init() { return; } -void Zone::mod_repop() { return; } +void Zone::mod_init() { + const NPCType* tmp = 0; + if((tmp = database.GetNPCType(999999))) + { + NPC* npc = new NPC(tmp, 0, 0, 0, 0, 0, FlyMode3); + if(npc) + { + entity_list.AddNPC(npc); + } + } +} + +void Zone::mod_repop() { + const NPCType* tmp = 0; + if((tmp = database.GetNPCType(999999))) + { + NPC* npc = new NPC(tmp, 0, 0, 0, 0, 0, FlyMode3); + if(npc) + { + entity_list.AddNPC(npc); + } + } +} void NPC::mod_prespawn(Spawn2 *sp) { //The spawn has to have 1 kill to qualify @@ -85,8 +108,23 @@ int NPC::mod_npc_damage(int damage, SkillType skillinuse, int hand, const Item_S return(damage); } -void NPC::mod_npc_killed_merit(Mob* c) { return; } -void NPC::mod_npc_killed(Mob* oos) { return; } +//Mob c has been given credit for a kill. This is called after the regular EVENT_KILLED_MERIT event. +void NPC::mod_npc_killed_merit(Mob* c) { + Mob *tmpmob = entity_list.GetMobByNpcTypeID(999999); + if(tmpmob) + { + parse->EventNPC(EVENT_KILLED_MERIT, tmpmob->CastToNPC(), c, this->GetCleanName(), this->GetNPCTypeID()); + } +} + +//Mob oos has been given credit for a kill. This is called after the regular EVENT_DEATH event. +void NPC::mod_npc_killed(Mob* oos) { + Mob *tmpmob = entity_list.GetMobByNpcTypeID(999999); + if(tmpmob) + { + parse->EventNPC(EVENT_DEATH, tmpmob->CastToNPC(), oos, this->GetCleanName(), this->GetNPCTypeID()); + } +} //Base damage from Client::Attack - can cover myriad skill types int Client::mod_client_damage(int damage, SkillType skillinuse, int hand, const ItemInst* weapon, Mob* other) { @@ -204,8 +242,23 @@ int Client::mod_client_damage(int damage, SkillType skillinuse, int hand, const } -//message is char[4096], don't screw it up. -bool Client::mod_client_message(char* message, uint8 chan_num) { return(true); } //Potentially dangerous string handling here +//message is char[4096], don't screw it up. Return true for normal behavior, false to return immediately. +bool Client::mod_client_message(char* message, uint8 chan_num) { + //!commands for serverman + if(message[0] == '!' && chan_num == 8) + { + Mob *tmpmob = entity_list.GetMobByNpcTypeID(999999); + if(tmpmob) + { + parse->EventNPC(EVENT_SAY, tmpmob->CastToNPC(), this, message, 0); + return(false); + } + Message(315, "Your pants are on sideways."); + return(false); + } + + return(true); +} //Potentially dangerous string handling here //Skillup override. When this is called the regular skillup check has failed. Return false to proceed with default behavior. //This will NOT allow a client to increase skill past a cap. @@ -287,8 +340,29 @@ int Client::mod_client_haste(int h) { return(h); } -void Client::mod_consider(Mob* tmob, Consider_Struct* con) { return; } -bool Client::mod_saylink(const std::string&, bool silentsaylink) { return(true); } +//This is called when a client cons a mob +void Client::mod_consider(Mob* tmob, Consider_Struct* con) { + if(tmob->GetLastName()[0] == '[') + { + Message(14, "%s", tmob->GetLastName()); + } +} + +//Return true to continue with normal behavior +bool Client::mod_saylink(const std::string& response, bool silentsaylink) { + if(silentsaylink && strlen(response.c_str()) > 1 && response[0] == '%' && response[1] == '!') + { + Mob *tmpmob = entity_list.GetMobByNpcTypeID(999999); + if(tmpmob) + { + parse->EventNPC(EVENT_SAY, tmpmob->CastToNPC(), this, response, 0); + return(false); + } + Message(315, "Your pants are on sideways."); + return(false); + } + return(true); +} //Client pet power as calculated by default formulas and bonuses int16 Client::mod_pet_power(int16 act_power, uint16 spell_id) { @@ -319,9 +393,30 @@ int32 Client::mod_tribute_item_value(int32 pts, const ItemInst* item) { } //Death reporting -void Client::mod_client_death_npc(Mob* killerMob) { return; } -void Client::mod_client_death_duel(Mob* killerMob) { return; } -void Client::mod_client_death_env() { return; } +void Client::mod_client_death_npc(Mob* killerMob) { + Mob *tmpmob = entity_list.GetMobByNpcTypeID(999999); + if(tmpmob) + { + parse->EventNPC(EVENT_SLAY, tmpmob->CastToNPC(), this, killerMob->GetCleanName(), killerMob->GetLevel()); + } +} + +void Client::mod_client_death_duel(Mob* killerMob) { + Mob *tmpmob = entity_list.GetMobByNpcTypeID(999999); + if(tmpmob) + { + std::string pname = std::string("PLAYER|") + killerMob->GetCleanName(); + parse->EventNPC(EVENT_SLAY, tmpmob->CastToNPC(), this, pname.c_str(), killerMob->GetLevel()); + } +} + +void Client::mod_client_death_env() { + Mob *tmpmob = entity_list.GetMobByNpcTypeID(999999); + if(tmpmob) + { + parse->EventNPC(EVENT_SLAY, tmpmob->CastToNPC(), this, "ENVIRONMENT", 0); + } +} //Calculated xp before consider modifier int32 Client::mod_client_xp(int32 in_xp, NPC *npc) { @@ -791,3 +886,32 @@ int Mob::mod_spell_resist(int resist_chance, int level_mod, int resist_modifier, return(final); } + +//This is called right before regular event processing (the switch block) +void PerlembParser::mod_quest_event(QuestEventID event, uint32 objid, const char * data, NPC* npcmob, ItemInst* iteminst, Mob* mob, uint32 extradata, bool global, std::string packagename) { + NPC *tnpc = 0; + + if(event == EVENT_KILLED_MERIT || event == EVENT_CAST_ON || event == EVENT_SLAY) + { + const NPCType* tmp = 0; + if((tmp = database.GetNPCType(extradata))) + { + tnpc = new NPC(tmp, 0, 0, 0, 0, 0, FlyMode3); + } + else + { + tnpc = npcmob; + } + + if(tnpc) + { + ExportVar(packagename.c_str(), "npcname", tnpc->GetCleanName()); + ExportVar(packagename.c_str(), "npclastname", tnpc->GetLastName()); + ExportVar(packagename.c_str(), "npclevel", tnpc->GetLevel()); + ExportVar(packagename.c_str(), "bodytype", tnpc->GetBodyType()); + ExportVar(packagename.c_str(), "npcid", tnpc->GetNPCTypeID()); + ExportVar(packagename.c_str(), "npcrace", tnpc->GetRace()); + ExportVar(packagename.c_str(), "npcclass", tnpc->GetClass()); + } + } +} From 1e5d6b0e349aad00d63fb39d710d597e2fbe9769 Mon Sep 17 00:00:00 2001 From: Tabasco Date: Mon, 20 May 2013 16:24:10 -0500 Subject: [PATCH 04/12] Chat filter tests --- zone/mod_functions.cpp | 146 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 139 insertions(+), 7 deletions(-) diff --git a/zone/mod_functions.cpp b/zone/mod_functions.cpp index fe1b8e937..e3d05f3c5 100644 --- a/zone/mod_functions.cpp +++ b/zone/mod_functions.cpp @@ -243,6 +243,19 @@ int Client::mod_client_damage(int damage, SkillType skillinuse, int hand, const //message is char[4096], don't screw it up. Return true for normal behavior, false to return immediately. +// Channels: +// 0 - Guild Chat +// 2 - Group Chat +// 3 - Shout +// 4 - Auction +// 5 - Out of Character +// 6 - Broadcast +// 7 - Tell +// 8 - Say +// 11 - GMSay +// 15 - Raid Chat +// 20 - UCS Relay for UF client and later +// 22 - Emotes for UF and later bool Client::mod_client_message(char* message, uint8 chan_num) { //!commands for serverman if(message[0] == '!' && chan_num == 8) @@ -257,6 +270,50 @@ bool Client::mod_client_message(char* message, uint8 chan_num) { return(false); } +/* + //Parse out link notation + Seperator ms(message, ' ', 20); + + std::string finalmsg(""); + bool modded = false; + for(int i = 0; i < ms.GetMaxArgNum(); i++) + { + if(i > 0) { finalmsg += " "; } + if(strlen(ms.arg[i]) < 5) { finalmsg += ms.arg[i]; continue; } + + if( ms.arg[i][0] == '$' && ms.arg[i][1] == 'N' && ms.arg[i][2] == 'P' && ms.arg[i][3] == 'C') + { + std::string npclink("%!!dbnav NPC "); + std::string npctext("NPC:"); + for(int x = 4; x < strlen(ms.arg[i]); x++) + { + npclink += ms.arg[i][x]; + npctext += ms.arg[i][x]; + } + modded = true; + char text[250]; + sprintf(text, "%S", npclink.c_str()); + finalmsg += quest_manager.saylink( text, true, const_cast(npctext.c_str()) ); + } + else if( ms.arg[i][0] == '$' && ms.arg[i][1] == 'T' && ms.arg[i][2] == 'E' && ms.arg[i][3] == 'S' && ms.arg[i][4] == 'T') + { + modded = true; + char text[250]; + sprintf(text, "%%!!help"); + finalmsg += quest_manager.saylink( text, true, text ); + finalmsg += "DBLINK TEST"; + } + else + { + finalmsg += ms.arg[i]; + } + } + + if(modded) + { + strn0cpy(message, finalmsg.c_str(), 4096); + } +*/ return(true); } //Potentially dangerous string handling here @@ -616,13 +673,88 @@ float Mob::mod_hit_chance(float chancetohit, SkillType skillinuse, Mob* attacker return(chancetohit + hitmod); } -float Mob::mod_riposte_chance(float ripostechance, Mob* attacker) { return(ripostechance); } -float Mob::mod_block_chance(float blockchance, Mob* attacker) { return(blockchance); } -float Mob::mod_parry_chance(float parrychance, Mob* attacker) { return(parrychance); } -float Mob::mod_dodge_chance(float dodgechance, Mob* attacker) { return(dodgechance); } -float Mob::mod_monk_weight(float monkweight, Mob* attacker) { return(monkweight); } -float Mob::mod_mitigation_rating(float mitigation_rating, Mob* attacker) { return(mitigation_rating); } -float Mob::mod_attack_rating(float attack_rating, Mob* defender) { return(attack_rating); } +//Final riposte chance +float Mob::mod_riposte_chance(float ripostechance, Mob* attacker) { + if(!IsClient()) { return(ripostechance); } + return(ripostechance + CastToClient()->GetActSTA()/200); +} + +//Final block chance +float Mob::mod_block_chance(float blockchance, Mob* attacker) { + if(!IsClient()) { return(blockchance); } + return(blockchance + CastToClient()->GetActSTA()/200); +} + +//Final parry chance +float Mob::mod_parry_chance(float parrychance, Mob* attacker) { + if(!IsClient()) { return(parrychance); } + return(parrychance + CastToClient()->GetActDEX()/200); +} + +//Final dodge chance +float Mob::mod_dodge_chance(float dodgechance, Mob* attacker) { + if(!IsClient()) { return(dodgechance); } + return(dodgechance + CastToClient()->GetActAGI()/200); +} + +//Monk AC Bonus weight cap. Defined in Combat:MonkACBonusWeight +//Usually 15, a monk under this weight threshold gets an AC bonus +float Mob::mod_monk_weight(float monkweight, Mob* attacker) { + if(!IsClient()) { return(monkweight); } + + monkweight += (CastToClient()->GetActAGI()/100) + (CastToClient()->GetActSTR()/50); + return(monkweight); +} + +//Mitigation rating is compared to incoming attack rating. Higher is better. +float Mob::mod_mitigation_rating(float mitigation_rating, Mob* attacker) { + if(!IsClient()) { return(mitigation_rating); } + + int shield_ac = 0; + float armor = (float)CastToClient()->GetRawACNoShield(shield_ac); + + switch(GetClass()) + { + case WARRIOR: + return(mitigation_rating + (armor/2)); + + case SHADOWKNIGHT: + case PALADIN: + return(mitigation_rating + (armor/3)); + + case RANGER: + case ROGUE: + case BARD: + return(mitigation_rating + (armor/5)); + + default: + return(mitigation_rating); + } + + //Shouldn't ever get here + return(mitigation_rating); +} + +float Mob::mod_attack_rating(float attack_rating, Mob* defender) { + if(!IsClient()) { return(attack_rating); } + + float hprmult = 1 + (1 - (GetHP()/GetMaxHP())); + + switch(GetClass()) + { + case BERSERKER: + return(attack_rating * hprmult); + + case ROGUE: + if( BehindMob(defender, GetX(), GetY()) ) { return(attack_rating * 2); } + else { return(attack_rating); } + + default: + return(attack_rating); + } + + return(attack_rating); +} //Kick damage after all other bonuses are applied int32 Mob::mod_kick_damage(int32 dmg) { From 930fda07c94b5d565178ae8c029f6c2f61ea09e0 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 22 May 2013 07:19:09 -0500 Subject: [PATCH 05/12] Added exp for level mod, misc fixes. --- zone/client.h | 1 + zone/exp.cpp | 5 ++- zone/mod_functions.cpp | 89 +++++++++++++++++++++++++++--------------- zone/questmgr.cpp | 2 +- 4 files changed, 64 insertions(+), 33 deletions(-) diff --git a/zone/client.h b/zone/client.h index 1da5b1551..46ee8f4fd 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1130,6 +1130,7 @@ public: void mod_client_death_duel(Mob* killerMob); void mod_client_death_env(); int32 mod_client_xp(int32 in_exp, NPC *npc); + uint32 mod_client_xp_for_level(uint32 xp, uint16 check_level); protected: friend class Mob; diff --git a/zone/exp.cpp b/zone/exp.cpp index 853bc555e..dab513750 100644 --- a/zone/exp.cpp +++ b/zone/exp.cpp @@ -485,7 +485,10 @@ uint32 Client::GetEXPForLevel(uint16 check_level) mod *= 1000; - return(uint32(base * mod)); + uint32 finalxp = (uint32)(base * mod); + finalxp = mod_client_xp_for_level(finalxp, check_level); + + return(finalxp); } void Client::AddLevelBasedExp(uint8 exp_percentage, uint8 max_level) { diff --git a/zone/mod_functions.cpp b/zone/mod_functions.cpp index e3d05f3c5..4a6b32117 100644 --- a/zone/mod_functions.cpp +++ b/zone/mod_functions.cpp @@ -96,7 +96,7 @@ int NPC::mod_npc_damage(int damage, SkillType skillinuse, int hand, const Item_S if(weapon) { - damage += (int)ceil(((float)weapon->Damage / (float)weapon->Delay) * (float)GetLevel()); + damage += (int)ceil(((float)weapon->Damage / (float)weapon->Delay) * (float)GetOwner()->GetLevel()); } damage = (int)ceil( (float)damage * chbonus ); @@ -495,9 +495,22 @@ int32 Client::mod_client_xp(int32 in_xp, NPC *npc) { return( (int32)((float)in_xp * xpmult) ); } +//Client XP formula. Changes here will cause clients to change level after gaining or losing xp. +//Either modify this before your server goes live, or be prepared to write a quest script that fixes levels. +uint32 Client::mod_client_xp_for_level(uint32 xp, uint16 check_level) { + uint16 check_levelm1 = check_level-1; + float mod; + + mod = 4; + float base = (check_levelm1)*(check_levelm1)*(check_levelm1); + mod *= 1000; + + return(uint32(base * mod)); +} + //effect_vallue - Spell effect value as calculated by default formulas. You will want to ignore effects that don't lend themselves to scaling - pet ID's, gate coords, etc. int Mob::mod_effect_value(int effect_value, uint16 spell_id, int effect_type, Mob* caster) { - if(IsClient()) { return(effect_value); } +// if(IsClient()) { return(effect_value); } if(!caster) { return(effect_value); } if(!caster->IsClient()) { return(effect_value); } @@ -505,24 +518,31 @@ int Mob::mod_effect_value(int effect_value, uint16 spell_id, int effect_type, Mo float spbonus = 0.0f; float spadd = 0.0f; - if(caster->GetClass() == BARD) - { - spbonus = (float)(caster->CastToClient()->GetActCHA() - DW_STATBASE) / 150; - spbonus += (float)(caster->CastToClient()->GetActINT() - DW_STATBASE) / 150; - } - else if(caster->GetCasterClass() == 'W') + int adval = caster->CastToClient()->Admin(); +// adval = 0; + + if(caster->GetCasterClass() == 'W') { spbonus = (float)(caster->CastToClient()->GetActWIS() - DW_STATBASE) / 400; spbonus += (float)(caster->CastToClient()->GetActSTA() - DW_STATBASE) / 400; } else if(caster->GetCasterClass() == 'I') { - spbonus = (float)(caster->CastToClient()->GetActINT() - DW_STATBASE) / 400; - spbonus += (float)(caster->CastToClient()->GetActDEX() - DW_STATBASE) / 400; + if(caster->GetClass() == BARD) + { + spbonus = (float)(caster->CastToClient()->GetActCHA() - DW_STATBASE) / 150; + spbonus += (float)(caster->CastToClient()->GetActINT() - DW_STATBASE) / 150; + } + else + { + spbonus = (float)(caster->CastToClient()->GetActINT() - DW_STATBASE) / 400; + spbonus += (float)(caster->CastToClient()->GetActDEX() - DW_STATBASE) / 400; + } } else { //No proc/click bonuses for non casters + if(adval > 80) { caster->Message(315, "CASTER CLASS NOT FOUND"); } return(effect_value); } @@ -625,6 +645,7 @@ int Mob::mod_effect_value(int effect_value, uint16 spell_id, int effect_type, Mo break; default: + if(adval > 80) { caster->Message(315, "Generic effect - ignored"); } return(effect_value); break; } @@ -632,6 +653,7 @@ int Mob::mod_effect_value(int effect_value, uint16 spell_id, int effect_type, Mo //Shroud of the bear if(caster->FindBuff(5045)) { + if(adval > 80) { caster->Message(315, "Shroud of bear nerf"); } spadd = spadd * -1; mult = 1.0f; } @@ -641,6 +663,8 @@ int Mob::mod_effect_value(int effect_value, uint16 spell_id, int effect_type, Mo effect_value *= mult; + if(adval > 80) { caster->Message(315, "Spell Bonus: %d, %d, %d", effect_value, spadd, effect_type); } + return( (int)(ceil(effect_value)) ); } @@ -966,41 +990,44 @@ int Mob::mod_spell_stack(uint16 spellid1, int caster_level1, Mob* caster1, uint1 int Mob::mod_spell_resist(int resist_chance, int level_mod, int resist_modifier, int target_resist, uint8 resist_type, uint16 spell_id, Mob* caster) { int final = resist_chance + level_mod + resist_modifier + target_resist; - int temp_level_diff = GetLevel() - caster->GetLevel(); - if(temp_level_diff > 15 && caster->GetLevel() < 46) - { - if(caster->IsClient()) - { - if(caster->CastToClient()->GetAAXP() < 100) - { - return(0); - } - } - } - if(final > 185) { final = 185; } // Cap resist so it's always possible to land a spell (unless we hit the client level diff max). - if(!IsClient()) { return(final); } + + if(!caster) { return(final); } + + int temp_level_diff = GetLevel() - caster->GetLevel(); + if(temp_level_diff > 15 && caster->GetLevel() < 46) + { + if(caster->IsClient()) + { + if(caster->CastToClient()->GetAAXP() < 100) + { + return(0); + } + } + } + + if(!caster->IsClient()) { return(final); } float resistmod = 1.0f; //Make charisma a part of all resists - resistmod += ((float)CastToClient()->GetActCHA() - DW_STATBASE) / 20; + resistmod += ((float)caster->CastToClient()->GetActCHA() - DW_STATBASE) / 20; //The other half is the casting stat - if(GetClass() == BARD) + if(caster->GetClass() == BARD) { - resistmod += ((float)CastToClient()->GetActCHA() - DW_STATBASE) / 20; + resistmod += ((float)caster->CastToClient()->GetActCHA() - DW_STATBASE) / 20; } - else if(GetCasterClass() == 'W') + else if(caster->GetCasterClass() == 'W') { - resistmod += ((float)CastToClient()->GetActWIS() - DW_STATBASE) / 20; + resistmod += ((float)caster->CastToClient()->GetActWIS() - DW_STATBASE) / 20; } - else if(GetCasterClass() == 'I') + else if(caster->GetCasterClass() == 'I') { - resistmod += ((float)CastToClient()->GetActINT() - DW_STATBASE) / 20; + resistmod += ((float)caster->CastToClient()->GetActINT() - DW_STATBASE) / 20; } - final += resistmod; + final -= resistmod; if(caster->GetLevel() > 50) { diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 51d8487a1..89012e041 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -834,7 +834,7 @@ uint16 QuestManager::scribespells(uint8 max_level, uint8 min_level) { spells[curspell].classes[initiator->GetPP().class_-1] <= max_level && //maximum level spells[curspell].classes[initiator->GetPP().class_-1] >= min_level && //minimum level spells[curspell].skill != 52 && - ( !RuleB(Spells, UseCHAScribeHack) || spells[curspell].effectid[EFFECT_COUNT - 1] != 10 ) + spells[curspell].effectid[EFFECT_COUNT - 1] != 10 ) { if (book_slot == -1) //no more book slots From 510ce16f0ed884f224d32375de51dd9fea1d959a Mon Sep 17 00:00:00 2001 From: root Date: Mon, 27 May 2013 08:46:50 -0500 Subject: [PATCH 06/12] Added reloadworld console command --- world/console.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/world/console.cpp b/world/console.cpp index 93f73ed4d..2b84ae6c7 100644 --- a/world/console.cpp +++ b/world/console.cpp @@ -469,6 +469,7 @@ void Console::ProcessCommand(const char* command) { if (admin >= 100) { SendMessage(1, " LSReconnect"); SendMessage(1, " signalcharbyname charname ID"); + SendMessage(1, " reloadworld"); } } else if (strcasecmp(sep.arg[0], "ping") == 0) { @@ -838,6 +839,15 @@ void Console::ProcessCommand(const char* command) { } } } + else if (strcasecmp(sep.arg[0], "reloadworld") == 0 && admin > 101) + { + SendEmoteMessage(0,0,0,15,"Reloading World..."); + ServerPacket* pack = new ServerPacket(ServerOP_ReloadWorld, sizeof(ReloadWorld_Struct)); + ReloadWorld_Struct* RW = (ReloadWorld_Struct*) pack->pBuffer; + RW->Option = 1; + zoneserver_list.SendPacket(pack); + safe_delete(pack); + } else { SendMessage(1, "Command unknown."); } From fa0196b9875f765ffc3a7b3c17d48159ae70cc92 Mon Sep 17 00:00:00 2001 From: Tabasco Date: Mon, 27 May 2013 15:32:59 -0500 Subject: [PATCH 07/12] Fixed some mod function bugs and stat caps. --- zone/client.cpp | 2 +- zone/client.h | 1 + zone/client_mods.cpp | 30 ++++++++++++++++-------------- zone/mod_functions.cpp | 42 ++++++++++++++++++++++++++++++++---------- zone/perl_npc.cpp | 4 ++-- 5 files changed, 52 insertions(+), 27 deletions(-) diff --git a/zone/client.cpp b/zone/client.cpp index 8f16956aa..2e501602c 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -2343,7 +2343,7 @@ bool Client::CheckIncreaseSkill(SkillType skillid, Mob *against_who, int chancem GetLevelCon(against_who->GetLevel()) == CON_GREEN) { //false by default - return mod_can_increase_skill(skillid, against_who); + if( !mod_can_increase_skill(skillid, against_who) ) { return(false); } } } diff --git a/zone/client.h b/zone/client.h index 46ee8f4fd..fc6d668ea 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1131,6 +1131,7 @@ public: void mod_client_death_env(); int32 mod_client_xp(int32 in_exp, NPC *npc); uint32 mod_client_xp_for_level(uint32 xp, uint16 check_level); + int mod_client_haste_cap(int cap); protected: friend class Mob; diff --git a/zone/client_mods.cpp b/zone/client_mods.cpp index 1e81c563e..3ecd7a1f9 100644 --- a/zone/client_mods.cpp +++ b/zone/client_mods.cpp @@ -1228,8 +1228,8 @@ int16 Client::CalcSTR() { int16 mod = aabonuses.STR; - if(val>255 && GetLevel() <= 60) - val = 255; +// if(val>255 && GetLevel() <= 60) +// val = 255; STR = val + mod; if(STR < 1) @@ -1247,8 +1247,8 @@ int16 Client::CalcSTA() { int16 mod = aabonuses.STA; - if(val>255 && GetLevel() <= 60) - val = 255; +// if(val>255 && GetLevel() <= 60) +// val = 255; STA = val + mod; if(STA < 1) @@ -1265,8 +1265,8 @@ int16 Client::CalcAGI() { int16 val = m_pp.AGI + itembonuses.AGI + spellbonuses.AGI - CalcAlcoholPhysicalEffect();; int16 mod = aabonuses.AGI; - if(val>255 && GetLevel() <= 60) - val = 255; +// if(val>255 && GetLevel() <= 60) +// val = 255; int16 str = GetSTR(); @@ -1294,8 +1294,8 @@ int16 Client::CalcDEX() { int16 mod = aabonuses.DEX; - if(val>255 && GetLevel() <= 60) - val = 255; +// if(val>255 && GetLevel() <= 60) +// val = 255; DEX = val + mod; if(DEX < 1) @@ -1313,8 +1313,8 @@ int16 Client::CalcINT() { int16 mod = aabonuses.INT; - if(val>255 && GetLevel() <= 60) - val = 255; +// if(val>255 && GetLevel() <= 60) +// val = 255; INT = val + mod; if(m_pp.intoxication) @@ -1342,8 +1342,8 @@ int16 Client::CalcWIS() { int16 mod = aabonuses.WIS; - if(val>255 && GetLevel() <= 60) - val = 255; +// if(val>255 && GetLevel() <= 60) +// val = 255; WIS = val + mod; if(m_pp.intoxication) @@ -1371,8 +1371,8 @@ int16 Client::CalcCHA() { int16 mod = aabonuses.CHA; - if(val>255 && GetLevel() <= 60) - val = 255; +// if(val>255 && GetLevel() <= 60) +// val = 255; CHA = val + mod; if(CHA < 1) @@ -1410,6 +1410,8 @@ int Client::CalcHaste() { cap = RuleI(Character, HasteCap); } + cap = mod_client_haste_cap(cap); + if(h > cap) h = cap; h += spellbonuses.hastetype3; diff --git a/zone/mod_functions.cpp b/zone/mod_functions.cpp index 4a6b32117..8a1cc96c2 100644 --- a/zone/mod_functions.cpp +++ b/zone/mod_functions.cpp @@ -134,6 +134,9 @@ int Client::mod_client_damage(int damage, SkillType skillinuse, int hand, const float cagi = (float)GetActAGI() - DW_STATBASE; float csta = (float)GetActSTA() - DW_STATBASE; + //if(Admin() > 80) { Message(315, "Dex: %f, Str: %f, Agi: %f, Sta: %f", cdex, cstr, cagi, csta); } + //if(Admin() > 80) { Message(315, "Str: %f, %d, %d", cstr, GetMaxSTR(), GetSTR()); } + float cmax = ((float)GetLevel() * 2) + 150; if(GetLevel() > 49) { cmax = 10000; } @@ -145,12 +148,12 @@ int Client::mod_client_damage(int damage, SkillType skillinuse, int hand, const switch(skillinuse) { case ARCHERY: - dmult += cdex / 600; - dmult += csta / 600; + dmult += cdex / 900; + dmult += csta / 900; if(GetClass() == RANGER) { - dmult += cdex / 1000; + dmult += cdex / 1200; } break; @@ -332,7 +335,7 @@ int16 Client::mod_increase_skill_chance(int16 chance, Mob* against_who) { float bonus = (cint + (cwis / 2)) / 10; - if(bonus < 0) { bonus = 0; } + if(bonus < 0.8) { bonus = 0.8; } return( (int)((float)chance * bonus) ); } @@ -397,6 +400,12 @@ int Client::mod_client_haste(int h) { return(h); } +//Haste cap override +int Client::mod_client_haste_cap(int cap) +{ + return( RuleI(Character, HasteCap) ); +} + //This is called when a client cons a mob void Client::mod_consider(Mob* tmob, Consider_Struct* con) { if(tmob->GetLastName()[0] == '[') @@ -519,24 +528,27 @@ int Mob::mod_effect_value(int effect_value, uint16 spell_id, int effect_type, Mo float spadd = 0.0f; int adval = caster->CastToClient()->Admin(); -// adval = 0; + adval = 0; if(caster->GetCasterClass() == 'W') { spbonus = (float)(caster->CastToClient()->GetActWIS() - DW_STATBASE) / 400; spbonus += (float)(caster->CastToClient()->GetActSTA() - DW_STATBASE) / 400; + if(adval > 80) { caster->Message(315, "WIS FORMULA"); } } else if(caster->GetCasterClass() == 'I') { if(caster->GetClass() == BARD) { - spbonus = (float)(caster->CastToClient()->GetActCHA() - DW_STATBASE) / 150; - spbonus += (float)(caster->CastToClient()->GetActINT() - DW_STATBASE) / 150; + spbonus = (float)(caster->CastToClient()->GetActCHA() - DW_STATBASE) / 400; + spbonus += (float)(caster->CastToClient()->GetActINT() - DW_STATBASE) / 400; + if(adval > 80) { caster->Message(315, "CHA FORMULA"); } } else { spbonus = (float)(caster->CastToClient()->GetActINT() - DW_STATBASE) / 400; spbonus += (float)(caster->CastToClient()->GetActDEX() - DW_STATBASE) / 400; + if(adval > 80) { caster->Message(315, "INT FORMULA"); } } } else @@ -658,14 +670,16 @@ int Mob::mod_effect_value(int effect_value, uint16 spell_id, int effect_type, Mo mult = 1.0f; } + int base_effect = effect_value; + if(effect_value > 0) { effect_value += (int)ceil(spadd); } else { effect_value -= (int)ceil(spadd); } - effect_value *= mult; + effect_value = (int)( ceil((float)effect_value * mult) ); - if(adval > 80) { caster->Message(315, "Spell Bonus: %d, %d, %d", effect_value, spadd, effect_type); } + if(adval > 80) { caster->Message(315, "Spell Bonus: Base: %d, New: %d, Add: %d", base_effect, effect_value, spadd); } - return( (int)(ceil(effect_value)) ); + return( effect_value ); } //chancetohit - 0 to 100 percent - set over 1000 for a guaranteed hit @@ -858,7 +872,15 @@ int32 Mob::mod_bash_damage(int32 dmg) { int32 Mob::mod_frenzy_damage(int32 dmg) { if(!IsClient()) { return(dmg); } + float hprmult = 1 + (1 - (GetHP()/GetMaxHP())); + dmg = CastToClient()->mod_client_damage(dmg, FRENZY, 0, nullptr, nullptr); + + if(GetClass() == BERSERKER) + { + dmg = (int)( (float)dmg * hprmult ); + } + return(dmg); } diff --git a/zone/perl_npc.cpp b/zone/perl_npc.cpp index c89445bd2..0ac61e3cc 100644 --- a/zone/perl_npc.cpp +++ b/zone/perl_npc.cpp @@ -129,8 +129,8 @@ XS(XS_NPC_AddLootTable); /* prototype to pass -Wmissing-prototypes */ XS(XS_NPC_AddLootTable) { dXSARGS; - if (items != 1) - Perl_croak(aTHX_ "Usage: NPC::AddLootTable(THIS)"); + if (items < 1) + Perl_croak(aTHX_ "Usage: NPC::AddLootTable(THIS, [loottable_id])"); { NPC * THIS; From 0ee54f11170b673c7e923bd4bcfa53c5a504f5f1 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 28 May 2013 19:58:40 -0500 Subject: [PATCH 08/12] Added mod_spell_cast and various mod_functions fixes. --- zone/mob.h | 1 + zone/mod_functions.cpp | 57 ++++++++++++++++++++++++++++++++++-------- zone/spells.cpp | 2 ++ 3 files changed, 50 insertions(+), 10 deletions(-) diff --git a/zone/mob.h b/zone/mob.h index d83f2aa90..128c40735 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -812,6 +812,7 @@ public: int mod_buff_duration(int res, Mob* caster, Mob* target, uint16 spell_id); int mod_spell_stack(uint16 spellid1, int caster_level1, Mob* caster1, uint16 spellid2, int caster_level2, Mob* caster2); int mod_spell_resist(int resist_chance, int level_mod, int resist_modifier, int target_resist, uint8 resist_type, uint16 spell_id, Mob* caster); + void mod_spell_cast(uint16 spell_id, Mob* spelltar, bool reflect, bool use_resist_adjust, int16 resist_adjust, bool isproc); protected: void CommonDamage(Mob* other, int32 &damage, const uint16 spell_id, const SkillType attack_skill, bool &avoidable, const int8 buffslot, const bool iBuffTic); diff --git a/zone/mod_functions.cpp b/zone/mod_functions.cpp index 8a1cc96c2..fa504b5ad 100644 --- a/zone/mod_functions.cpp +++ b/zone/mod_functions.cpp @@ -662,8 +662,8 @@ int Mob::mod_effect_value(int effect_value, uint16 spell_id, int effect_type, Mo break; } - //Shroud of the bear - if(caster->FindBuff(5045)) + //Shroud of the bear and Blood of the Master + if(caster->FindBuff(5045) || caster->FindBuff(1169)) { if(adval > 80) { caster->Message(315, "Shroud of bear nerf"); } spadd = spadd * -1; @@ -969,24 +969,29 @@ int32 Mob::mod_cast_time(int32 cast_time) { //res - Default buff duration formula int Mob::mod_buff_duration(int res, Mob* caster, Mob* target, uint16 spell_id) { - if(!IsClient()) { return(res); } + //if(!IsClient()) { return(res); } + if(res <= 1) { return(res); } + if(!caster) { return(res); } + if(!caster->IsClient()) { return(res); } float cmult = 1; - if(GetClass() == BARD) +// caster->Message(315, "Duration: %d", res); + + if(caster->GetClass() == BARD) { - cmult = (float)(CastToClient()->GetActCHA() - DW_STATBASE) / 200; + cmult = (float)(caster->CastToClient()->GetActCHA() - DW_STATBASE) / 200; } - else if(GetCasterClass() == 'W') + else if(caster->GetCasterClass() == 'W') { - cmult = (float)(CastToClient()->GetActWIS() - DW_STATBASE) / 200; + cmult = (float)(caster->CastToClient()->GetActWIS() - DW_STATBASE) / 200; } - else if(GetCasterClass() == 'I') + else if(caster->GetCasterClass() == 'I') { - cmult = (float)(CastToClient()->GetActINT() - DW_STATBASE) / 200; + cmult = (float)(caster->CastToClient()->GetActINT() - DW_STATBASE) / 200; } - cmult += (float)(CastToClient()->GetActSTA() - DW_STATBASE) / 400; + cmult += (float)(caster->CastToClient()->GetActSTA() - DW_STATBASE) / 400; if(cmult < 1) { cmult = 1; } @@ -1068,6 +1073,38 @@ int Mob::mod_spell_resist(int resist_chance, int level_mod, int resist_modifier, return(final); } +//Spell is cast by this on spelltar, called from spellontarget after the event_cast_on NPC event +void Mob::mod_spell_cast(uint16 spell_id, Mob* spelltar, bool reflect, bool use_resist_adjust, int16 resist_adjust, bool isproc) +{ + float cval = 5; + + if(!IsClient()) { return; } + if(GetClass() == WIZARD) + { + cval += (float)(CastToClient()->GetActINT() - DW_STATBASE) / 100; + cval += (float)(CastToClient()->GetActDEX() - DW_STATBASE) / 100; + cval += (float)(CastToClient()->GetActCHA() - DW_STATBASE) / 100; + + if(MakeRandomFloat(0, 99) < cval) + { + Message(14, "You channel addition power into the spell!"); + SpellOnTarget(spell_id, spelltar, reflect, use_resist_adjust, resist_adjust, isproc); + + if(MakeRandomFloat(0, 99) < cval) + { + Message(14, "You continue to channel additional power!"); + SpellOnTarget(spell_id, spelltar, reflect, use_resist_adjust, resist_adjust, isproc); + + if(MakeRandomFloat(0, 99) < cval) + { + Message(14, "You apply the full force of your concentration into the spell!"); + SpellOnTarget(spell_id, spelltar, reflect, use_resist_adjust, resist_adjust, isproc); + } + } + } + } +} + //This is called right before regular event processing (the switch block) void PerlembParser::mod_quest_event(QuestEventID event, uint32 objid, const char * data, NPC* npcmob, ItemInst* iteminst, Mob* mob, uint32 extradata, bool global, std::string packagename) { NPC *tnpc = 0; diff --git a/zone/spells.cpp b/zone/spells.cpp index cf37971dd..184f0c894 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -3077,6 +3077,8 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r parse->EventNPC(EVENT_CAST_ON, spelltar->CastToNPC(), this, temp1, 0); } + mod_spell_cast(spell_id, spelltar, reflect, use_resist_adjust, resist_adjust, isproc); + // now check if the spell is allowed to land // invuln mobs can't be affected by any spells, good or bad From 567c17cc9e985858d9809d5161d47f948050678f Mon Sep 17 00:00:00 2001 From: root Date: Tue, 28 May 2013 20:27:17 -0500 Subject: [PATCH 09/12] Berserker updates. --- zone/mod_functions.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/zone/mod_functions.cpp b/zone/mod_functions.cpp index fa504b5ad..5579135a6 100644 --- a/zone/mod_functions.cpp +++ b/zone/mod_functions.cpp @@ -210,6 +210,7 @@ int Client::mod_client_damage(int damage, SkillType skillinuse, int hand, const { dmult += csta / 100; dmult += cstr / 100; + if(berserk) { dmult += cstr / 100; } } else { @@ -765,6 +766,10 @@ float Mob::mod_mitigation_rating(float mitigation_rating, Mob* attacker) { case BARD: return(mitigation_rating + (armor/5)); + case BERSERKER: + if(CastToClient()->berserk) { return(mitigation_rating / 1.5); } + else { return(mitigation_rating); } + default: return(mitigation_rating); } @@ -1084,12 +1089,16 @@ void Mob::mod_spell_cast(uint16 spell_id, Mob* spelltar, bool reflect, bool use_ cval += (float)(CastToClient()->GetActINT() - DW_STATBASE) / 100; cval += (float)(CastToClient()->GetActDEX() - DW_STATBASE) / 100; cval += (float)(CastToClient()->GetActCHA() - DW_STATBASE) / 100; + cval += (float)(CastToClient()->GetActSTA() - DW_STATBASE) / 100; + + if(cval > 50) { cval = 50; } //This absolutely needs a cap if(MakeRandomFloat(0, 99) < cval) { Message(14, "You channel addition power into the spell!"); SpellOnTarget(spell_id, spelltar, reflect, use_resist_adjust, resist_adjust, isproc); +/* This is already recursive if(MakeRandomFloat(0, 99) < cval) { Message(14, "You continue to channel additional power!"); @@ -1101,6 +1110,7 @@ void Mob::mod_spell_cast(uint16 spell_id, Mob* spelltar, bool reflect, bool use_ SpellOnTarget(spell_id, spelltar, reflect, use_resist_adjust, resist_adjust, isproc); } } +*/ } } } From 851c84252995649f278298f13f041427b7e019e6 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 1 Jun 2013 10:44:32 -0500 Subject: [PATCH 10/12] Updated mod_functions and mod_functions_base with new hooks and descriptions --- zone/mod_functions.cpp | 1062 ++--------------------------------- zone/mod_functions_base.cpp | 69 ++- 2 files changed, 114 insertions(+), 1017 deletions(-) diff --git a/zone/mod_functions.cpp b/zone/mod_functions.cpp index 5579135a6..bf559d733 100644 --- a/zone/mod_functions.cpp +++ b/zone/mod_functions.cpp @@ -23,228 +23,26 @@ extern Zone* zone; extern WorldServer worldserver; -using namespace std; +//All functions that modify a value are passed the value as it was computed by default formulas and bonuses. In most cases this should be the final value that will be used. -#define DW_STATBASE 70 +//These are called when a zone boots or is repopped +void Zone::mod_init() { return; } +void Zone::mod_repop() { return; } -void Zone::mod_init() { - const NPCType* tmp = 0; - if((tmp = database.GetNPCType(999999))) - { - NPC* npc = new NPC(tmp, 0, 0, 0, 0, 0, FlyMode3); - if(npc) - { - entity_list.AddNPC(npc); - } - } -} - -void Zone::mod_repop() { - const NPCType* tmp = 0; - if((tmp = database.GetNPCType(999999))) - { - NPC* npc = new NPC(tmp, 0, 0, 0, 0, 0, FlyMode3); - if(npc) - { - entity_list.AddNPC(npc); - } - } -} - -void NPC::mod_prespawn(Spawn2 *sp) { - //The spawn has to have 1 kill to qualify - if(sp->GetKillCount() < 1) { return; } - //Ignore existing bosses - if(lastname[0] == '[') { return; } - //5% chance to elevate - if(MakeRandomInt(0, 100) > 5) { return; } - - //Let everything else happen in perl. Our job here is to set the last name - int npcscore = GetScore(); - std::string bosstag = "<"; - int lvs = (int)(npcscore/10); - for(int x = 0; x < 10; x++) - { - if(x < lvs) { bosstag += "+"; } - else { bosstag += "="; } - } - bosstag += ">"; - strn0cpy(lastname, bosstag.c_str(), sizeof(lastname)); - - TempName("DYNBOSS"); -} +//Pre-spawn hook called from the NPC object to be spawned +void NPC::mod_prespawn(Spawn2 *sp) { return; } //Base damage from NPC::Attack -int NPC::mod_npc_damage(int damage, SkillType skillinuse, int hand, const Item_Struct* weapon, Mob* other) { - float chbonus; - int lbonus; - -// if(!IsPet() || !GetOwner()) { return(damage); } -// if(!GetOwner()->IsClient()) { return(damage); } - - //Client pet power bonuses - if(GetOwner() && GetOwner()->IsClient()) - { - chbonus = (float)((float)GetOwner()->CastToClient()->GetActCHA() - DW_STATBASE) / 100; - chbonus += 1; - - if(GetOwner()->GetLevel() > 50) - { - lbonus = GetOwner()->GetLevel() - 50; - damage += lbonus * (20 * lbonus); - } - - if(weapon) - { - damage += (int)ceil(((float)weapon->Damage / (float)weapon->Delay) * (float)GetOwner()->GetLevel()); - } - - damage = (int)ceil( (float)damage * chbonus ); - return(damage); - } - - //Regular NPC damage - test for debuffs that currently do nothing. - //str, sta, agi, dex, AC, ATK - return(damage); -} +int NPC::mod_npc_damage(int damage, SkillType skillinuse, int hand, const Item_Struct* weapon, Mob* other) { return(damage); } //Mob c has been given credit for a kill. This is called after the regular EVENT_KILLED_MERIT event. -void NPC::mod_npc_killed_merit(Mob* c) { - Mob *tmpmob = entity_list.GetMobByNpcTypeID(999999); - if(tmpmob) - { - parse->EventNPC(EVENT_KILLED_MERIT, tmpmob->CastToNPC(), c, this->GetCleanName(), this->GetNPCTypeID()); - } -} +void NPC::mod_npc_killed_merit(Mob* c) { return; } //Mob oos has been given credit for a kill. This is called after the regular EVENT_DEATH event. -void NPC::mod_npc_killed(Mob* oos) { - Mob *tmpmob = entity_list.GetMobByNpcTypeID(999999); - if(tmpmob) - { - parse->EventNPC(EVENT_DEATH, tmpmob->CastToNPC(), oos, this->GetCleanName(), this->GetNPCTypeID()); - } -} +void NPC::mod_npc_killed(Mob* oos) { return; } //Base damage from Client::Attack - can cover myriad skill types -int Client::mod_client_damage(int damage, SkillType skillinuse, int hand, const ItemInst* weapon, Mob* other) { - float dmult = 1.1f; - float cdex = (float)GetActDEX() - DW_STATBASE; - float cstr = (float)GetActSTR() - DW_STATBASE; - float cagi = (float)GetActAGI() - DW_STATBASE; - float csta = (float)GetActSTA() - DW_STATBASE; - - //if(Admin() > 80) { Message(315, "Dex: %f, Str: %f, Agi: %f, Sta: %f", cdex, cstr, cagi, csta); } - //if(Admin() > 80) { Message(315, "Str: %f, %d, %d", cstr, GetMaxSTR(), GetSTR()); } - - float cmax = ((float)GetLevel() * 2) + 150; - if(GetLevel() > 49) { cmax = 10000; } - - if(cdex > cmax) { cdex = cmax; } - if(cstr > cmax) { cstr = cmax; } - if(cagi > cmax) { cagi = cmax; } - if(csta > cmax) { csta = cmax; } - - switch(skillinuse) - { - case ARCHERY: - dmult += cdex / 900; - dmult += csta / 900; - - if(GetClass() == RANGER) - { - dmult += cdex / 1200; - } - break; - - case KICK: - case HAND_TO_HAND: - case BACKSTAB: - case _1H_BLUNT: - case _1H_SLASHING: - case PIERCING: - case THROWING: - if(GetClass() == MONK || GetClass() == BEASTLORD) - { - if(GetRace() == BARBARIAN || GetRace() == TROLL || GetRace() == OGRE) - { - dmult += cstr / 320; - dmult += csta / 320; - dmult += cdex / 150; - //2.325 - } - else - { - dmult += cdex / 400; - dmult += csta / 200; - dmult += cstr / 200; - //2.25 - } - } - else - { - dmult += cdex / 400; - dmult += cstr / 200; - dmult += csta / 200; - //2.25 - } - break; - - case BASH: - if(GetClass() == WARRIOR) - { - dmult += csta / 100; - dmult += cstr / 100; - } - else - { - dmult += csta / 150; - dmult += cstr / 150; - } - break; - - case _2H_SLASHING: - case _2H_BLUNT: - case FRENZY: - if(GetClass() == BERSERKER) - { - dmult += csta / 100; - dmult += cstr / 100; - if(berserk) { dmult += cstr / 100; } - } - else - { - dmult += csta / 150; - dmult += cstr / 150; - } - break; - - default: - dmult += cstr / 200; - dmult += csta / 200; - break; - } - - if(GetLevel() > 50) - { - float lbonus = GetLevel() - 50; - dmult += lbonus * 0.2; - } - - int final = (int)((float)damage * dmult); - - if(skillinuse == ARCHERY) - { - final += (GetSkill(ARCHERY) + (GetLevel() * 2)) / 2; - if(weapon) //We should always have a weapon here - { - final = (int)((float)final * (float)(0.6 + ((float)weapon->GetItem()->Delay / 100))); - } - } - - return(final); -} - +int Client::mod_client_damage(int damage, SkillType skillinuse, int hand, const ItemInst* weapon, Mob* other) { return(damage); } //message is char[4096], don't screw it up. Return true for normal behavior, false to return immediately. // Channels: @@ -260,664 +58,98 @@ int Client::mod_client_damage(int damage, SkillType skillinuse, int hand, const // 15 - Raid Chat // 20 - UCS Relay for UF client and later // 22 - Emotes for UF and later -bool Client::mod_client_message(char* message, uint8 chan_num) { - //!commands for serverman - if(message[0] == '!' && chan_num == 8) - { - Mob *tmpmob = entity_list.GetMobByNpcTypeID(999999); - if(tmpmob) - { - parse->EventNPC(EVENT_SAY, tmpmob->CastToNPC(), this, message, 0); - return(false); - } - Message(315, "Your pants are on sideways."); - return(false); - } - -/* - //Parse out link notation - Seperator ms(message, ' ', 20); - - std::string finalmsg(""); - bool modded = false; - for(int i = 0; i < ms.GetMaxArgNum(); i++) - { - if(i > 0) { finalmsg += " "; } - if(strlen(ms.arg[i]) < 5) { finalmsg += ms.arg[i]; continue; } - - if( ms.arg[i][0] == '$' && ms.arg[i][1] == 'N' && ms.arg[i][2] == 'P' && ms.arg[i][3] == 'C') - { - std::string npclink("%!!dbnav NPC "); - std::string npctext("NPC:"); - for(int x = 4; x < strlen(ms.arg[i]); x++) - { - npclink += ms.arg[i][x]; - npctext += ms.arg[i][x]; - } - modded = true; - char text[250]; - sprintf(text, "%S", npclink.c_str()); - finalmsg += quest_manager.saylink( text, true, const_cast(npctext.c_str()) ); - } - else if( ms.arg[i][0] == '$' && ms.arg[i][1] == 'T' && ms.arg[i][2] == 'E' && ms.arg[i][3] == 'S' && ms.arg[i][4] == 'T') - { - modded = true; - char text[250]; - sprintf(text, "%%!!help"); - finalmsg += quest_manager.saylink( text, true, text ); - finalmsg += "DBLINK TEST"; - } - else - { - finalmsg += ms.arg[i]; - } - } - - if(modded) - { - strn0cpy(message, finalmsg.c_str(), 4096); - } -*/ - return(true); -} //Potentially dangerous string handling here +bool Client::mod_client_message(char* message, uint8 chan_num) { return(true); } //Skillup override. When this is called the regular skillup check has failed. Return false to proceed with default behavior. //This will NOT allow a client to increase skill past a cap. -bool Client::mod_can_increase_skill(SkillType skillid, Mob* against_who) { - //Let people skillup on golem training dummies. - if(against_who->GetRace() == 405) { return(true); } - return(false); -} +bool Client::mod_can_increase_skill(SkillType skillid, Mob* against_who) { return(false); } //chance of general skill increase, rolled against 0-99 where higher chance is better. -int16 Client::mod_increase_skill_chance(int16 chance, Mob* against_who) { - float cint = (float)GetActINT() - DW_STATBASE; - float cwis = (float)GetActWIS() - DW_STATBASE; - - float bonus = (cint + (cwis / 2)) / 10; - - if(bonus < 0.8) { bonus = 0.8; } - - return( (int)((float)chance * bonus) ); -} +int16 Client::mod_increase_skill_chance(int16 chance, Mob* against_who) { return(chance); } //Max percent of health you can bind wound starting with default value for class, item, and AA bonuses -int Client::mod_bindwound_percent(int max_percent, Mob* bindmob) { - return(max_percent + 20); -} +int Client::mod_bindwound_percent(int max_percent, Mob* bindmob) { return(max_percent); } //Final bind HP value after bonuses -int Client::mod_bindwound_hp(int bindhps, Mob* bindmob) { - if(GetSkill(BIND_WOUND) > 200) - { - bindhps += GetSkill(BIND_WOUND) * 2; - } - else - { - bindhps += GetSkill(BIND_WOUND); - } - - if(GetLevel() > 50) - { - float bonus = ((GetLevel() - 50) / 10) + 1; - bindhps += (int)( (float)bindhps * bonus ); - } - - return(bindhps); -} +int Client::mod_bindwound_hp(int bindhps, Mob* bindmob) { return(bindhps); } //Client haste as calculated by default formulas - In percent from 0-100 -int Client::mod_client_haste(int h) { - float agibase = (float)GetActAGI() - DW_STATBASE; - float agibonus = 0; - - if(agibase > 0) - { - agibonus = agibase; - - float l1, l2, l3; - - switch(GetClass()) - { - case ROGUE: - case MONK: - l1 = 1.5; - l2 = 2.0; - l3 = 2.5; - break; - - default: - l1 = 1.0; - l2 = 1.5; - l3 = 2.0; - } - - if(GetLevel() > 19) { agibonus = agibase * l1; } - if(GetLevel() > 39) { agibonus = agibase * l2; } - if(GetLevel() > 59) { agibonus = agibase * l3; } - } - - h += (int)(agibonus / 10); - return(h); -} +int Client::mod_client_haste(int h) { return(h); } //Haste cap override -int Client::mod_client_haste_cap(int cap) -{ - return( RuleI(Character, HasteCap) ); -} +int Client::mod_client_haste_cap(int cap) { return(cap); } //This is called when a client cons a mob -void Client::mod_consider(Mob* tmob, Consider_Struct* con) { - if(tmob->GetLastName()[0] == '[') - { - Message(14, "%s", tmob->GetLastName()); - } -} +void Client::mod_consider(Mob* tmob, Consider_Struct* con) { return; } -//Return true to continue with normal behavior -bool Client::mod_saylink(const std::string& response, bool silentsaylink) { - if(silentsaylink && strlen(response.c_str()) > 1 && response[0] == '%' && response[1] == '!') - { - Mob *tmpmob = entity_list.GetMobByNpcTypeID(999999); - if(tmpmob) - { - parse->EventNPC(EVENT_SAY, tmpmob->CastToNPC(), this, response, 0); - return(false); - } - Message(315, "Your pants are on sideways."); - return(false); - } - return(true); -} +//Return true to continue with normal behavior, false returns in the parent function +bool Client::mod_saylink(const std::string& response, bool silentsaylink) { return(true); } //Client pet power as calculated by default formulas and bonuses -int16 Client::mod_pet_power(int16 act_power, uint16 spell_id) { - act_power += (int)(((float)GetActCHA() - DW_STATBASE) /2 ) + GetLevel(); - return(act_power); -} +int16 Client::mod_pet_power(int16 act_power, uint16 spell_id) { return(act_power); } //Chance to combine rolled against a random 0-99 where higher is better. -float Client::mod_tradeskill_chance(float chance, DBTradeskillRecipe_Struct *spec) { - chance += 10; - return(chance); -} +float Client::mod_tradeskill_chance(float chance, DBTradeskillRecipe_Struct *spec) { return(chance); } //Chance to skillup rolled against a random 0-99 where higher is better. -float Client::mod_tradeskill_skillup(float chance_stage2) { - float cint = (float)CastToClient()->GetActINT() - DW_STATBASE; - float cwis = (float)CastToClient()->GetActWIS() - DW_STATBASE; - - float bonus = (cint + (cwis / 2)) / 10; - - if(bonus < 0) { bonus = 0; } - return(chance_stage2 + bonus); -} +float Client::mod_tradeskill_skillup(float chance_stage2) { return(chance_stage2); } //Tribute value override -int32 Client::mod_tribute_item_value(int32 pts, const ItemInst* item) { - return(0); -} +int32 Client::mod_tribute_item_value(int32 pts, const ItemInst* item) { return(pts); } //Death reporting -void Client::mod_client_death_npc(Mob* killerMob) { - Mob *tmpmob = entity_list.GetMobByNpcTypeID(999999); - if(tmpmob) - { - parse->EventNPC(EVENT_SLAY, tmpmob->CastToNPC(), this, killerMob->GetCleanName(), killerMob->GetLevel()); - } -} +void Client::mod_client_death_npc(Mob* killerMob) { return; } +void Client::mod_client_death_duel(Mob* killerMob) { return; } +void Client::mod_client_death_env() { return; } -void Client::mod_client_death_duel(Mob* killerMob) { - Mob *tmpmob = entity_list.GetMobByNpcTypeID(999999); - if(tmpmob) - { - std::string pname = std::string("PLAYER|") + killerMob->GetCleanName(); - parse->EventNPC(EVENT_SLAY, tmpmob->CastToNPC(), this, pname.c_str(), killerMob->GetLevel()); - } -} - -void Client::mod_client_death_env() { - Mob *tmpmob = entity_list.GetMobByNpcTypeID(999999); - if(tmpmob) - { - parse->EventNPC(EVENT_SLAY, tmpmob->CastToNPC(), this, "ENVIRONMENT", 0); - } -} - -//Calculated xp before consider modifier -int32 Client::mod_client_xp(int32 in_xp, NPC *npc) { - float xpmult = 2.0f; - - if(GetLevel() > 5) - { - xpmult = 1.5f; - } - if(GetLevel() > 10) - { - xpmult = 1.25f; - } - if(GetLevel() > 15) - { - xpmult = 1.0f; - } - - return( (int32)((float)in_xp * xpmult) ); -} +//Calculated xp before consider modifier, called whenever a client gets XP for killing a mob. +int32 Client::mod_client_xp(int32 in_xp, NPC *npc) { return(in_xp); } //Client XP formula. Changes here will cause clients to change level after gaining or losing xp. //Either modify this before your server goes live, or be prepared to write a quest script that fixes levels. -uint32 Client::mod_client_xp_for_level(uint32 xp, uint16 check_level) { - uint16 check_levelm1 = check_level-1; - float mod; - - mod = 4; - float base = (check_levelm1)*(check_levelm1)*(check_levelm1); - mod *= 1000; - - return(uint32(base * mod)); -} +//To adjust how much XP is given per kill, use mod_client_xp +uint32 Client::mod_client_xp_for_level(uint32 xp, uint16 check_level) { return(xp); } //effect_vallue - Spell effect value as calculated by default formulas. You will want to ignore effects that don't lend themselves to scaling - pet ID's, gate coords, etc. -int Mob::mod_effect_value(int effect_value, uint16 spell_id, int effect_type, Mob* caster) { -// if(IsClient()) { return(effect_value); } - if(!caster) { return(effect_value); } - if(!caster->IsClient()) { return(effect_value); } - - float mult = 1.0f; - float spbonus = 0.0f; - float spadd = 0.0f; - - int adval = caster->CastToClient()->Admin(); - adval = 0; - - if(caster->GetCasterClass() == 'W') - { - spbonus = (float)(caster->CastToClient()->GetActWIS() - DW_STATBASE) / 400; - spbonus += (float)(caster->CastToClient()->GetActSTA() - DW_STATBASE) / 400; - if(adval > 80) { caster->Message(315, "WIS FORMULA"); } - } - else if(caster->GetCasterClass() == 'I') - { - if(caster->GetClass() == BARD) - { - spbonus = (float)(caster->CastToClient()->GetActCHA() - DW_STATBASE) / 400; - spbonus += (float)(caster->CastToClient()->GetActINT() - DW_STATBASE) / 400; - if(adval > 80) { caster->Message(315, "CHA FORMULA"); } - } - else - { - spbonus = (float)(caster->CastToClient()->GetActINT() - DW_STATBASE) / 400; - spbonus += (float)(caster->CastToClient()->GetActDEX() - DW_STATBASE) / 400; - if(adval > 80) { caster->Message(315, "INT FORMULA"); } - } - } - else - { - //No proc/click bonuses for non casters - if(adval > 80) { caster->Message(315, "CASTER CLASS NOT FOUND"); } - return(effect_value); - } - - //Add a fixed value to help things like bard songs, dots, and other low effect value spells - spadd = (mult + spbonus) * ((float)caster->GetLevel() / 10); - if(caster->GetLevel() > 50) - { - float lbonus = caster->GetLevel() - 50; - spadd += spadd * (lbonus / 2); - } - - switch(effect_type) - { - case SE_CriticalHitChance: - case SE_SpellCritChance: - case SE_CrippBlowChance: - case SE_AvoidMeleeChance: - case SE_RiposteChance: - case SE_DodgeChance: - case SE_ParryChance: - case SE_DualWieldChance: - case SE_DoubleAttackChance: - case SE_MovementSpeed: - case SE_AttackSpeed4: - case SE_AttackSpeed3: - case SE_AttackSpeed2: - case SE_AttackSpeed: - if(caster->GetLevel() < 30) { spbonus = spbonus / 2; } - if(caster->GetLevel() >= 30 && caster->GetLevel() < 46) { spbonus = spbonus / 1.5; } - mult += spbonus; - //No fixed bonus on these types - spadd = 0; - break; - - case SE_CurrentHPOnce: - case SE_CurrentHP: - if(caster->GetLevel() < 30) { spbonus = spbonus / 2; } - if(caster->GetLevel() >= 30 && caster->GetLevel() < 46) { spbonus = spbonus / 1.5; } - mult += spbonus; - break; - - case SE_DamageShield: - case SE_Stun: - case SE_ArmorClass: - case SE_ATK: - case SE_STR: - case SE_DEX: - case SE_AGI: - case SE_STA: - case SE_INT: - case SE_WIS: - case SE_CHA: - case SE_CurrentMana: - case SE_Lull: - case SE_AddFaction: - case SE_Stamina: - case SE_ChangeFrenzyRad: - case SE_DiseaseCounter: - case SE_PoisonCounter: - case SE_ResistFire: - case SE_ResistCold: - case SE_ResistPoison: - case SE_ResistDisease: - case SE_ResistMagic: - case SE_Rune: - case SE_TotalHP: - case SE_TossUp: - case SE_ManaPool: - case SE_HealOverTime: - case SE_CastingLevel: - case SE_Hunger: - case SE_CurseCounter: - case SE_HealRate: - case SE_ImprovedDamage: - case SE_ImprovedHeal: - case SE_SpellResistReduction: - case SE_IncreaseSpellHaste: - case SE_IncreaseSpellDuration: - case SE_IncreaseRange: - case SE_AllStats: - case SE_MeleeLifetap: - case SE_AllInstrumentMod: - case SE_ResistSpellChance: - case SE_ResistFearChance: - case SE_HitChance: - case SE_DamageModifier: - case SE_MinDamageModifier: - case SE_IncreaseBlockChance: - case SE_CurrentEndurance: - case SE_EndurancePool: - case SE_CurrentEnduranceOnce: - case SE_MaxHPChange: - case SE_Accuracy: - case SE_BardAEDot: - case SE_CurrentManaOnce: - case SE_FactionMod: - case SE_CorruptionCounter: - case SE_ResistCorruption: - mult += spbonus; - break; - - default: - if(adval > 80) { caster->Message(315, "Generic effect - ignored"); } - return(effect_value); - break; - } - - //Shroud of the bear and Blood of the Master - if(caster->FindBuff(5045) || caster->FindBuff(1169)) - { - if(adval > 80) { caster->Message(315, "Shroud of bear nerf"); } - spadd = spadd * -1; - mult = 1.0f; - } - - int base_effect = effect_value; - - if(effect_value > 0) { effect_value += (int)ceil(spadd); } - else { effect_value -= (int)ceil(spadd); } - - effect_value = (int)( ceil((float)effect_value * mult) ); - - if(adval > 80) { caster->Message(315, "Spell Bonus: Base: %d, New: %d, Add: %d", base_effect, effect_value, spadd); } - - return( effect_value ); -} +int Mob::mod_effect_value(int effect_value, uint16 spell_id, int effect_type, Mob* caster) { return(effect_value); } //chancetohit - 0 to 100 percent - set over 1000 for a guaranteed hit -float Mob::mod_hit_chance(float chancetohit, SkillType skillinuse, Mob* attacker) { - if(!IsClient()) - { - //Factor NPC debuffs - return(chancetohit); - } - - int divisor; - - switch(GetClass()) - { - case MONK: - case ROGUE: - divisor = 8; - divisor -= (GetLevel() / 100) * 2; - break; - - default: - divisor = 8; - } - - float hitmod = ((float)CastToClient()->GetActDEX() - DW_STATBASE) / divisor; - hitmod += ((float)CastToClient()->GetActAGI() - DW_STATBASE) / divisor; - if(hitmod < 0) { hitmod = -5; } - - return(chancetohit + hitmod); -} +float Mob::mod_hit_chance(float chancetohit, SkillType skillinuse, Mob* attacker) { return(chancetohit); } //Final riposte chance -float Mob::mod_riposte_chance(float ripostechance, Mob* attacker) { - if(!IsClient()) { return(ripostechance); } - return(ripostechance + CastToClient()->GetActSTA()/200); -} +float Mob::mod_riposte_chance(float ripostechance, Mob* attacker) { return(ripostechance); } //Final block chance -float Mob::mod_block_chance(float blockchance, Mob* attacker) { - if(!IsClient()) { return(blockchance); } - return(blockchance + CastToClient()->GetActSTA()/200); -} +float Mob::mod_block_chance(float blockchance, Mob* attacker) { return(blockchance); } //Final parry chance -float Mob::mod_parry_chance(float parrychance, Mob* attacker) { - if(!IsClient()) { return(parrychance); } - return(parrychance + CastToClient()->GetActDEX()/200); -} +float Mob::mod_parry_chance(float parrychance, Mob* attacker) { return(parrychance); } //Final dodge chance -float Mob::mod_dodge_chance(float dodgechance, Mob* attacker) { - if(!IsClient()) { return(dodgechance); } - return(dodgechance + CastToClient()->GetActAGI()/200); -} +float Mob::mod_dodge_chance(float dodgechance, Mob* attacker) { return(dodgechance); } //Monk AC Bonus weight cap. Defined in Combat:MonkACBonusWeight //Usually 15, a monk under this weight threshold gets an AC bonus -float Mob::mod_monk_weight(float monkweight, Mob* attacker) { - if(!IsClient()) { return(monkweight); } - - monkweight += (CastToClient()->GetActAGI()/100) + (CastToClient()->GetActSTR()/50); - return(monkweight); -} +float Mob::mod_monk_weight(float monkweight, Mob* attacker) { return(monkweight); } //Mitigation rating is compared to incoming attack rating. Higher is better. -float Mob::mod_mitigation_rating(float mitigation_rating, Mob* attacker) { - if(!IsClient()) { return(mitigation_rating); } - - int shield_ac = 0; - float armor = (float)CastToClient()->GetRawACNoShield(shield_ac); - - switch(GetClass()) - { - case WARRIOR: - return(mitigation_rating + (armor/2)); - - case SHADOWKNIGHT: - case PALADIN: - return(mitigation_rating + (armor/3)); - - case RANGER: - case ROGUE: - case BARD: - return(mitigation_rating + (armor/5)); - - case BERSERKER: - if(CastToClient()->berserk) { return(mitigation_rating / 1.5); } - else { return(mitigation_rating); } - - default: - return(mitigation_rating); - } - - //Shouldn't ever get here - return(mitigation_rating); -} - -float Mob::mod_attack_rating(float attack_rating, Mob* defender) { - if(!IsClient()) { return(attack_rating); } - - float hprmult = 1 + (1 - (GetHP()/GetMaxHP())); - - switch(GetClass()) - { - case BERSERKER: - return(attack_rating * hprmult); - - case ROGUE: - if( BehindMob(defender, GetX(), GetY()) ) { return(attack_rating * 2); } - else { return(attack_rating); } - - default: - return(attack_rating); - } - - return(attack_rating); -} +float Mob::mod_mitigation_rating(float mitigation_rating, Mob* attacker) { return(mitigation_rating); } +float Mob::mod_attack_rating(float attack_rating, Mob* defender) { return(attack_rating); } //Kick damage after all other bonuses are applied -int32 Mob::mod_kick_damage(int32 dmg) { - if(!IsClient()) { return(dmg); } - - ItemInst *item = CastToClient()->GetInv().GetItem(SLOT_FEET); - if(item) - { - dmg += item->GetItem()->AC; - for(int i = 0; i < MAX_AUGMENT_SLOTS; ++i) - { - ItemInst *aug = item->GetAugment(i); - if(aug) - { - dmg += aug->GetItem()->AC; - } - } - } - dmg += GetLevel() / 4; - dmg = CastToClient()->mod_client_damage(dmg, KICK, 0, nullptr, nullptr); - - return(dmg); -} +int32 Mob::mod_kick_damage(int32 dmg) { return(dmg); } //Slam and bash damage after all other bonuses are applied -int32 Mob::mod_bash_damage(int32 dmg) { - if(!IsClient()) { return(dmg); } - - float lmult = (((float)GetLevel() * 2 ) / 100) + 1; - bool foundshield = false; - - ItemInst *item = CastToClient()->GetInv().GetItem(SLOT_SECONDARY); - if(item) - { - if(item->GetItem()->ItemType == ItemTypeShield) - { - foundshield = true; - dmg += item->GetItem()->AC * lmult; - for(int i = 0; i < MAX_AUGMENT_SLOTS; ++i) - { - ItemInst *aug = item->GetAugment(i); - if(aug) - { - dmg += aug->GetItem()->AC; - } - } - } - } - - if(!foundshield) //This is from a slam - { - item = CastToClient()->GetInv().GetItem(SLOT_SHOULDER); - if(item) - { - if(item->GetItem()->ItemType == ItemTypeArmor) - { - dmg += item->GetItem()->AC * lmult; - for(int i = 0; i < MAX_AUGMENT_SLOTS; ++i) - { - ItemInst *aug = item->GetAugment(i); - if(aug) - { - dmg += aug->GetItem()->AC; - } - } - } - } - } - - dmg += GetLevel() / 4; - dmg = CastToClient()->mod_client_damage(dmg, BASH, 0, nullptr, nullptr); - - return(dmg); -} +int32 Mob::mod_bash_damage(int32 dmg) { return(dmg); } //Frenzy damage after all other bonuses are applied -int32 Mob::mod_frenzy_damage(int32 dmg) { - if(!IsClient()) { return(dmg); } - - float hprmult = 1 + (1 - (GetHP()/GetMaxHP())); - - dmg = CastToClient()->mod_client_damage(dmg, FRENZY, 0, nullptr, nullptr); - - if(GetClass() == BERSERKER) - { - dmg = (int)( (float)dmg * hprmult ); - } - - return(dmg); -} +int32 Mob::mod_frenzy_damage(int32 dmg) { return(dmg); } //Special attack damage after all other bonuses are applied. -int32 Mob::mod_monk_special_damage(int32 ndamage, SkillType skill_type) { - if(!IsClient()) { return(ndamage); } - - ndamage = CastToClient()->mod_client_damage(ndamage, KICK, 0, nullptr, nullptr); - return(ndamage); -} +int32 Mob::mod_monk_special_damage(int32 ndamage, SkillType skill_type) { return(ndamage); } //ndamage - Backstab damage as calculated by default formulas -int32 Mob::mod_backstab_damage(int32 ndamage) { - if(!IsClient()) { return(ndamage); } - - float cdex = (float)CastToClient()->GetActDEX() - DW_STATBASE; - float cstr = (float)CastToClient()->GetActSTR() - DW_STATBASE; - float cagi = (float)CastToClient()->GetActAGI() - DW_STATBASE; - float bsm = 1.0f; - - bsm += (cdex / 200) + ((float)GetLevel() / 100); - bsm += cstr / 300; - bsm += cagi / 300; - - if(GetLevel() > 50) - { - float lbonus = GetLevel() - 50; - bsm += (lbonus * 0.1); - } - - return( (int32)((float)ndamage * bsm) ); -} +int32 Mob::mod_backstab_damage(int32 ndamage) { return(ndamage); } //Chance for 50+ archery bonus damage if Combat:UseArcheryBonusRoll is true. Base is Combat:ArcheryBonusChance int Mob::mod_archery_bonus_chance(int bonuschance, const ItemInst* RangeWeapon) { return(bonuschance); } @@ -926,82 +158,16 @@ int Mob::mod_archery_bonus_chance(int bonuschance, const ItemInst* RangeWeapon) uint32 Mob::mod_archery_bonus_damage(uint32 MaxDmg, const ItemInst* RangeWeapon) { return(MaxDmg); } //Final archery damage including bonus if it was applied. -int32 Mob::mod_archery_damage(int32 TotalDmg, bool hasbonus, const ItemInst* RangeWeapon) { - if(!IsClient()) { return(TotalDmg); } - - TotalDmg += (GetLevel() * 2); - TotalDmg = CastToClient()->mod_client_damage(TotalDmg, ARCHERY, 0, RangeWeapon, nullptr); - - return(TotalDmg); -} +int32 Mob::mod_archery_damage(int32 TotalDmg, bool hasbonus, const ItemInst* RangeWeapon) { return(TotalDmg); } //Thrown weapon damage after all other calcs -uint16 Mob::mod_throwing_damage(uint16 MaxDmg) { - if(!IsClient()) { return(MaxDmg); } +uint16 Mob::mod_throwing_damage(uint16 MaxDmg) { return(MaxDmg); } - MaxDmg = CastToClient()->mod_client_damage(MaxDmg, THROWING, 0, nullptr, nullptr); - return(MaxDmg); -} - -int32 Mob::mod_cast_time(int32 cast_time) { - if(!IsClient()) { return(cast_time); } - - float ctmod = 1; - float cdex = (float)CastToClient()->GetActDEX() - DW_STATBASE; - float ccast = 0; - - if(GetCasterClass() == 'W') - { - ccast = (float)CastToClient()->GetActWIS() - DW_STATBASE; - } - if(GetCasterClass() == 'I') - { - ccast = (float)CastToClient()->GetActINT() - DW_STATBASE; - } - if(ccast < 0.0001) { return(cast_time); } - - ctmod += cdex / 185; - ctmod += ccast / 185; - - if(GetLevel() > 50) - { - float lbonus = GetLevel() - 50; - ctmod += (lbonus * 0.1); - } - - return( (int32)((float)cast_time / ctmod) ); -} +//Spell cast time in milliseconds - will not sync with client cast time bar, but does work. +int32 Mob::mod_cast_time(int32 cast_time) { return(cast_time); } //res - Default buff duration formula -int Mob::mod_buff_duration(int res, Mob* caster, Mob* target, uint16 spell_id) { - //if(!IsClient()) { return(res); } - if(res <= 1) { return(res); } - if(!caster) { return(res); } - if(!caster->IsClient()) { return(res); } - - float cmult = 1; - -// caster->Message(315, "Duration: %d", res); - - if(caster->GetClass() == BARD) - { - cmult = (float)(caster->CastToClient()->GetActCHA() - DW_STATBASE) / 200; - } - else if(caster->GetCasterClass() == 'W') - { - cmult = (float)(caster->CastToClient()->GetActWIS() - DW_STATBASE) / 200; - } - else if(caster->GetCasterClass() == 'I') - { - cmult = (float)(caster->CastToClient()->GetActINT() - DW_STATBASE) / 200; - } - - cmult += (float)(caster->CastToClient()->GetActSTA() - DW_STATBASE) / 400; - - if(cmult < 1) { cmult = 1; } - - return( (int)((float)res * cmult) ); -} +int Mob::mod_buff_duration(int res, Mob* caster, Mob* target, uint16 spell_id) { return(res); } //Spell stack override - If this returns anything < 2, it will ignore all other stacking rules. // See spells.cpp: Mob::CheckStackConflict @@ -1009,137 +175,17 @@ int Mob::mod_buff_duration(int res, Mob* caster, Mob* target, uint16 spell_id) { // 1 - Overwrite, spellid1 is replaced by spellid2 // -1 - Blocked, spellid2 will not land // 2 - Default stacking behavior -int Mob::mod_spell_stack(uint16 spellid1, int caster_level1, Mob* caster1, uint16 spellid2, int caster_level2, Mob* caster2) { - - if(IsEffectInSpell(spellid1, SE_Illusion) && IsEffectInSpell(spellid2, SE_Illusion)) - { - return(1); - } - return(2); -} +int Mob::mod_spell_stack(uint16 spellid1, int caster_level1, Mob* caster1, uint16 spellid2, int caster_level2, Mob* caster2) { return(2); } //Sum of various resists rolled against a value of 200. int Mob::mod_spell_resist(int resist_chance, int level_mod, int resist_modifier, int target_resist, uint8 resist_type, uint16 spell_id, Mob* caster) { int final = resist_chance + level_mod + resist_modifier + target_resist; - - if(final > 185) { final = 185; } // Cap resist so it's always possible to land a spell (unless we hit the client level diff max). - - if(!caster) { return(final); } - - int temp_level_diff = GetLevel() - caster->GetLevel(); - if(temp_level_diff > 15 && caster->GetLevel() < 46) - { - if(caster->IsClient()) - { - if(caster->CastToClient()->GetAAXP() < 100) - { - return(0); - } - } - } - - if(!caster->IsClient()) { return(final); } - - float resistmod = 1.0f; - - //Make charisma a part of all resists - resistmod += ((float)caster->CastToClient()->GetActCHA() - DW_STATBASE) / 20; - - //The other half is the casting stat - if(caster->GetClass() == BARD) - { - resistmod += ((float)caster->CastToClient()->GetActCHA() - DW_STATBASE) / 20; - } - else if(caster->GetCasterClass() == 'W') - { - resistmod += ((float)caster->CastToClient()->GetActWIS() - DW_STATBASE) / 20; - } - else if(caster->GetCasterClass() == 'I') - { - resistmod += ((float)caster->CastToClient()->GetActINT() - DW_STATBASE) / 20; - } - - final -= resistmod; - - if(caster->GetLevel() > 50) - { - final -= (int)( (caster->GetLevel() - 50) * 20 ); - } - - //Let the client be highly resistant to their own AoE - if( - (spells[spell_id].targettype == ST_AECaster || spells[spell_id].targettype == ST_AETarget) && - caster->CastToClient()->CharacterID() == CastToClient()->CharacterID() - ) - { - final = 185; - } - return(final); } //Spell is cast by this on spelltar, called from spellontarget after the event_cast_on NPC event -void Mob::mod_spell_cast(uint16 spell_id, Mob* spelltar, bool reflect, bool use_resist_adjust, int16 resist_adjust, bool isproc) -{ - float cval = 5; - - if(!IsClient()) { return; } - if(GetClass() == WIZARD) - { - cval += (float)(CastToClient()->GetActINT() - DW_STATBASE) / 100; - cval += (float)(CastToClient()->GetActDEX() - DW_STATBASE) / 100; - cval += (float)(CastToClient()->GetActCHA() - DW_STATBASE) / 100; - cval += (float)(CastToClient()->GetActSTA() - DW_STATBASE) / 100; - - if(cval > 50) { cval = 50; } //This absolutely needs a cap - - if(MakeRandomFloat(0, 99) < cval) - { - Message(14, "You channel addition power into the spell!"); - SpellOnTarget(spell_id, spelltar, reflect, use_resist_adjust, resist_adjust, isproc); - -/* This is already recursive - if(MakeRandomFloat(0, 99) < cval) - { - Message(14, "You continue to channel additional power!"); - SpellOnTarget(spell_id, spelltar, reflect, use_resist_adjust, resist_adjust, isproc); - - if(MakeRandomFloat(0, 99) < cval) - { - Message(14, "You apply the full force of your concentration into the spell!"); - SpellOnTarget(spell_id, spelltar, reflect, use_resist_adjust, resist_adjust, isproc); - } - } -*/ - } - } -} +void Mob::mod_spell_cast(uint16 spell_id, Mob* spelltar, bool reflect, bool use_resist_adjust, int16 resist_adjust, bool isproc) { return; } //This is called right before regular event processing (the switch block) -void PerlembParser::mod_quest_event(QuestEventID event, uint32 objid, const char * data, NPC* npcmob, ItemInst* iteminst, Mob* mob, uint32 extradata, bool global, std::string packagename) { - NPC *tnpc = 0; - - if(event == EVENT_KILLED_MERIT || event == EVENT_CAST_ON || event == EVENT_SLAY) - { - const NPCType* tmp = 0; - if((tmp = database.GetNPCType(extradata))) - { - tnpc = new NPC(tmp, 0, 0, 0, 0, 0, FlyMode3); - } - else - { - tnpc = npcmob; - } - - if(tnpc) - { - ExportVar(packagename.c_str(), "npcname", tnpc->GetCleanName()); - ExportVar(packagename.c_str(), "npclastname", tnpc->GetLastName()); - ExportVar(packagename.c_str(), "npclevel", tnpc->GetLevel()); - ExportVar(packagename.c_str(), "bodytype", tnpc->GetBodyType()); - ExportVar(packagename.c_str(), "npcid", tnpc->GetNPCTypeID()); - ExportVar(packagename.c_str(), "npcrace", tnpc->GetRace()); - ExportVar(packagename.c_str(), "npcclass", tnpc->GetClass()); - } - } -} +//It is intended to be used for exporting new variables to new or existing events. +void PerlembParser::mod_quest_event(QuestEventID event, uint32 objid, const char * data, NPC* npcmob, ItemInst* iteminst, Mob* mob, uint32 extradata, bool global, std::string packagename) { return; } diff --git a/zone/mod_functions_base.cpp b/zone/mod_functions_base.cpp index 94750a184..bf559d733 100644 --- a/zone/mod_functions_base.cpp +++ b/zone/mod_functions_base.cpp @@ -13,6 +13,8 @@ #include "client.h" #include "worldserver.h" #include "QuestParserCollection.h" +#include "event_codes.h" +#include "embparser.h" #include #include @@ -21,8 +23,6 @@ extern Zone* zone; extern WorldServer worldserver; -using namespace std; - //All functions that modify a value are passed the value as it was computed by default formulas and bonuses. In most cases this should be the final value that will be used. //These are called when a zone boots or is repopped @@ -34,14 +34,31 @@ void NPC::mod_prespawn(Spawn2 *sp) { return; } //Base damage from NPC::Attack int NPC::mod_npc_damage(int damage, SkillType skillinuse, int hand, const Item_Struct* weapon, Mob* other) { return(damage); } + +//Mob c has been given credit for a kill. This is called after the regular EVENT_KILLED_MERIT event. void NPC::mod_npc_killed_merit(Mob* c) { return; } + +//Mob oos has been given credit for a kill. This is called after the regular EVENT_DEATH event. void NPC::mod_npc_killed(Mob* oos) { return; } //Base damage from Client::Attack - can cover myriad skill types -int Client::mod_client_damage(int damage, SkillType skillinuse, int hand, const ItemInst* weapon, Mob* other) { return(final); } +int Client::mod_client_damage(int damage, SkillType skillinuse, int hand, const ItemInst* weapon, Mob* other) { return(damage); } -//message is char[4096], don't screw it up. -bool Client::mod_client_message(char* message, uint8 chan_num) { return(true); } //Potentially dangerous string handling here +//message is char[4096], don't screw it up. Return true for normal behavior, false to return immediately. +// Channels: +// 0 - Guild Chat +// 2 - Group Chat +// 3 - Shout +// 4 - Auction +// 5 - Out of Character +// 6 - Broadcast +// 7 - Tell +// 8 - Say +// 11 - GMSay +// 15 - Raid Chat +// 20 - UCS Relay for UF client and later +// 22 - Emotes for UF and later +bool Client::mod_client_message(char* message, uint8 chan_num) { return(true); } //Skillup override. When this is called the regular skillup check has failed. Return false to proceed with default behavior. //This will NOT allow a client to increase skill past a cap. @@ -59,8 +76,14 @@ int Client::mod_bindwound_hp(int bindhps, Mob* bindmob) { return(bindhps); } //Client haste as calculated by default formulas - In percent from 0-100 int Client::mod_client_haste(int h) { return(h); } +//Haste cap override +int Client::mod_client_haste_cap(int cap) { return(cap); } + +//This is called when a client cons a mob void Client::mod_consider(Mob* tmob, Consider_Struct* con) { return; } -bool Client::mod_saylink(const std::string&, bool silentsaylink) { return(true); } + +//Return true to continue with normal behavior, false returns in the parent function +bool Client::mod_saylink(const std::string& response, bool silentsaylink) { return(true); } //Client pet power as calculated by default formulas and bonuses int16 Client::mod_pet_power(int16 act_power, uint16 spell_id) { return(act_power); } @@ -71,7 +94,7 @@ float Client::mod_tradeskill_chance(float chance, DBTradeskillRecipe_Struct *spe //Chance to skillup rolled against a random 0-99 where higher is better. float Client::mod_tradeskill_skillup(float chance_stage2) { return(chance_stage2); } -//Item Tribute value override -- Need to pass the item, duh. +//Tribute value override int32 Client::mod_tribute_item_value(int32 pts, const ItemInst* item) { return(pts); } //Death reporting @@ -79,20 +102,37 @@ void Client::mod_client_death_npc(Mob* killerMob) { return; } void Client::mod_client_death_duel(Mob* killerMob) { return; } void Client::mod_client_death_env() { return; } -//Calculated xp before consider modifier +//Calculated xp before consider modifier, called whenever a client gets XP for killing a mob. int32 Client::mod_client_xp(int32 in_xp, NPC *npc) { return(in_xp); } +//Client XP formula. Changes here will cause clients to change level after gaining or losing xp. +//Either modify this before your server goes live, or be prepared to write a quest script that fixes levels. +//To adjust how much XP is given per kill, use mod_client_xp +uint32 Client::mod_client_xp_for_level(uint32 xp, uint16 check_level) { return(xp); } + //effect_vallue - Spell effect value as calculated by default formulas. You will want to ignore effects that don't lend themselves to scaling - pet ID's, gate coords, etc. int Mob::mod_effect_value(int effect_value, uint16 spell_id, int effect_type, Mob* caster) { return(effect_value); } //chancetohit - 0 to 100 percent - set over 1000 for a guaranteed hit float Mob::mod_hit_chance(float chancetohit, SkillType skillinuse, Mob* attacker) { return(chancetohit); } +//Final riposte chance float Mob::mod_riposte_chance(float ripostechance, Mob* attacker) { return(ripostechance); } + +//Final block chance float Mob::mod_block_chance(float blockchance, Mob* attacker) { return(blockchance); } + +//Final parry chance float Mob::mod_parry_chance(float parrychance, Mob* attacker) { return(parrychance); } + +//Final dodge chance float Mob::mod_dodge_chance(float dodgechance, Mob* attacker) { return(dodgechance); } + +//Monk AC Bonus weight cap. Defined in Combat:MonkACBonusWeight +//Usually 15, a monk under this weight threshold gets an AC bonus float Mob::mod_monk_weight(float monkweight, Mob* attacker) { return(monkweight); } + +//Mitigation rating is compared to incoming attack rating. Higher is better. float Mob::mod_mitigation_rating(float mitigation_rating, Mob* attacker) { return(mitigation_rating); } float Mob::mod_attack_rating(float attack_rating, Mob* defender) { return(attack_rating); } @@ -123,6 +163,7 @@ int32 Mob::mod_archery_damage(int32 TotalDmg, bool hasbonus, const ItemInst* Ran //Thrown weapon damage after all other calcs uint16 Mob::mod_throwing_damage(uint16 MaxDmg) { return(MaxDmg); } +//Spell cast time in milliseconds - will not sync with client cast time bar, but does work. int32 Mob::mod_cast_time(int32 cast_time) { return(cast_time); } //res - Default buff duration formula @@ -137,4 +178,14 @@ int Mob::mod_buff_duration(int res, Mob* caster, Mob* target, uint16 spell_id) { int Mob::mod_spell_stack(uint16 spellid1, int caster_level1, Mob* caster1, uint16 spellid2, int caster_level2, Mob* caster2) { return(2); } //Sum of various resists rolled against a value of 200. -int Mob::mod_spell_resist(int resist_chance, int level_mod, int resist_modifier, int target_resist, uint8 resist_type, uint16 spell_id, Mob* caster) { return(resist_chance + level_mod + resist_modifier + target_resist); } +int Mob::mod_spell_resist(int resist_chance, int level_mod, int resist_modifier, int target_resist, uint8 resist_type, uint16 spell_id, Mob* caster) { + int final = resist_chance + level_mod + resist_modifier + target_resist; + return(final); +} + +//Spell is cast by this on spelltar, called from spellontarget after the event_cast_on NPC event +void Mob::mod_spell_cast(uint16 spell_id, Mob* spelltar, bool reflect, bool use_resist_adjust, int16 resist_adjust, bool isproc) { return; } + +//This is called right before regular event processing (the switch block) +//It is intended to be used for exporting new variables to new or existing events. +void PerlembParser::mod_quest_event(QuestEventID event, uint32 objid, const char * data, NPC* npcmob, ItemInst* iteminst, Mob* mob, uint32 extradata, bool global, std::string packagename) { return; } From b16cf575103abe51ae1c604fd529dd7117b3c0e4 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 1 Jun 2013 10:49:58 -0500 Subject: [PATCH 11/12] Cautionary XP mod update. --- zone/exp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/exp.cpp b/zone/exp.cpp index dab513750..a847f5873 100644 --- a/zone/exp.cpp +++ b/zone/exp.cpp @@ -485,7 +485,7 @@ uint32 Client::GetEXPForLevel(uint16 check_level) mod *= 1000; - uint32 finalxp = (uint32)(base * mod); + uint32 finalxp = uint32(base * mod); finalxp = mod_client_xp_for_level(finalxp, check_level); return(finalxp); From a8de7e9ffcc3d3eeeead547379d7b0934f030962 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 3 Jun 2013 17:08:58 -0500 Subject: [PATCH 12/12] Removed comments from mod_client.cpp for erroneous 255 stat cap. --- zone/client_mods.cpp | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/zone/client_mods.cpp b/zone/client_mods.cpp index 53680ca7e..eaab0ba81 100644 --- a/zone/client_mods.cpp +++ b/zone/client_mods.cpp @@ -1230,8 +1230,6 @@ int16 Client::CalcSTR() { int16 mod = aabonuses.STR; -// if(val>255 && GetLevel() <= 60) -// val = 255; STR = val + mod; if(STR < 1) @@ -1249,8 +1247,6 @@ int16 Client::CalcSTA() { int16 mod = aabonuses.STA; -// if(val>255 && GetLevel() <= 60) -// val = 255; STA = val + mod; if(STA < 1) @@ -1267,9 +1263,6 @@ int16 Client::CalcAGI() { int16 val = m_pp.AGI + itembonuses.AGI + spellbonuses.AGI - CalcAlcoholPhysicalEffect();; int16 mod = aabonuses.AGI; -// if(val>255 && GetLevel() <= 60) -// val = 255; - int16 str = GetSTR(); //Encumbered penalty @@ -1296,8 +1289,6 @@ int16 Client::CalcDEX() { int16 mod = aabonuses.DEX; -// if(val>255 && GetLevel() <= 60) -// val = 255; DEX = val + mod; if(DEX < 1) @@ -1315,8 +1306,6 @@ int16 Client::CalcINT() { int16 mod = aabonuses.INT; -// if(val>255 && GetLevel() <= 60) -// val = 255; INT = val + mod; if(m_pp.intoxication) @@ -1344,8 +1333,6 @@ int16 Client::CalcWIS() { int16 mod = aabonuses.WIS; -// if(val>255 && GetLevel() <= 60) -// val = 255; WIS = val + mod; if(m_pp.intoxication) @@ -1373,8 +1360,6 @@ int16 Client::CalcCHA() { int16 mod = aabonuses.CHA; -// if(val>255 && GetLevel() <= 60) -// val = 255; CHA = val + mod; if(CHA < 1)