mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-17 03:08:26 +00:00
Implemented SPA 469, 470
Implemented SE_Chance_Best_in_Spell_Grp 469 Chance to cast highest scribed spell within a spell group. All base2 spells share roll chance, only 1 cast. SE_Trigger_Best_in_Spell_Grp 470 Chance to cast highest scribed spell within a spell group. Each spell has own chance. Additional Changes: Rewrote TrySpellTrigger function used for SPA 340 since it incorporates SPA 469. Improved code so that chance of spell being triggered should be more accurate statistically.
This commit is contained in:
+3
-3
@@ -682,7 +682,7 @@ typedef enum {
|
||||
#define SE_PercentXPIncrease 337 // implemented
|
||||
#define SE_SummonAndResAllCorpses 338 // implemented
|
||||
#define SE_TriggerOnCast 339 // implemented
|
||||
#define SE_SpellTrigger 340 // implemented - chance to trigger spell
|
||||
#define SE_SpellTrigger 340 // implemented - chance to trigger spell [Share rolls with 469] All base2 spells share roll chance, only 1 cast.
|
||||
#define SE_ItemAttackCapIncrease 341 // implemented[AA] - increases the maximum amount of attack you can gain from items.
|
||||
#define SE_ImmuneFleeing 342 // implemented - stop mob from fleeing
|
||||
#define SE_InterruptCasting 343 // implemented - % chance to interrupt spells being cast every tic. Cacophony (8272)
|
||||
@@ -811,8 +811,8 @@ typedef enum {
|
||||
#define SE_PC_Pet_Flurry_Chance 466 // implemented - Base1 % chance to do flurry from double attack hit.
|
||||
#define SE_DS_Mitigation_Amount 467 // implemented - Modify incoming damage shield damage by percentage
|
||||
#define SE_DS_Mitigation_Percentage 468 // implemented - Modify incoming damage shield damage by a flat amount
|
||||
//#define SE_Chance_Best_in_Spell_Grp 469 //
|
||||
//#define SE_Trigger_Best_in_Spell Grp 470 //
|
||||
#define SE_Chance_Best_in_Spell_Grp 469 // implemented - Chance to cast highest scribed spell within a spell group. All base2 spells share roll chance, only 1 cast.
|
||||
#define SE_Trigger_Best_in_Spell_Grp 470 // implemented - Chance to cast highest scribed spell within a spell group. Each spell has own chance.
|
||||
//#define SE_Double_Melee_Round 471 //
|
||||
//#define SE_Buy_AA_Rank 472 //
|
||||
#define SE_Double_Backstab_Front 473 // implemented - Chance to double backstab from front
|
||||
|
||||
@@ -1021,6 +1021,7 @@ public:
|
||||
int GetNextAvailableSpellBookSlot(int starting_slot = 0);
|
||||
inline uint32 GetSpellByBookSlot(int book_slot) { return m_pp.spell_book[book_slot]; }
|
||||
inline bool HasSpellScribed(int spellid) { return FindSpellBookSlotBySpellID(spellid) != -1; }
|
||||
uint32 GetHighestScribedSpellinSpellGroup(uint32 spell_group);
|
||||
uint16 GetMaxSkillAfterSpecializationRules(EQ::skills::SkillType skillid, uint16 maxSkill);
|
||||
void SendPopupToClient(const char *Title, const char *Text, uint32 PopupID = 0, uint32 Buttons = 0, uint32 Duration = 0);
|
||||
void SendFullPopup(const char *Title, const char *Text, uint32 PopupID = 0, uint32 NegativeID = 0, uint32 Buttons = 0, uint32 Duration = 0, const char *ButtonName0 = 0, const char *ButtonName1 = 0, uint32 SoundControls = 0);
|
||||
|
||||
+64
-39
@@ -3537,57 +3537,82 @@ void Mob::TriggerOnCast(uint32 focus_spell, uint32 spell_id, bool aa_trigger)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool Mob::TrySpellTrigger(Mob *target, uint32 spell_id, int effect)
|
||||
{
|
||||
if(!target || !IsValidSpell(spell_id))
|
||||
if (!target || !IsValidSpell(spell_id))
|
||||
return false;
|
||||
|
||||
int spell_trig = 0;
|
||||
// Count all the percentage chances to trigger for all effects
|
||||
for(int i = 0; i < EFFECT_COUNT; i++)
|
||||
{
|
||||
if (spells[spell_id].effectid[i] == SE_SpellTrigger)
|
||||
spell_trig += spells[spell_id].base[i];
|
||||
}
|
||||
// If all the % add to 100, then only one of the effects can fire but one has to fire.
|
||||
if (spell_trig == 100)
|
||||
{
|
||||
int trig_chance = 100;
|
||||
for(int i = 0; i < EFFECT_COUNT; i++)
|
||||
{
|
||||
if (spells[spell_id].effectid[i] == SE_SpellTrigger)
|
||||
{
|
||||
if(zone->random.Int(0, trig_chance) <= spells[spell_id].base[i])
|
||||
{
|
||||
// If we trigger an effect then its over.
|
||||
if (IsValidSpell(spells[spell_id].base2[i])){
|
||||
SpellFinished(spells[spell_id].base2[i], target, EQ::spells::CastingSlot::Item, 0, -1, spells[spells[spell_id].base2[i]].ResistDiff);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Increase the chance to fire for the next effect, if all effects fail, the final effect will fire.
|
||||
trig_chance -= spells[spell_id].base[i];
|
||||
}
|
||||
}
|
||||
/*The effects SE_SpellTrigger (SPA 340) and SE_Chance_Best_in_Spell_Grp (SPA 469) work as follows, you typically will have 2-3 different spells each with their own
|
||||
chance to be triggered with all chances equaling up to 100 pct, with only 1 spell out of the group being ultimately cast.
|
||||
(ie Effect1 trigger spellA with 30% chance, Effect2 triggers spellB with 20% chance, Effect3 triggers spellC with 50% chance).
|
||||
The following function ensures a stastically accurate chance for each spell to be cast based on their chance values. These effects are also used in spells where there
|
||||
is only 1 effect using the trigger effect. In those situations we simply roll a chance for that spell to be cast once.
|
||||
Note: Both SPA 340 and 469 can be in same spell and both cummulative add up to 100 pct chances. SPA469 only difference being the spell cast will
|
||||
be "best in spell group", instead of a defined spell_id.*/
|
||||
|
||||
}
|
||||
}
|
||||
// if the chances don't add to 100, then each effect gets a chance to fire, chance for no trigger as well.
|
||||
else
|
||||
int chance_array[EFFECT_COUNT] = {};
|
||||
int total_chance = 0;
|
||||
int effect_slot = effect;
|
||||
bool CastSpell = false;
|
||||
|
||||
for (int i = 0; i < EFFECT_COUNT; i++)
|
||||
{
|
||||
if(zone->random.Int(0, 100) <= spells[spell_id].base[effect])
|
||||
{
|
||||
if (IsValidSpell(spells[spell_id].base2[effect])){
|
||||
SpellFinished(spells[spell_id].base2[effect], target, EQ::spells::CastingSlot::Item, 0, -1, spells[spells[spell_id].base2[effect]].ResistDiff);
|
||||
return true; //Only trigger once of these per spell effect.
|
||||
if (spells[spell_id].effectid[i] == SE_SpellTrigger || spells[spell_id].effectid[i] == SE_Chance_Best_in_Spell_Grp)
|
||||
total_chance += spells[spell_id].base[i];
|
||||
}
|
||||
|
||||
if (total_chance == 100)
|
||||
{
|
||||
int current_chance = 0;
|
||||
int cummulative_chance = 0;
|
||||
|
||||
for (int i = 0; i < EFFECT_COUNT; i++){
|
||||
//Find spells with SPA 340 and add the cummulative percent chances to the roll array
|
||||
if ((spells[spell_id].effectid[i] == SE_SpellTrigger) || (spells[spell_id].effectid[i] == SE_Chance_Best_in_Spell_Grp)){
|
||||
|
||||
cummulative_chance = current_chance + spells[spell_id].base[i];
|
||||
chance_array[i] = cummulative_chance;
|
||||
current_chance = cummulative_chance;
|
||||
}
|
||||
}
|
||||
int random_roll = zone->random.Int(1, 100);
|
||||
//Determine which spell out of the group of the spells (each with own percent chance out of 100) will be cast based on a single roll.
|
||||
for (int i = 0; i < EFFECT_COUNT; i++){
|
||||
if (chance_array[i] != 0 && random_roll <= chance_array[i]) {
|
||||
effect_slot = i;
|
||||
CastSpell = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//If the chances don't add to 100, then each effect gets a chance to fire, chance for no trigger as well.
|
||||
else if (zone->random.Roll(spells[spell_id].base[effect])) {
|
||||
CastSpell = true; //In this case effect_slot is what was passed into function.
|
||||
}
|
||||
|
||||
if (CastSpell) {
|
||||
if (spells[spell_id].effectid[effect_slot] == SE_SpellTrigger && IsValidSpell(spells[spell_id].base2[effect_slot])) {
|
||||
SpellFinished(spells[spell_id].base2[effect_slot], target, EQ::spells::CastingSlot::Item, 0, -1, spells[spells[spell_id].base2[effect_slot]].ResistDiff);
|
||||
return true;
|
||||
}
|
||||
else if (IsClient() & spells[spell_id].effectid[effect_slot] == SE_Chance_Best_in_Spell_Grp) {
|
||||
uint32 best_spell_id = CastToClient()->GetHighestScribedSpellinSpellGroup(spells[spell_id].base2[effect_slot]);
|
||||
if (IsValidSpell(best_spell_id)) {
|
||||
SpellFinished(best_spell_id, target, EQ::spells::CastingSlot::Item, 0, -1, spells[best_spell_id].ResistDiff);
|
||||
}
|
||||
return true;//Do nothing if you don't have the any spell in spell group scribed.
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Mob::TryTriggerOnValueAmount(bool IsHP, bool IsMana, bool IsEndur, bool IsPet)
|
||||
{
|
||||
/*
|
||||
|
||||
+25
-3
@@ -197,7 +197,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
if (!IsPowerDistModSpell(spell_id))
|
||||
SetSpellPowerDistanceMod(0);
|
||||
|
||||
bool SE_SpellTrigger_HasCast = false;
|
||||
bool spell_trigger_cast_complete = false; //Used with SE_Spell_Trigger and SE_Chance_Best_in_Spell_Grp, true when spell has been triggered.
|
||||
|
||||
// if buff slot, use instrument mod there, otherwise calc it
|
||||
uint32 instrument_mod = buffslot > -1 ? buffs[buffslot].instrument_mod : caster ? caster->GetInstrumentMod(spell_id) : 10;
|
||||
@@ -2822,9 +2822,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
|
||||
case SE_SpellTrigger: {
|
||||
|
||||
if (!SE_SpellTrigger_HasCast) {
|
||||
if (!spell_trigger_cast_complete) {
|
||||
if (caster && caster->TrySpellTrigger(this, spell_id, i))
|
||||
SE_SpellTrigger_HasCast = true;
|
||||
spell_trigger_cast_complete = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2873,6 +2873,28 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
HealDamage(amt, caster);
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_Chance_Best_in_Spell_Grp: {
|
||||
if (!spell_trigger_cast_complete) {
|
||||
if (caster && caster->TrySpellTrigger(this, spell_id, i))
|
||||
spell_trigger_cast_complete = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_Trigger_Best_in_Spell_Grp: {
|
||||
|
||||
if (caster && !caster->IsClient())
|
||||
break;
|
||||
|
||||
if (zone->random.Roll(spells[spell_id].base[i])) {
|
||||
uint32 best_spell_id = caster->CastToClient()->GetHighestScribedSpellinSpellGroup(spells[spell_id].base2[i]);
|
||||
|
||||
if (caster && IsValidSpell(best_spell_id))
|
||||
caster->SpellFinished(best_spell_id, this, EQ::spells::CastingSlot::Item, 0, -1, spells[best_spell_id].ResistDiff);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case SE_PersistentEffect:
|
||||
|
||||
@@ -5251,6 +5251,27 @@ int Client::FindSpellBookSlotBySpellID(uint16 spellid) {
|
||||
return -1; //default
|
||||
}
|
||||
|
||||
uint32 Client::GetHighestScribedSpellinSpellGroup(uint32 spell_group)
|
||||
{
|
||||
//Typical live spells follow 1/5/10 rank value for actual ranks 1/2/3, but this can technically be set as anything.
|
||||
|
||||
int highest_rank = 0; //highest ranked found in spellgroup
|
||||
uint32 highest_spell_id = 0; //spell_id of the highest ranked spell you have scribed in that spell rank.
|
||||
|
||||
for (int i = 0; i < EQ::spells::SPELLBOOK_SIZE; i++) {
|
||||
|
||||
if (IsValidSpell(m_pp.spell_book[i])) {
|
||||
if (spells[m_pp.spell_book[i]].spellgroup == spell_group) {
|
||||
if (highest_rank < spells[m_pp.spell_book[i]].rank) {
|
||||
highest_rank = spells[m_pp.spell_book[i]].rank;
|
||||
highest_spell_id = m_pp.spell_book[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return highest_spell_id;
|
||||
}
|
||||
|
||||
bool Client::SpellGlobalCheck(uint16 spell_id, uint32 char_id) {
|
||||
std::string spell_global_name;
|
||||
int spell_global_value;
|
||||
|
||||
Reference in New Issue
Block a user