Jump to content

Implememting Ghouls


Guest ChanF07

Recommended Posts

Currently the Death Knight spells Raise Dead, Raise Ally and Army of the Dead do not work.

After a bit of tinkering and browsing I have, so far, sort of found how Raise Dead works.

(NB Source list for spell info comes at end of post)

Initially the spell Raise Dead that a player would have access to is spell 46584.

This spell has two effects:

First is to call SPELL_EFFECT_SCRIPT_EFFECT (77) with the value of 46585.

The effect here, I guess, is to cast spell 46585, which happens to be a spell that summons a 2 minute long duration ghoul, with the spell effect no. 28 (SPELL_EFFECT_SUMMON).

It also passes on a summon type of 829, which the core does not recognize and prints the error "Unrecognized summon type 829".

This case, ithink, needs to be handled within somewhere in Pet.cpp in a similar fashion to a guardian; the player does not have control over the ghoul and acts much like a guardian.

Secondly the spell calls SPELL_EFFECT_DUMMY (3) with a value of 52150.

Spell 52150, is a spell to summon a pet ghoul, without a time limit.

This condition should only be achieved while the talent Master of Ghouls is active.

The core summons the pet fine in this case currently, as a normal pet.

In both cases the same ghoul (id= 26125) is summoned as a pet.

My trouble is how does the talent spell (52143) switch spell 46584 into casting 52150 instead? The talent spell calls a SPELL_EFFECT_DUMMY, so could we write an dummy spell exception to change 46584 to cast 52150?

The other problem with ghouls is how do we implement the summoning cost of 1 Corpse dust or a dead humanoid corpse? I need to do more browsing to find out if the player has to target a corpse to use the corpse instead of the corpse dust (will do later).

Anyway a big thanks to the developers for coding mangos. Also thanks in advance to any help. I am trying to learn to code, but am not confident.

Sources

Raise Dead (46584) - http://www.wowhead.com/?spell=46584 - Player spell

Raise Dead (46585) - http://www.wowhead.com/?spell=46585 - 2 minute ghoul spell

Raise Dead (52150) - http://www.wowhead.com/?spell=52150 - Pet summon spell

Master of Ghouls (52143) - http://www.wowhead.com/?spell=52143 - Talent that enables Pet Ghoul

I'll try and have a look at Raise Ally and Shadow of Death, which I suspect may be similar spells with just different targets, later.

Link to comment
Share on other sites

  • Replies 54
  • Created
  • Last Reply

Top Posters In This Topic

Some code; most likely wrong...etc Just and idea of how to implement. (I have no prior coding experience; so please don't use this code!)

//In SpellEffects.cpp
//Under void Spell::EffectScriptEffect(uint32 effIndex) probably under SPELLFAMILY_GENERIC somewhere
        case 46584:
         {
                  //  Get list of dummy auras
                   Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
                   for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr)
                   {
                      // Look for Master of Ghouls talent dummy spell (52143)
                       if((*itr)->GetSpellProto()->SpellId == 52143);
                           // Player has talent; cast pet ghoul spell
                           cast 52150
                           return;
                       // Player has not got talent; cast time limited ghoul spell
                       cast 46585
                       return;
                    }
         }

I am trying to place an exception so that when spell 46584 (Player Raise Dead spell) is cast, a check for whether the talent Master of Ghouls is active and if so cast 52150, else cast 46585.

Problems I see in code and need help with:

1) Is this the right way to check for if the talent is active? If so...

1a) Is there any way to check for the aura without iterating all the dummy auras that could be on the player at the time?

1GetId() seems to be what I'm looking for

Feel free to point out errors in my code because I can only learn from this exercise...

Link to comment
Share on other sites

I tested this code that came up with but I'm not sure why it didn't work and redirect the cast of the spell to the right spell. It did not generate compile errors but I'm not sure I'm doing it right.

@@ -4833,10 +4833,28 @@ void Spell::EffectScriptEffect(uint32 effIndex)

+                // Summon Ghoul
+                case 46584:
+                {
+                    //  Get list of dummy auras
+                    Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
+                    for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr)
+                    {
+                       // Look for Master of Ghouls talent dummy spell (52143)
+                        if((*itr)->GetId() == 52143)
+                            // Player has talent; cast pet ghoul spell
+                            m_caster->CastSpell(unitTarget, 52150, false);
+                            else
+                            // Player has not got talent; cast time limited ghoul spell
+                            m_caster->CastSpell(unitTarget, 46585, false);
+                        break;
+                    }
+                }
+


Feedback and hole poking of my code would be very appreciated.

Problems 1) and 1a) still apply I need some help in making sure I haven't screwed up

