EQEmulator Forums

EQEmulator Forums (https://www.eqemulator.org/forums/index.php)
-   Archive::Development (https://www.eqemulator.org/forums/forumdisplay.php?f=621)
-   -   Fix: Invisibility and IVU (Huge! Requires DB change) (https://www.eqemulator.org/forums/showthread.php?t=11455)

Mongrel 01-20-2004 04:27 AM

Fix: Invisibility and IVU (Huge! Requires DB change)
 
This is a pretty big update, so I probably made a mistake somewhere in this post. I'll update this accordingly.

Note to the devs: I'd love to post this in a better way, but I don't know how to use diffs. It's a large update, sorry if it's confusing at some points.

Another note: Some of the linebreaks might be wrong (they shouldn't though). I had to add them to make this somewhat readable.

@Trump: If this is too large for you to merge (not meant as an insult!), maybe you could send me your cvs version and I'll merge it in myself.

To make invis and IVU work we have to change the DB structure a bit and modify the code for zone.exe.

DB changes:
First we need to change our NPC Types table. We will add three columns: see_invis, see_invis_undead and undead. All three are pretty self-explanatory, however they're not linked with each other in any way shape or form. That way it's easy to make high level undeads that can see through Invis vs. Undead or boss mobs that see through normal Invisibility.

Here are the SQL commands to change the DB (copy&paste the commands below into a text file):

Code:

-- Add a see_invis, see_invis_undead and an undead column
ALTER TABLE npc_types ADD COLUMN
(
see_invis TINYINT NOT NULL default '0',
see_invis_undead TINYINT NOT NULL default '1'
);

This will make all our mobs "alive" and able to see through IVU, but not through invis.

Here are SQL commands to make a few npcs undead:

Code:

-- Change race 14 (Werewolf) to undead
UPDATE npc_types SET see_invis=1, see_invis_undead=0 WHERE race=14;

-- Change race 27 (Froglok Ghoul) to undead
UPDATE npc_types SET see_invis=1, see_invis_undead=0 WHERE race=27;

-- Change race 32 (Ghost) to undead
UPDATE npc_types SET see_invis=1, see_invis_undead=0 WHERE race=32;

-- Change race 33 (Ghoul) to undead
UPDATE npc_types SET see_invis=1, see_invis_undead=0 WHERE race=33;

-- Change race 45 (Demi Lich) to undead
UPDATE npc_types SET see_invis=1, see_invis_undead=0 WHERE race=45;

-- Change race 60 (Skeleton) to undead
UPDATE npc_types SET see_invis=1, see_invis_undead=0 WHERE race=60;

-- Change race 65 (Vampire) to undead
UPDATE npc_types SET see_invis=1, see_invis_undead=0 WHERE race=65;

-- Change race 70 (Zombie) to undead
UPDATE npc_types SET see_invis=1, see_invis_undead=0 WHERE race=70;

-- Change race 85 (Spectre) to undead
UPDATE npc_types SET see_invis=1, see_invis_undead=0 WHERE race=85;

-- Change race 98 (Elf Vampire) to undead
UPDATE npc_types SET see_invis=1, see_invis_undead=0 WHERE race=98;

-- Change race 117 (Ghost Dwarf) to undead
UPDATE npc_types SET see_invis=1, see_invis_undead=0 WHERE race=117;

-- Change race 118 (Erudite Ghost) to undead
UPDATE npc_types SET see_invis=1, see_invis_undead=0 WHERE race=118;

-- Change race 122 (Dragon Skeleton) to undead
UPDATE npc_types SET see_invis=1, see_invis_undead=0 WHERE race=122;

-- Change race 146 (Spectral Sarnak) to undead
UPDATE npc_types SET see_invis=1, see_invis_undead=0 WHERE race=146;

-- Change race 147 (Spectral Iksar) to undead
UPDATE npc_types SET see_invis=1, see_invis_undead=0 WHERE race=147;

-- Change race 155 (Sarnak Skeleton) to undead
UPDATE npc_types SET see_invis=1, see_invis_undead=0 WHERE race=155;

-- Change race 161 (Iksar Skeleton) to undead
UPDATE npc_types SET see_invis=1, see_invis_undead=0 WHERE race=161;

-- Change race 174 (Cold Spectre) to undead
UPDATE npc_types SET see_invis=1, see_invis_undead=0 WHERE race=174;

-- Change race 196 (Ghost Dragon) to undead
UPDATE npc_types SET see_invis=1, see_invis_undead=0 WHERE race=196;

-- Change race 208 (Vampyre) to undead
UPDATE npc_types SET see_invis=1, see_invis_undead=0 WHERE race=208;

-- Change race 234 (Vah Shir Skeleton) to undead
UPDATE npc_types SET see_invis=1, see_invis_undead=0 WHERE race=234;

-- Change race 282 (Skeletal Horse) to undead
UPDATE npc_types SET see_invis=1, see_invis_undead=0 WHERE race=282;

I'm sure I missed a few PoP undeads, but I never played PoP on live, so I don't really know those races. Feel free to add a few on your own.
That was easy, wasn't it? Gets a lot more difficult now ...

Now to the code changes:
In zone/zonedump.h add the following two lines to the structure NPCType:

Code:

        bool        see_invis;                        // Mongrel: See Invis flag added
        bool        see_invis_undead;        // Mongrel: See Invis flag added

At this point you may have to rebuild EQEmuShareMem. While I was debugging this I found that sizeof(NPCType) returned the wrong value. Recompiling fixed this.

In common/database.cpp search for the following line four times. The first appearance is right at the top of the file, we don't want that one. The second and third appearances is about items and doors, we don't need those. The fourth appearance is the one we need (about npc_types).
Code:

#ifdef SHAREMEM
Inside this #ifdef block you will find a function named bool Database::DBLoadNPCTypes(). This function is used to load the NPC Types from the DB when you're using EQEmuShareMem. I doubt anyone is using the non-sharemem version, so won't go into that now.

Inside bool Database::DBLoadNPCTypes() look for the following lines:
Code:

                        NPCType tmpNPCType;
                        // support the old database too for a while...
                        // neotokyo: added aggroradius
                        // neotokyo: added bodytype
                        MakeAnyLenString(&query, "SELECT id,name,level,race,class,hp,gender,texture,helmtexture,size,loottable_id, merchant_id, banish, mindmg, maxdmg, npcspecialattks, npc_spells_id, d_meele_texture1,d_meele_texture2, walkspeed, runspeed,fixedz,hp_regen_rate,mana_regen_rate,aggroradius,bodytype,npc_faction_id,face FROM npc_types");//WHERE zone='%s'", zone_name
                        if (RunQuery(query, strlen(query), errbuf, &result))
                        {

Replace it with:
Code:

                        NPCType tmpNPCType;
                        // support the old database too for a while...
                        // neotokyo: added aggroradius
                        // neotokyo: added bodytype
                        MakeAnyLenString(&query, "SELECT id,name,level,race,class,hp,gender,texture,helmtexture,size,loottable_id, merchant_id, banish, mindmg, maxdmg, npcspecialattks, npc_spells_id, d_meele_texture1,d_meele_texture2, walkspeed, runspeed,fixedz,hp_regen_rate,mana_regen_rate,aggroradius,
bodytype,npc_faction_id,face,see_invis,see_invis_undead FROM npc_types");//WHERE zone='%s'", zone_name
                        if (RunQuery(query, strlen(query), errbuf, &result))
                        {

I have added "see_invis,see_invis_undead" to the end of the query.

Then change this:
Code:

                                        tmpNPCType.luclinface=atoi(row[27]);
                                        // set defaultvalue for aggroradius
                                        if (tmpNPCType.aggroradius <= 0)
                                                tmpNPCType.aggroradius = 70;

                                        //tmpNPCType.ipc = atoi(row[27]);

to this:
Code:

                                        tmpNPCType.luclinface=atoi(row[27]);
                                        // set defaultvalue for aggroradius
                                        if (tmpNPCType.aggroradius <= 0)
                                                tmpNPCType.aggroradius = 70;

                                        tmpNPCType.see_invis = atoi(row[28]);
                                        tmpNPCType.see_invis_undead = atoi(row[29]);
                                                        //tmpNPCType.ipc = atoi(row[27]);

At this point the NPC Types have been updated, however mobs, when spawned, do not know about this yet. That's what we'll do next.

In zone/mob.h find the constructor of the class "mob"
Code:

        Mob(const char*  in_name,
            const char*  in_lastname,
            sint32  in_cur_hp,
            sint32  in_max_hp,

// Many more lines of code here ... skipping ...

            int16  in_d_meele_texture1,
            int16  in_d_meele_texture2
        );
        virtual ~Mob();

add the following two lines to the end of the constructor:
Code:

                int8        in_see_invis,
                int8        in_see_invis_undead

The result should look like this:
Code:

        Mob(const char*  in_name,
            const char*  in_lastname,
            sint32  in_cur_hp,
            sint32  in_max_hp,

// Many more lines of code here ... skipping ...

            int16  in_d_meele_texture1,
            int16  in_d_meele_texture2,
                int8        in_see_invis,
                int8        in_see_invis_undead
        );
        virtual ~Mob();

Do not forget to add the comma after "in_d_meele_texture2"

Now search for the following lines in the same file:
Code:

        inline bool SeeInvisible() { return false; }
        inline bool SeeInvisibleUndead() { return true; }
       
        bool IsInvisible(Mob* other = 0) {
        // TC - removing until SeeInvisible is implemented.
        //if (other && other->SeeInvisible() && !sneaking) { return false; }
                if (other && !sneaking) { return false; }
          if (sneaking && BehindMob(other, GetX(), GetY()) ){ return true; }
      else { return invisible; }
    }

Replace it with:
Code:

        inline bool SeeInvisible() { return see_invis; }                                // Mongrel: Now using the flags
        inline bool SeeInvisibleUndead() { return see_invis_undead; }        // Mongrel: Now using the flags
       
        bool IsInvisible(Mob* other = 0)
        {
        // TC - removing until SeeInvisible is implemented.
        // Mongrel: Reimplementing see invis
                if (other && invisible && !other->SeeInvisible())
                {
                        return true;
                }
                if (other && invisible_undead && !other->SeeInvisibleUndead())
                {
                        return true;
                }
                if (other && !sneaking)
                {
                        return false;
                }
                if (sneaking && BehindMob(other, GetX(), GetY()) )
                {
                        return true;
                }
                else
                {
                        return invisible;
                }
        }

Now find this (still in zone/mob.h)
Code:

        bool        invulnerable;
        bool        invisible, invisible_undead, sneaking;
        void        Spin();
        void        Kill();

Replace with:
Code:

        bool        invulnerable;
        bool        invisible, invisible_undead, sneaking;
        bool        see_invis, see_invis_undead;        // Mongrel: See Invis and See Invis vs. Undead
        void        Spin();
        void        Kill();

Now open zone/mob.cpp and apply the changes we just made to the constructor:
Change
Code:

                int8        in_luclinface, // and beard
                int8        in_aa_title,
                float        in_fixed_z,
                int16        in_d_meele_texture1,
                int16        in_d_meele_texture2
                )
{

to

Code:

                int8        in_luclinface, // and beard
                int8        in_aa_title,
                float        in_fixed_z,
                int16        in_d_meele_texture1,
                int16        in_d_meele_texture2,
                int8        in_see_invis,
                int8        in_see_invis_undead
                )
{

At the end of the constructor change:
Code:

        pStandingPetOrder = SPO_Follow;
       
        // Bind wound
        bindwound_timer = new Timer(10000);
        bindwound_timer->Disable();
        bindwound_target = 0;

to

Code:

        pStandingPetOrder = SPO_Follow;

        see_invis = in_see_invis;
        see_invis_undead = in_see_invis_undead;
       
        // Bind wound
        bindwound_timer = new Timer(10000);
        bindwound_timer->Disable();
        bindwound_target = 0;

Now open zone/npc.cpp and search for the following:
Code:

          d->fixedZ,
          d->d_meele_texture1,
          d->d_meele_texture2)
{
        Mob* mob = entity_list.GetMob(name);

Replace with:
Code:

          d->fixedZ,
          d->d_meele_texture1,
          d->d_meele_texture2,
          d->see_invis,
          d->see_invis_undead
          )
{
        Mob* mob = entity_list.GetMob(name);

Open zone/client.cpp and find:
Code:

        1, // fixedz
        0, // standart text1
        0 // standart text2
        )
{
        for(int cf=0;cf<21;cf++)

Replace with:

Code:

        1, // fixedz
        0, // standart text1
        0, // standart text2
        0, // see_invis
        0 // see_invis_undead
        )
{
        for(int cf=0;cf<21;cf++)

Open zone/PlayerCorpse.cpp and search for:
Code:

// To be used on NPC death and ZoneStateLoad
Corpse::Corpse(NPC* in_npc, ItemList** in_itemlist, int32 in_npctypeid, NPCType** in_npctypedata, int32 in_decaytime)
 : Mob("Unnamed_Corpse","",0,0,in_npc->GetGender(),in_npc->GetRace(),in_npc->GetClass(),0//bodytype added
      ,in_npc->GetDeity(),in_npc->GetLevel(),in_npc->GetNPCTypeID(),0,in_npc->GetSize(),0,0,
in_npc->GetHeading(),in_npc->GetX(),in_npc->GetY(),in_npc->GetZ(),0,0,in_npc->GetTexture(),
in_npc->GetHelmTexture(),0,0,0,0,0,0,0,0,0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,1,0,0)
{

Replace with:
Code:

// To be used on NPC death and ZoneStateLoad
Corpse::Corpse(NPC* in_npc, ItemList** in_itemlist, int32 in_npctypeid, NPCType** in_npctypedata, int32 in_decaytime)
 : Mob("Unnamed_Corpse","",0,0,in_npc->GetGender(),in_npc->GetRace(),in_npc->GetClass(),0//bodytype added
      ,in_npc->GetDeity(),in_npc->GetLevel(),in_npc->GetNPCTypeID(),0,in_npc->GetSize(),0,0,
in_npc->GetHeading(),in_npc->GetX(),in_npc->GetY(),in_npc->GetZ(),0,0,in_npc->GetTexture(),
in_npc->GetHelmTexture(),0,0,0,0,0,0,0,0,0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,1,0,0,0,0)
{

This just adds two zeros at the end for the two new flags

Repeat with
Code:

// To be used on PC death
Corpse::Corpse(Client* client, PlayerProfile_Struct* pp, sint32 in_rezexp, int8 iCorpseLevel)
 : Mob("Unnamed_Corpse","",0,0,client->GetGender(),client->GetRace(),client->GetClass(), 0, // bodytype added
        client->GetDeity(),client->GetLevel(),0,0, client->GetSize(), 0, 0,client->GetHeading(),client->GetX(),client->GetY(),client->GetZ(),0,0,client->GetTexture(),
client->GetHelmTexture(),0,0,0,0,0,0,0,0,0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,1,0,0)
{

change to:
Code:

// To be used on PC death
Corpse::Corpse(Client* client, PlayerProfile_Struct* pp, sint32 in_rezexp, int8 iCorpseLevel)
 : Mob("Unnamed_Corpse","",0,0,client->GetGender(),client->GetRace(),client->GetClass(), 0, // bodytype added
        client->GetDeity(),client->GetLevel(),0,0, client->GetSize(), 0, 0,client->GetHeading(),client->GetX(),client->GetY(),client->GetZ(),0,0,client->GetTexture(),
client->GetHelmTexture(),0,0,0,0,0,0,0,0,0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,1,0,0,0,0)
{

and again ... find:
Code:

// To be called from LoadFromDBData
Corpse::Corpse(int32 in_dbid, int32 in_charid, char* in_charname, ItemList* in_itemlist, int32 in_copper, int32 in_silver, int32 in_gold, int32 in_plat, float in_x, float in_y, float in_z, float in_heading, float in_size, int8 in_gender, int16 in_race, int8 in_class, int8 in_deity, int8 in_level, int8 in_texture, int8 in_helmtexture,int32 in_rezexp)
 : Mob("Unnamed_Corpse","",0,0,in_gender, in_race, in_class, 0, in_deity, in_level,0,0, in_size, 0, 0, in_heading, in_x, in_y, in_z,0,0,in_texture,in_helmtexture,0,0,0,0,0,0,0,0,0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,1,0,0)
{

change to:
Code:

// To be called from LoadFromDBData
Corpse::Corpse(int32 in_dbid, int32 in_charid, char* in_charname, ItemList* in_itemlist, int32 in_copper, int32 in_silver, int32 in_gold, int32 in_plat, float in_x, float in_y, float in_z, float in_heading, float in_size, int8 in_gender, int16 in_race, int8 in_class, int8 in_deity, int8 in_level, int8 in_texture, int8 in_helmtexture,int32 in_rezexp)
 : Mob("Unnamed_Corpse","",0,0,in_gender, in_race, in_class, 0, in_deity, in_level,0,0, in_size, 0, 0, in_heading, in_x, in_y, in_z,0,0,in_texture,in_helmtexture,0,0,0,0,0,0,0,0,0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,1,0,0,0,0)
{

Ok, we're almost done now. Open zone/spells.cpp. Function bool Mob::SpellEffect():

Search for "case SE_InvisVsUndead"
Replace
Code:

                        case SE_InvisVsUndead: {
#ifdef SPELL_EFFECT_SPAM
                                Message(0, "Effect #%i: You cast an Invis Vs Undead spell.", i);
#endif
                                Mob *p = this->GetPet();
                                if (p)

with
Code:

                        case SE_InvisVsUndead: {
#ifdef SPELL_EFFECT_SPAM
                                Message(0, "Effect #%i: You cast an Invis Vs Undead spell.", i);
#endif
                                invisible_undead = true;
                                Mob *p = this->GetPet();
                                if (p)

In function void Mob::BuffFadeBySlot() replace
Code:

                        case SE_Invisibility: {
                                invisible = false;
                                break;
                        }

with
Code:

                        case SE_Invisibility: {
                                invisible = false;
                                break;
                        }
                        case SE_InvisVsUndead: {
                                invisible_undead = false;
                                break;
                        }

I've tested this quite a lot and it works. As I already mentioned at the beginning of this post, I might have forgotten something somewhere.

Well, that's it. It could be done in an easier way, but doing it like above makes invis/ivu very flexible.

Edit: Rewrote some lines. They weren't exactly wrong, but sometimes it wasn't clear what I meant.

Trumpcard 01-20-2004 04:53 AM

Wow... What a change !

I'll look at it tonight, but it shouldnt be too hard to merge in.

Mongrel 01-20-2004 08:40 PM

I just tested this with Shawn cvs from 01-12-04 and found an error in my post. I forgot to add something, which made the fix not working:

(Note: I've also added this to my initial post.)

-----------------------------------------

Now open zone/mob.cpp and apply the changes we just made to the constructor:
Change
Code:

                int8        in_luclinface, // and beard
                int8        in_aa_title,
                float        in_fixed_z,
                int16        in_d_meele_texture1,
                int16        in_d_meele_texture2
                )
{

to

Code:

                int8        in_luclinface, // and beard
                int8        in_aa_title,
                float        in_fixed_z,
                int16        in_d_meele_texture1,
                int16        in_d_meele_texture2,
                int8        in_see_invis,
                int8        in_see_invis_undead
                )
{

At the end of the constructor change:
Code:

        pStandingPetOrder = SPO_Follow;
       
        // Bind wound
        bindwound_timer = new Timer(10000);
        bindwound_timer->Disable();
        bindwound_target = 0;

to

Code:

        pStandingPetOrder = SPO_Follow;

        see_invis = in_see_invis;
        see_invis_undead = in_see_invis_undead;
       
        // Bind wound
        bindwound_timer = new Timer(10000);
        bindwound_timer->Disable();
        bindwound_target = 0;

-----------------------------------------

devn00b 01-20-2004 08:50 PM

btw body type (existing colum in the db) flags wether a mob is undead or not.

Mongrel 01-20-2004 10:46 PM

D'oh! Sorry.

I removed the undead flag from the code above. (Sorry Trump!)

If you already added the undead column to your DB, use the following query to remove it:

Code:

ALTER TABLE npc_types DROP COLUMN undead;

Mongrel 01-20-2004 10:48 PM

And don't tell me that there already existed a column for see invis as well. Gonna jump off the next building then.

Trumpcard 01-21-2004 12:01 AM

This is going to be a hard one to put in without diff/patch files, just because of the sheer number of changes necessary...

Mongrel 01-21-2004 01:28 AM

Wanna send me your code then? I tested it with Shawn cvs and since I already know where to put the changes, it only took me 5 mins.

Wiz 01-21-2004 01:37 AM

I just reference bodytype for undead/animal.

Trumpcard 01-21-2004 02:18 AM

I just pushed out the latest CVS code.

Pull it off sourceforge and merge it there, and send it to me.. I'll do my best to merge it (assuming nothing major gets merged between now and then)

Mongrel 01-21-2004 03:25 AM

sent you a PM


All times are GMT -4. The time now is 10:19 PM.

Powered by vBulletin®, Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.