|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Archive::Development Archive area for Development's posts that were moved here after an inactivity period of 90 days. |
|
|
|
01-20-2004, 04:27 AM
|
Hill Giant
|
|
Join Date: Jul 2003
Location: Germany
Posts: 232
|
|
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).
Inside this #ifdef block you will find a function named bool Database:BLoadNPCTypes(). 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:BLoadNPCTypes() 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.
|
|
|
|
01-20-2004, 04:53 AM
|
Demi-God
|
|
Join Date: Jan 2002
Location: Charlotte, NC
Posts: 2,614
|
|
Wow... What a change !
I'll look at it tonight, but it shouldnt be too hard to merge in.
__________________
Quitters never win, and winners never quit, but those who never win and never quit are idiots.
|
|
|
|
01-20-2004, 08:40 PM
|
Hill Giant
|
|
Join Date: Jul 2003
Location: Germany
Posts: 232
|
|
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;
-----------------------------------------
|
|
|
|
01-20-2004, 08:50 PM
|
|
Demi-God
|
|
Join Date: Jan 2002
Posts: 15,658
|
|
btw body type (existing colum in the db) flags wether a mob is undead or not.
__________________
(Former)Senior EQEMu Developer
GuildWars Co-Founder / World Builder.
World Builder and Co-Founder Zek [PVP/Guild Wars/City Takeovers]
Member of the "I hate devn00b" Club
Most Senior EQEMu Member.
Current Work: EverQuest 2 Emulator. Zeklabs Server
|
01-20-2004, 10:46 PM
|
Hill Giant
|
|
Join Date: Jul 2003
Location: Germany
Posts: 232
|
|
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;
|
01-20-2004, 10:48 PM
|
Hill Giant
|
|
Join Date: Jul 2003
Location: Germany
Posts: 232
|
|
And don't tell me that there already existed a column for see invis as well. Gonna jump off the next building then.
|
01-21-2004, 12:01 AM
|
Demi-God
|
|
Join Date: Jan 2002
Location: Charlotte, NC
Posts: 2,614
|
|
This is going to be a hard one to put in without diff/patch files, just because of the sheer number of changes necessary...
__________________
Quitters never win, and winners never quit, but those who never win and never quit are idiots.
|
01-21-2004, 01:28 AM
|
Hill Giant
|
|
Join Date: Jul 2003
Location: Germany
Posts: 232
|
|
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.
|
01-21-2004, 01:37 AM
|
Dragon
|
|
Join Date: Feb 2002
Posts: 583
|
|
I just reference bodytype for undead/animal.
|
01-21-2004, 02:18 AM
|
Demi-God
|
|
Join Date: Jan 2002
Location: Charlotte, NC
Posts: 2,614
|
|
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)
__________________
Quitters never win, and winners never quit, but those who never win and never quit are idiots.
|
01-21-2004, 03:25 AM
|
Hill Giant
|
|
Join Date: Jul 2003
Location: Germany
Posts: 232
|
|
sent you a PM
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -4. The time now is 04:38 PM.
|
|
|
|
|
|
|
|
|
|
|
|
|