Link to comment
Share on other sites

Did you try with or without the talent?

Also, the corpse has to be targetted for the spell to not consume the Corpse Dust, so you could use

if( unitTarget && unitTarget->isDead() && unitTarget->GetCreatureType()==CREATURE_TYPE_HUMANOID )

for the check.

Ressing a player as a ghoul wouldn't work now without mind control working tho :(

Link to comment
Share on other sites

Luckily that's been shoved off to the Raise Ally spell. Currently the check to use corpse dust or a humanoid corpse isn't in the code yet, since I want to get the bare spell working at first. The requirement check can be probably added later (I'm assuming that the code follows a linear execution path). Thank you for your suggestion on how to do the humanoid corpse part.

I tried with talent and no talent. In theory the code above should, if I didn't screw up, cast a ghoul when character has talent or fail and do nothing without the talent since the exception for handling the two minute guardian hasn't been done yet :P.

I have a strange feeling that my GetId() check is failing or doing something weird or the spell is actually a spell not a aura. All help is really appreciated.

Link to comment
Share on other sites

I figured out why the summon doesn't work; for the path to the talent to work the talent must be on the player and for some reason the talent doesn't stay active after being cast... It instead has a spell effect dummy and just dies off :P Must code a way for talent to stay active. Either that or find a way to see if player knows spell 52143.

Other problem is that the summon spell need a target so I have to pass m_caster instead of uintTarget.

Spell 48289 is a dummy spell that requires corpse dust to be cast solving the dust requirement.

               // Summon Ghoul
               case 46584:
               {
                   //  Corpse or dust check
                   if( unitTarget && unitTarget->isDead() && unitTarget->GetCreatureType()==CREATURE_TYPE_HUMANOID )
                       return;
                   else
                       m_caster->CastSpell(m_caster,48289,false); 
                       return;
                   if( Player::HasSpell(52143))
                   {
                   //  Get list of dummy auras - Not working due to Master of Ghouls != dummy spell aura
                   // Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
                   // for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr)
                   //{
                      // Look for Master of Ghouls talent dummy spell (52143)
                       // if((*itr)->GetId() == 52143)
                           // Player has talent; cast pet ghoul spell
                           m_caster->CastSpell(m_caster, 52150, false);
                           else
                           // Player has not got talent; cast time limited ghoul spell
                           m_caster->CastSpell(m_caster, 46585, false);
                       break;
                   }
               }

EDIT: Problem with this code is that Player::HasSpell is not a static function and thus cannot be used in such a way... I really need some help.

Link to comment
Share on other sites

I finally tweaked the patch to work! Not...

Features still missing:

-[bug] Will consume a corpse dust even when a corpse is available

-Only corpses that yield experience/honor can be used by spell

-Should also remove corpse after use

case SPELLFAMILY_DEATHKNIGHT:
       {
           switch(m_spellInfo->Id)
           {
               // Summon Ghoul
               case 46584:
               {
                   //  Corpse or dust check
                   if( unitTarget && unitTarget->isDead() && unitTarget->GetCreatureType()==CREATURE_TYPE_HUMANOID )
                       m_caster->AttackStop();
                   else
                   {
                       if(((Player*)m_caster)->HasItemCount(37201,1))
                           ((Player*)m_caster)->DestroyItemCount(37201,1,true); 
                   }
                   // Look for Master of Ghouls talent dummy spell (52143)
                   if( m_caster->GetTypeId()==TYPEID_PLAYER && ((Player*)m_caster)->HasSpell(52143) )
                        // Player has talent; cast pet ghoul spell
                        m_caster->CastSpell(m_caster, 52150, false);
                        else
                        // Player has not got talent; cast time limited ghoul spell
                        m_caster->CastSpell(m_caster, 46585, false);
                       return;
                 }
           }
       }

I'd would have preferred a neater way to do the negative instead of the "m_caster->AttackStop();" (NB doing a negative if clause is not going to work)

Also I was under the impression that in a if/else clause it was either the first or second being executed not both which is somehow occurring in this example... or is its some special caste of no nesting past a certain depth?

Link to comment
Share on other sites

Bonus code

@@ -3197,10 +3197,11 @@ void Spell::EffectSummonType(uint32 i)
        case SUMMON_TYPE_GUARDIAN:
        case SUMMON_TYPE_POSESSED:
        case SUMMON_TYPE_POSESSED2:
        case SUMMON_TYPE_FORCE_OF_NATURE:
        case SUMMON_TYPE_GUARDIAN2:
+      case SUMMON_TYPE_GHOUL:
            EffectSummonGuardian(i);
            break;
        case SUMMON_TYPE_WILD:
            EffectSummonWild(i);
            break;

@@ -2082,10 +2082,11 @@ enum SummonType
    SUMMON_TYPE_CRITTER3    = 307,
    SUMMON_TYPE_UNKNOWN5    = 409,
    SUMMON_TYPE_UNKNOWN2    = 427,
    SUMMON_TYPE_POSESSED2   = 428,
    SUMMON_TYPE_FORCE_OF_NATURE = 669,
+  SUMMON_TYPE_GHOUL        = 829,
    SUMMON_TYPE_GUARDIAN2   = 1161
};

