Mongrel
01-20-2004, 04:27 AM
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):
-- 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:
-- 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:
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).
#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:
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,helmtex ture,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,aggr oradius,bodytype,npc_faction_id,face FROM npc_types");//WHERE zone='%s'", zone_name
if (RunQuery(query, strlen(query), errbuf, &result))
{
Replace it with:
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,helmtex ture,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,aggr oradius,
bodytype,npc_faction_id,face,see_invis,see_invis_u ndead 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:
tmpNPCType.luclinface=atoi(row[27]);
// set defaultvalue for aggroradius
if (tmpNPCType.aggroradius <= 0)
tmpNPCType.aggroradius = 70;
//tmpNPCType.ipc = atoi(row[27]);
to this:
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"
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:
int8 in_see_invis,
int8 in_see_invis_undead
The result should look like this:
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:
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:
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)
bool invulnerable;
bool invisible, invisible_undead, sneaking;
void Spin();
void Kill();
Replace with:
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
int8 in_luclinface, // and beard
int8 in_aa_title,
float in_fixed_z,
int16 in_d_meele_texture1,
int16 in_d_meele_texture2
)
{
to
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:
pStandingPetOrder = SPO_Follow;
// Bind wound
bindwound_timer = new Timer(10000);
bindwound_timer->Disable();
bindwound_target = 0;
to
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:
d->fixedZ,
d->d_meele_texture1,
d->d_meele_texture2)
{
Mob* mob = entity_list.GetMob(name);
Replace with:
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:
1, // fixedz
0, // standart text1
0 // standart text2
)
{
for(int cf=0;cf<21;cf++)
Replace with:
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:
// 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:
// 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
// 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:
// 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:
// 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:
// 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
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
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
case SE_Invisibility: {
invisible = false;
break;
}
with
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.
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):
-- 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:
-- 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:
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).
#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:
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,helmtex ture,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,aggr oradius,bodytype,npc_faction_id,face FROM npc_types");//WHERE zone='%s'", zone_name
if (RunQuery(query, strlen(query), errbuf, &result))
{
Replace it with:
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,helmtex ture,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,aggr oradius,
bodytype,npc_faction_id,face,see_invis,see_invis_u ndead 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:
tmpNPCType.luclinface=atoi(row[27]);
// set defaultvalue for aggroradius
if (tmpNPCType.aggroradius <= 0)
tmpNPCType.aggroradius = 70;
//tmpNPCType.ipc = atoi(row[27]);
to this:
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"
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:
int8 in_see_invis,
int8 in_see_invis_undead
The result should look like this:
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:
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:
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)
bool invulnerable;
bool invisible, invisible_undead, sneaking;
void Spin();
void Kill();
Replace with:
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
int8 in_luclinface, // and beard
int8 in_aa_title,
float in_fixed_z,
int16 in_d_meele_texture1,
int16 in_d_meele_texture2
)
{
to
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:
pStandingPetOrder = SPO_Follow;
// Bind wound
bindwound_timer = new Timer(10000);
bindwound_timer->Disable();
bindwound_target = 0;
to
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:
d->fixedZ,
d->d_meele_texture1,
d->d_meele_texture2)
{
Mob* mob = entity_list.GetMob(name);
Replace with:
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:
1, // fixedz
0, // standart text1
0 // standart text2
)
{
for(int cf=0;cf<21;cf++)
Replace with:
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:
// 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:
// 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
// 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:
// 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:
// 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:
// 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
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
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
case SE_Invisibility: {
invisible = false;
break;
}
with
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.