PDA

View Full Version : Berserker Rage Volley Fix


Wolftousen
03-07-2009, 08:43 AM
File: zone/spell_effects.cpp
Line: 275

From:

if(spells[spell_id].skill == ARCHERY || spells[spell_id].skill == THROWING)
{

To:

//Wolftousen Rage Volley will bypass spell code and work like a normal throwing attack with 100% chance to hit
//check to see if Rage Volley is being cast and that we are a client since mobs do not use this spell
if(spell_id == 6754 && caster->IsClient())
{
//do a normal throwing attack instead of a"magic" attack to apply proper bonuses
caster->ThrowingAttack(caster->GetTarget());
break;
}
else if(spells[spell_id].skill == ARCHERY || spells[spell_id].skill == THROWING)
{

Description: This is to get Rage Volley working properly. It subverts the normal spell attack and uses the ThrowingAttack function to apply proper bonuses and chance to hit. There is also something you need to do to the ChanceToHit function to insure that Rage Volley works properly in this manner: http://www.eqemulator.net/forums/showthread.php?t=27640

Wolftousen
03-07-2009, 09:06 AM
Bah, scratch this for now, just realized that the ThrowingAttack function checks the attack timer. Will need a way around it if the discipline is to work this way.

Wolftousen
03-07-2009, 09:15 AM
Or add the following to -

File: zone/special_attack.cpp
Line: 897

From:
DeleteItemInInventory(ammo_slot, 1, true);
CheckIncreaseSkill(THROWING);

To:
if(!isCasting() || CastingSpellID() != 6754) //if we are casting Rage Volley Discipline, we do not use up ammo and do not skill up
{
DeleteItemInInventory(ammo_slot, 1, true);

CheckIncreaseSkill(THROWING);
}

And

File: zone/special_attack.cpp
Line: 759

From:

if((attack_timer.Enabled() && !attack_timer.Check(false)) || (ranged_timer.Enabled() && !ranged_timer.Check())) {
mlog(COMBAT__RANGED, "Throwing attack canceled. Timer not up. Attack %d, ranged %d", attack_timer.GetRemainingTime(), ranged_timer.GetRemainingTime());
Message(0, "Error: Timer not up. Attack %d, ranged %d", attack_timer.GetRemainingTime(), ranged_timer.GetRemainingTime());
return;
}

To:

if(!isCasting() || CastingSpellID() != 6754) //if we are casting Rage Volley Discipline, ignore the throwing attack timer
{
if((attack_timer.Enabled() && !attack_timer.Check(false)) || (ranged_timer.Enabled() && !ranged_timer.Check())) {
mlog(COMBAT__RANGED, "Throwing attack canceled. Timer not up. Attack %d, ranged %d", attack_timer.GetRemainingTime(), ranged_timer.GetRemainingTime());
Message(0, "Error: Timer not up. Attack %d, ranged %d", attack_timer.GetRemainingTime(), ranged_timer.GetRemainingTime());
return;
}
}

Wolftousen
03-07-2009, 09:30 AM
Also need to change this, Rage Volley never showed a resist message on live, it only ever showed miss messages (this may be able to be fixed in the spells_en.txt, i dunno though):

File: zone/spells.cpp
Line: 2,433

From:

if(IsResistableSpell(spell_id))

To:

if(spell_id != 6754 && IsResistableSpell(spell_id)) //Rage Volley is not resistable

AndMetal
03-07-2009, 04:06 PM
Just a recommendation, but it would be better to use IsEffectInSpell(spellid, effect) (http://code.google.com/p/projecteqemu/source/browse/trunk/EQEmuServer/zone/spdat.cpp#415) than hard coding the spell ID, in case it changes or there is a newer, similar spell down the line (or if someone wants to create a custom spell). You might even want to add a new function to both check if it's the skill attack (SE_SkillAttack (http://code.google.com/p/projecteqemu/source/browse/trunk/EQEmuServer/zone/spdat.h#300)) & return what skill is being used.

On a side note, it's awesome that you've been putting all of this work into adding & fixing AAs. I started working on making AAs more like spells as far as how they're calculated (every time we run CalcBonuses() (http://code.google.com/p/projecteqemu/source/browse/trunk/EQEmuServer/zone/bonuses.cpp#82)), but ran into a roadblock because we would have to run ~1600 queries to the database every time we calculate bonuses (see Client::CalcAABonuses() (http://code.google.com/p/projecteqemu/source/browse/trunk/EQEmuServer/zone/bonuses.cpp#414)). The alternative is to load AAs into shared memory, but I haven't had a chance to jump into that within the past several months. If we can do that, then we just have to modify the StatBonuses (http://code.google.com/p/projecteqemu/source/browse/trunk/EQEmuServer/zone/mob.h#140) struct to incorporate the new effects. Then, when we run the checks in the code, it would look something like this:
int bonus = itembonuses.AC + spellbonuses.AC + aabonuses.AC
Then, once we have all of the AA & spell effects in (the ones that aren't currently), new AAs are just a matter of adding to the database.

In the long run, I think it would be better if we can get this happening, since we're going to have to go back & make changes to all of the AAs we're putting in now once we do this (but going forward, it will be a lot easier).

Wolftousen
03-08-2009, 02:58 AM
Right, I was just trying to get the ability working in anyway possible before going into more depth with messing around with things. This code is so disorganized and uncommented it took me forever just to locate and follow the path that the Rage Volley Disc took, this quick "hack" was a way to see if it would start working right. I hadn't downloaded the latest SVN when I put this stuff in so I'm going back through and updating line numbers now. (Rage Volley isn't an AA btw if you thought it was)

I know Rage Volley is just the 1st of several Volley abilities, again, just a quick "hack" to get the ability working properly until a better solution can be done.

Adjusted line numbers for latest SVN.

File: zone/spells.cpp
Line: 2,433 should be 2,724

File: zone/special_attacks.cpp
Line: 897 should be 1,057
Line: 759 should be 934

File: zone/spell_effects.cpp
Line: 275 should be 2,233

cavedude
03-09-2009, 12:47 AM
This needs a bit of work before it can be committed. ThrowingAttack is a member of Client, not Mob. So, it would look something like:

Client *c=CastToClient();
c->ThrowingAttack(target);

However, I don't agree with that method. To the client, Rage Volley is a spell and it should be treated as such. Even if its effects need to be added manually that would be fine, though I would imagine that is handled by the spell data. The change in spells.cpp is not needed as whether a spell is resistible or not is handled by the spell data. The change to the ammo consumption causes zone to crash, however again the spell data for Rage Volley does not consume an item, so it wouldn't anyway (and testing it without your code proves me correct.) A minor detail, but important isCasting has to be IsCasting. Also, I agree with AndMetal, spellids should only be specified to exempt if the spelltype cannot be used for whatever reason (and I can only think of two situations in the code where this happens.) I would take a look at the spell data: http://lucy.allakhazam.com/spell.html?id=6754&source=Live and figure out what it handles. You might find you can nail it all in a line or two.

Wolftousen
03-09-2009, 03:35 AM
Ok, i understand and also agree. All of this was just a first glance "how can I get this working properly with what is already here" thing. That link to lucy is what i have been using, this code is just all over the place and hard to do things with...

The issue with this spell specifically at the moment is:
1. It is not supposed to be resistable period, I have gotten resist messages with it in game.
2. The attacks it does are supposed to hit 100% of the time
3. The skill mod the spell applies to the characters skill is not applied when calculating damage.
4. The berserker AA damage mods are not taken into account when calculating damage.

Solving #1: I'm not sure about how to do this, in lucy it says UNRESISTABLE, yet when i randomly tried it on an iksar guard outside sebilis I got a resist message with it, though that is the only one I have seen and may be a fluke. Put this off until I see it again or someone else does.

Solving #2: (this is the biggest issue, i've only seen issue #1 a few times on PEQ)
This issue is caused by line 2,290 in zone/spell_effects.cpp. It does a normal CheckHitChance as if it were a regular melee attack and does not take into account any spell accuracy modifiers as far as I can tell after examining the lines of code in CheckHitChance. I don't have experience with other melee classes discs to know whether or not they are unavoidable, so completely omitting this section could be bad. The if statement here that uses wpnD confuses me and seems like it's only purpose is to force a CheckHitChance.

After looking/finding a monk disc that is similar: http://lucy.allakhazam.com/spellraw.html?id=6752&source=Live I believe that the base2_# that corrisponds to the base# is the hit chance mod and if it is 10000 it is a 100% hit chance.

So to test/fix this we should edit line 2,290 in zone/spell_effects.cpp:
From:
if(CheckHitChance(caster, spells[spell_id].skill, 13))

To: (i is the EFFECT_COUNT counter the for loop is using)
if(spells[spell_id].base2[i] == 10000 || CheckHitChance(caster, spells[spell_id].skill, 13))

Solving #3: This can be done by changing line 2,240. This should probably be done for all the damage calcs under the SkillAttack effect, but to see if i'm right just do it for throwing/archery and we'll test with rage volley.

From:
dam = effect_value + itm->GetItem()->Damage * 2 + (itm->GetItem()->Damage * (GetSkill(spells[spell_id].skill) + GetDEX()) / 225);

To: spells[spell_id].base[i] (i is the EFFECT_COUNT counter the for loop is using)
dam = effect_value + itm->GetItem()->Damage * 2 + (itm->GetItem()->Damage * (GetSkill(spells[spell_id].skill) + spells[spell_id].base[i] + GetDEX()) / 225);

Solving #4: Easily solved by moving the AA check from throwing attack to ApplyMeleeDamageBonus function like so:

Take lines 1,015 to 1,027 from zone/special_attacks.cpp:
switch(GetAA(aaThrowingMastery))
{
case 1:
MaxDmg = MaxDmg * 115/100;
break;
case 2:
MaxDmg = MaxDmg * 125/100;
break;
case 3:
MaxDmg = MaxDmg * 150/100;
break;
}

And insert them into zone/attack.cpp at line 4,762 (Don't forget to remove from ThrowingAttack function or else it will get done twice). This will cause both a normal throwing attack and a spell based throwing attack to catch these bonuses.

Wolftousen
03-09-2009, 04:07 AM
Almost forgot, when doing the solution for #4, you need to put the switch statement in a if block and test the skill for type THROWING since the ApplyMeleeDamageBonus doesn't know that automatically. This way the damage bonus only gets applied if it is a throwing attack, like it should...

if(skill == THROWING)
{
switch(GetAA(aaThrowingMastery))
{
case 1:
MaxDmg = MaxDmg * 115/100;
break;
case 2:
MaxDmg = MaxDmg * 125/100;
break;
case 3:
MaxDmg = MaxDmg * 150/100;
break;
}
}

Wolftousen
03-09-2009, 05:23 AM
I'm not sure I like the solution to #4 quite yet, but it does get it partially in there. I realize that you want to view Rage Volley and other melee discs as spells, but not wanting to send it down the same path as a melee/ranged attack doesn't work out unless you want to repeat tons of code and make it even more ugly than it already is.

If you go to goberserker.com and ask if base damage bonuses, aa bonuses, item bonuses and spell bonuses apply to Rage Volley, you will get a very load yes. The current way this is set up, you get none of those bonuses period. Discs are Spells that cause modified physical attacks, thus they should always go down the physical attack pipeline and pick up bonuses along the way.

Also, the way it is set up, the min dmg is always 1 for discs that cause attacks. This isn't right either as Volley never hits for 1 on live.

The way this should work (at least for Rage Volley instance) is in SE_SkillAttack, if it is throwing skill, spells[spell_id].base[i] should be added to the mobs throwing skill and spells[spell_id].base2[i] should be added to the mobs throwing skill accuracy. After that, the 4 attacks should take place and then the modifications to the mobs throwing skill and throwing accuracy should be undone.

I thought about pilling all the damage bonuses for all physical attacks into ApplyMeleeDamageBonus function, but that still leaves the issue of min dmg on discs being 1.

I'm going to work on a better solution for #4, but I can tell you now that it is going to go down that same pipeline as a normal melee/ranged attack b/c that is what it does on live.

AndMetal
03-09-2009, 02:04 PM
It looks like the main reason Rage Volley doesn't work is we don't have SE_SkillAttack (http://code.google.com/p/projecteqemu/source/browse/trunk/EQEmuServer/zone/spdat.h#300) implemented. If we implement the spell effect, it should, as a result, implement Rage Volley, since all Rage Volley does it attempt 4 round kicks (skill 38 (http://www.eqemulator.net/wiki/wikka.php?wakka=SkillList)) based on the spell info. Everything else, like it being unresistable, should still be handled by the spell code.

Wolftousen
03-09-2009, 02:33 PM
It's not that it isn't working. It is working, it just isn't working as intended. it gets to and does SE_SkillAttack in spell_effects.cpp. But, that isn't the end of it b/c of the way SE_SkillAttack is currently functioning, it just needs to be fixed.

Wolftousen
03-09-2009, 03:20 PM
Also, you are interpreting the spell data wrong... The Skill Attack(38) is the bonus it applies to the skill being used with the spell. The skill being used is specified elseware in the rawdata if you scroll down. This ability does 4 throwing attacks. Zerkers don't get round kick and since this is a zerker only ability it would make no sense for it to use round kick...