enum ResponseCodes
{

This adds support for the temporary 2 minute ghoul summon.

Link to comment
Share on other sites

Restructured code to avoid if/else issue. Also lot more easy to read but has duplication...

       case SPELLFAMILY_DEATHKNIGHT:
       {
           switch(m_spellInfo->Id)
           {
               // Summon Ghoul
               case 46584:
               {
                   // Corpse or dust check
                   // See if player is targeting a dead, humanoid, =plevel-3 target
                   if( [b]unitTarget->isDead()[/b] && unitTarget->GetCreatureType()==CREATURE_TYPE_HUMANOID && unitTarget->getLevel() >= m_caster->getLevel()-3 )
                   {
                       // Look for Master of Ghouls talent dummy spell (52143)
                       if( m_caster->GetTypeId()==TYPEID_PLAYER && ((Player*)m_caster)->HasSpell(52143) )
                       {
                           // Player has talent; cast pet ghoul spell
                           m_caster->CastSpell(m_caster, 52150, false);
                       }
                       else
                       {
                           // Player has not got talent; cast time limited ghoul spell
                           m_caster->CastSpell(m_caster, 46585, false);
                       }
                   }
                   else
                   {
                       //See if player has [Corpse Dust]; if yes -1 and continue, if no reset and break. (Note Dust removed after cast)
                       if(((Player*)m_caster)->HasItemCount(37201,1))
                       {
                           ((Player*)m_caster)->DestroyItemCount(37201,1,true);
                           // Look for Master of Ghouls talent dummy spell (52143)
                           if( m_caster->GetTypeId()==TYPEID_PLAYER && ((Player*)m_caster)->HasSpell(52143) )
                           {
                               // Player has talent; cast pet ghoul spell
                               m_caster->CastSpell(m_caster, 52150, false);
                               ((Player*)m_caster)->DestroyItemCount(37201,1,true);
                           }
                           else
                           {
                               // Player has not got talent; cast time limited ghoul spell
                               m_caster->CastSpell(m_caster, 46585, false);
                               ((Player*)m_caster)->DestroyItemCount(37201,1,true);
                           }
                       }
                       else
                           m_caster->CastStop();
                           return;
                   }
                       return;
                 }
           }
       }

The code in bold isn't working; for some mysterious reason the isDead check come back negative when targeting a corpse...

Link to comment
Share on other sites

Yes, I'm well aware of that, and thats exactly what I'm saying, I have the nameparts for the ghoul pet. Anyway, I'm looking at your code now, did some changes, added the nameparts and if it works I'll report back.

Instead of:

if( unitTarget->isDead() && unitTarget->GetCreatureType()==CREATURE_TYPE_HUMANOID && unitTarget->getLevel() >= m_caster->getLevel()-3 )

try

if (((unitTarget->GetCreatureType()==CREATURE_TYPE_HUMANOID) && (unitTarget->getLevel() >= m_caster->getLevel()-3)) && !unitTarget->isAlive())

Tested, not working. Trying some alternate options.

What does work:

Name generation, and save pet name to db. will upload a patch as soon as I tested it a bit.

Link to comment
Share on other sites

  • 1 month later...

Just my feeling, I may be wrong.

Maybe you should move the Ghould summon code to Player class instead of writing this is spell system.

EG: create a summon Ghould method that do the work. Check player talents, check around dead mobs, check consumable and finally probably call part of existing hunter pet code.

The hunter pet code manages already most of the permanent ghould possibilities. At first thinking, I see level progression which is different. A ghould has no XP and just follow DK's level.

About humanoid mob selection, I am not sure only the selected one is used as component. I don't let my ghould die on offy, so I don't summon it often :D Btw, I beleave any near mob that meet the requirements is used. So in case this is right (I cannot check soon), just use a CreatureLastSearcher to find one.

I hope this help.

Neo2003

Link to comment
Share on other sites

  • 1 month later...

This is what I got, I've also started working on the other pet related things regarding this, but, without this code block working as it should it's pretty useless working on the other aspects. Neo2003, the petspells etc all seem to reside in spelleffects.cpp, thus I'll keep this here for now. I'm still learning the pet side of things, and as I pick things up, I can make it better. But, I really need help here.

The problem I have is with this bit://tried Dead check(not working): unitTarget->GetHealth() == 0, !unitTarget->isAlive, unitTarget->isDead. I even did deathstate checks. Could anyone enlighten me, please?

/*&& unitTarget->getLevel() <= MaNGOS::XP::GetGrayLevel(m_caster->getLevel())*/ --will be checked as soon as I figured out the corpse check.

        
case SPELLFAMILY_DEATHKNIGHT:
       {
           switch (m_spellInfo->Id)
           // Summon Ghoul
       case 46584:
                {
                    //tried Dead check(not working): unitTarget->GetHealth() == 0, !unitTarget->isAlive, unitTarget->isDead
                    // See if player is targeting a dead, humanoid, =plevel-3 target
                    if(unitTarget && (unitTarget->GetCreatureType() == CREATURE_TYPE_HUMANOID || unitTarget->GetTypeId() == TYPEID_PLAYER)//works in Dalaran only- have to recheck?!?
                        /*&& unitTarget->getLevel() <= MaNGOS::XP::GetGrayLevel(m_caster->getLevel())*/)
                    {
                        sLog.outError("SUMMON GHOUL: Target is valid.");
                        if((m_caster)->HasSpell(52143) )// Look for Master of Ghouls talent dummy spell (52143)
                        {
                            sLog.outError("SUMMON GHOUL: Master of Ghouls.");
                            (m_caster)->CastSpell(unitTarget, 52150, false);// Player has talent; cast pet ghoul spell
                        }
                        else
                        {
                            sLog.outError("SUMMON GHOUL: No Master of Ghouls.");
                            (m_caster)->CastSpell(unitTarget, 46585, false);    
                        }
                        return;
                    }
                    else if( ((Player*)m_caster)->HasItemCount(37201,1))
                      {
                      sLog.outError("SUMMON GHOUL: Corpse dust present.");
                      ((Player*)m_caster)->DestroyItemCount(37201,1,true);
                      if((m_caster)->HasSpell(52143) )// Look for Master of Ghouls talent dummy spell (52143)
                      {
                          sLog.outError("SUMMON GHOUL: Master of Ghouls - Corpse dust used.");
                          (m_caster)->CastSpell(m_caster, 52150, false);// Player has talent; cast pet ghoul spell
                      }
                      else
                      {
                          sLog.outError("SUMMON GHOUL: No Master of Ghouls - Corpse dust used..");
                          (m_caster)->CastSpell(m_caster, 46585, false);
                      }
                      return;
                    }
                      else 
                      {
                          (m_caster)->CastStop();
                          sLog.outError("SUMMON GHOUL: Criteria not met!!.");
                          return;
                      }
                }
       }

Link to comment
Share on other sites

From memory

unitTarget->GetTypeId() == TYPEID_PLAYER

isn't needed since Raise Ally exists for that condition. (Not mentioning that for friendly players they have control of ghoul)

Oh yeah the bit about the lack of xp and etc; just define the temp ghoul as a guardian and that handles that (petstats are handled by db). Btw all the sLog.outError calls are debugs atm right? cause the console would light up fast and make it harder to trawl through the logs.

About the isDead check, it maybe that its has to be separated from the other checks due to some weird bug (or feature is design); from memory the only way isDead/Alive called is usually as a separate check like;

if(xyz=00100110)
{
if(unitTarget=isDead)
{
break;
}
...etc

Either that it was designed like this or we could be overloading the if() statement (no idea on this)

In reality it probably would be less hacky to make an operator that uses the CreatureLastSearcher, specified for a dead target then apply humanoid/xp filter. But this sorta too darn complex for me.

Link to comment
Share on other sites

Yeah, the sLog.outError is indeed for me to see exactly where it breaks, it will be removed as soon as it works. Lemme see if I can work around the dead check. It's pretty much the biggest problem at the moment.

It would be nice to have a little help from a dev that knows the system well tho. Just to give us a push in the right direction.

For the record, I tested:

Unit* victim = (Player*)m_caster->SelectNearbyTarget();

SelectNearbyTarget seems to check for enemies, a corpse is hardly an enemy. Damn!

Would changing the definition of it to check any nearby target impact alot of other things?

Would it be better to make a seperate lets say 'SelectDeadTarget' definition?

Link to comment
Share on other sites

I'm currently working on the cannibal spell, but so far I had limited success. ChanF07 - I couldn't find any SD references to corpse checks. I do think Neo2003 is correct, and I'm having the spell check for corpses via the 20577 check in Spell.cpp. thusfar though, no luck.

Will post what I have at the end of the day.

Spell.cpp:

added the line:

               case SPELL_EFFECT_DUMMY:
               {
                   switch(m_spellInfo->Id)
                   {
+                        case 46584:                         // Raise Dead
                       case 20577:                         // Cannibalize
                       {

My latest feeble attempt in Spelleffects.cpp(believe me I tried quite a few things) but I'm done now:

        case SPELLFAMILY_DEATHKNIGHT:
       {
           switch (m_spellInfo->Id)
          // Summon Ghoul
       case 46584:
                {
                    if( unitTarget->getLevel() > ManGOS::XP::GetGrayLevel(m_caster->getLevel())))              
                        return;

                    if(unitTarget && unitTarget->GetTypeId() == TYPEID_CORPSE && unitTarget->GetCreatureType() == CREATURE_TYPE_HUMANOID)
                    {
                            if((m_caster)->HasSpell(52143) )// Look for Master of Ghouls talent dummy spell (52143)
                            {
                                (m_caster)->CastSpell(unitTarget, 52150,false);// Player has talent; cast pet ghoul spell
                            }
                            else
                            {
                                (m_caster)->CastSpell(unitTarget, 46585,false);
                            }
                    }
                    else
                    {
                        if (!unitTarget && ((Player*)m_caster)->HasItemCount(37201,1))
                        {
                            ((Player*)m_caster)->DestroyItemCount(37201,1,true);
                            if((m_caster)->HasSpell(52143) )// Look for Master of Ghouls talent dummy spell (52143)
                            {
                                (m_caster)->CastSpell(m_caster, 52150,false);// Player has talent; cast pet ghoul spell
                            }
                            else
                            {
                                (m_caster)->CastSpell(m_caster, 46585,false);
                            }
                            return;
                        }
                    }
                }
       }

The rest of the pet code is kinda useless without this working, but if you want me to post what I did there, lemme know.

Link to comment
Share on other sites

I've finally installed / compiled my server again, and i'm also figgling around with your given codes :)

I've tried the one from post #17, but i can summon a ghoul w/out Corpse Dust or a nearby corpse (dunno how that can be, i've might done something wrong... i'm not an expert in C++, but i'm learning it on the way ;))

Also, on the very first try of casting the spell with the Ghoul-mastery talent on, i've summoned a pet with the name "Bonerawler". But after i dismissed him to give it another shot, he was called "Risen Ghoul" :huh: (Every time i summon him now, he's called like that...)

I'm going to see if i can help you guys a bit. Anyways, great work making it work sofar. =)

Edit: you got a little typo in your last code: ManGOS::XP::GetGrayLevel, it should be with a capital "N"

Link to comment
Share on other sites

  • 3 weeks later...

Since the Ghoul pet is only permanent if talent is known; more checks are need most likely and a check within the cast code is needed should the player respec and unlearn talent. What the dummy handle code would look like

case SPELLFAMILY_DEATHKNIGHT:
{
  switch (m_spellInfo->Id)
      // Summon Ghoul
      case 46584:
     {
            bool ptype =(m_caster)->HasSpell(52143);
            bool level = if( unitTarget->getLevel() > MaNGOS::XP::GetGrayLevel(m_caster->getLevel()));
            bool humanoid = if( unitTarget->GetCreatureType() == CREATURE_TYPE_HUMANOID);
            bool item = if((Player*)m_caster)->HasItemCount(37201,1));
            bool dead =  if(unitTarget->!isAlive());
            int spell0 = 0;

            if(level=false)
            {
                if(item=true)
                return;
               else
               break;
            return;
            if(dead=false)
            {
               if(item=true)
               return;
               else
               break;
            return;
            if(humanoid = false)
            {
                if(item=true)
                return;
               else
               break;
            return;
            if(ptype=false)
            {
             spell0 =52150
             }
            else
            {
            spell0 = 46585
            }            
           (m_caster)->CastSpell(m_caster,spell0 ,false);

      }
return;

Ofc none of this code is check for consistency, optimisation, style and full working; its just to give an rough outline of what I think can be done as a temp patch. Should someone (or someday after more learning, me) be able to do the get random target check, it would be a simple matter of setting that target as unitTarget or some other pointer for this code to work.

Also I don't have access to the latest source atm so I can't help code, test, write code better or see the cannabailse code (if someone reposts the relevent sections I may be able to guesstimate some working code).

Link to comment
Share on other sites

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. Privacy Policy Terms of Use