Page 1 of 2

new struct _ZONEINFO reemerges! (includes offset)

Posted: Fri May 16, 2003 10:49 pm
by Amadeus
First, kudos to Lax for having discovered this months ago. I saw the player/server name offset, but I don't think I would have ever put two and two together to see all of this had it not been for his work in thread: http://macroquest2.com/phpBB2/viewtopic.php?t=1782

Also, I should point out that based on Lax's notes (quoting him), "The exp modifier display using %.2f .. 0.75 is base, anything higher is bonus (0.80 would be 5% bonus, 0.85 would be 10% bonus, etc) and anything lower is a penalty (0.70 is 5% penalty, etc)."

Code: Select all

Zoneinfo=006fcaec

Code: Select all

// 5-15-2003	Amadeus (discovered by Lax)
typedef struct _ZONEINFO { 
/*0x000*/	CHAR	 CharacterName[64]; 
/*0x040*/	CHAR	 ShortName[32];
/*0x060*/	CHAR	 LongName[278];
/*0x176*/	BYTE	 Unknown0x176;	       // obsolete data?
/*0x177*/	BYTE	 Unknown0x177[11];	
/*0x182*/	WORD	 Unknown0x182;
/*0x184*/	FLOAT	Unknown0x184[4];	
/*0x194*/	FLOAT	Unknown0x194[4];	
/*0x1a4*/	FLOAT	Unknown0x1a4;		   // important(?)
/*0x1a8*/	BYTE	 Unknown0x1a8[4];		// possibly a pointer?
/*0x1ac*/	DWORD	Unknown0x1ac[15];	
/*0x1e8*/	FLOAT	ZoneExpModifier;
/*0x1ec*/	DWORD	Unknown0x1ec[3];	
/*0x1f8*/	FLOAT	Unknown0x1f8[4];	
/*0x208*/	DWORD	Unknown0x208[6];
/*0x220*/	DWORD	Unknown0x220[14];
/*0x258*/	WORD	 Unknown0x258[2];	
/*0x25c*/	DWORD	Unknown0x25c;		
/*0x260*/	BYTE	 Unknown0x260[240];	 //unused
/*0x350*/	FLOAT	Unknown0x350;
/*0x354*/	FLOAT	Unknown0x354;
// Stopping here for now, though structure possibly continues
} ZONEINFO, *PZONEINFO; 

Posted: Fri May 16, 2003 10:53 pm
by Amadeus
Eventually, I will write a function that will allow everyone to help gather data to fill in the unknowns in this function. However, here are three zones and their data....does anyone see any patterns in those unknown values in relation to those particular zones?

Code: Select all

ShortName = Misty (offset 0x40)
LongName = Misty Thicket (offset 0x60)
Unknown0x177[0] = 100 (offset 0x177)
Unknown0x177[1] = 100 (offset 0x178)
Unknown0x177[2] = 100 (offset 0x179)
Unknown0x177[3] = 100 (offset 0x17a)
Unknown0x177[4] = 120 (offset 0x17b)
Unknown0x177[5] = 120 (offset 0x17c)
Unknown0x177[6] = 120 (offset 0x17d)
Unknown0x177[7] = 120 (offset 0x17e)
Unknown0x177[8] = 50 (offset 0x17f)
Unknown0x177[9] = 50 (offset 0x180)
Unknown0x177[10] = 50 (offset 0x181)
Unknown0x182 = 50 (offset 0x182)
Unknown0x184[0] = 10.000000 (offset 0x184)
Unknown0x184[1] = 10.000000 (offset 0x188)
Unknown0x184[2] = 10.000000 (offset 0x18c)
Unknown0x184[3] = 10.000000 (offset 0x190)
Unknown0x194[0] = 500.000000 (offset 0x194)
Unknown0x194[1] = 500.000000 (offset 0x198)
Unknown0x194[2] = 500.000000 (offset 0x19c)
Unknown0x194[3] = 500.000000 (offset 0x1a0)
Unknown0x1a4 = 0.400000 (offset 0x1a4)
Unknown0x1ac[0] = 10 (offset 0x1ac)
Unknown0x1ac[1] = 0 (offset 0x1b0)
Unknown0x1ac[2] = 0 (offset 0x1b4)
Unknown0x1ac[3] = -256 (offset 0x1b8)
Unknown0x1ac[4] = -1 (offset 0x1bc)
Unknown0x1ac[5] = -1 (offset 0x1c0)
Unknown0x1ac[6] = -1 (offset 0x1c4)
Unknown0x1ac[7] = -1 (offset 0x1c8)
Unknown0x1ac[8] = -1 (offset 0x1cc)
Unknown0x1ac[9] = -1 (offset 0x1d0)
Unknown0x1ac[10] = -1 (offset 0x1d4)
Unknown0x1ac[11] = 255 (offset 0x1d8)
Unknown0x1ac[12] = 4 (offset 0x1dc)
Unknown0x1ac[13] = 2 (offset 0x1e0)
Unknown0x1ac[14] = 0 (offset 0x1e4)
[b]ZoneExpModifier = 0.750000 (offset 0x1e8)[/b]
Unknown0x1f8[0] = 585.000000 (offset 0x1f8)
Unknown0x1f8[1] = -126.000000 (offset 0x1fc)
Unknown0x1f8[2] = 450.000000 (offset 0x200)
Unknown0x1f8[3] = 550.000000 (offset 0x204)
Unknown0x208[0] = 4539 (offset 0x208)
Unknown0x208[1] = 4540 (offset 0x20c)
Unknown0x208[2] = -1 (offset 0x210)
Unknown0x208[3] = 4625 (offset 0x214)
Unknown0x208[4] = -1 (offset 0x218)
Unknown0x208[5] = -1 (offset 0x21c)
Unknown0x220[0] = 0 (offset 0x220)
Unknown0x220[1] = 1 (offset 0x224)
Unknown0x220[2] = 0 (offset 0x228)
Unknown0x220[3] = 0 (offset 0x22c)
Unknown0x220[4] = 0 (offset 0x230)
Unknown0x220[5] = 0 (offset 0x234)
Unknown0x220[6] = 0 (offset 0x238)
Unknown0x220[7] = 0 (offset 0x23c)
Unknown0x220[8] = 1 (offset 0x240)
Unknown0x220[9] = 0 (offset 0x244)
Unknown0x220[10] = 0 (offset 0x248)
Unknown0x220[11] = 1 (offset 0x24c)
Unknown0x220[12] = 0 (offset 0x250)
Unknown0x220[13] = 0 (offset 0x254)
Unknown0x258[0] = 24350 (offset 0x258)
Unknown0x258[1] = 30 (offset 0x25a)
Unknown0x25c = 0 (offset 0x25c)
Unknown0x350 = 0.000000 (offset 0x350)
Unknown0x354 = 6.000000 (offset 0x354)

Code: Select all

ShortName = Nadox (offset 0x40)
LongName = Crypt of Nadox (offset 0x60)
Unknown0x177[0] = 20 (offset 0x177)
Unknown0x177[1] = 20 (offset 0x178)
Unknown0x177[2] = 20 (offset 0x179)
Unknown0x177[3] = 20 (offset 0x17a)
Unknown0x177[4] = 20 (offset 0x17b)
Unknown0x177[5] = 20 (offset 0x17c)
Unknown0x177[6] = 20 (offset 0x17d)
Unknown0x177[7] = 20 (offset 0x17e)
Unknown0x177[8] = 40 (offset 0x17f)
Unknown0x177[9] = 40 (offset 0x180)
Unknown0x177[10] = 40 (offset 0x181)
Unknown0x182 = 40 (offset 0x182)
Unknown0x184[0] = 200.000000 (offset 0x184)
Unknown0x184[1] = 200.000000 (offset 0x188)
Unknown0x184[2] = 200.000000 (offset 0x18c)
Unknown0x184[3] = 200.000000 (offset 0x190)
Unknown0x194[0] = 600.000000 (offset 0x194)
Unknown0x194[1] = 600.000000 (offset 0x198)
Unknown0x194[2] = 600.000000 (offset 0x19c)
Unknown0x194[3] = 600.000000 (offset 0x1a0)
Unknown0x1a4 = 0.400000 (offset 0x1a4)
Unknown0x1ac[0] = 33950726 (offset 0x1ac)
Unknown0x1ac[1] = 10 (offset 0x1b0)
Unknown0x1ac[2] = 0 (offset 0x1b4)
Unknown0x1ac[3] = -256 (offset 0x1b8)
Unknown0x1ac[4] = -1 (offset 0x1bc)
Unknown0x1ac[5] = -1 (offset 0x1c0)
Unknown0x1ac[6] = -1 (offset 0x1c4)
Unknown0x1ac[7] = -1 (offset 0x1c8)
Unknown0x1ac[8] = -1 (offset 0x1cc)
Unknown0x1ac[9] = -1 (offset 0x1d0)
Unknown0x1ac[10] = -1 (offset 0x1d4)
Unknown0x1ac[11] = 255 (offset 0x1d8)
Unknown0x1ac[12] = 4 (offset 0x1dc)
Unknown0x1ac[13] = 2 (offset 0x1e0)
Unknown0x1ac[14] = 0 (offset 0x1e4)
[b]ZoneExpModifier = 0.850000 (offset 0x1e8)[/b]
Unknown0x1f8[0] = 500.000000 (offset 0x1f8)
Unknown0x1f8[1] = -300.000000 (offset 0x1fc)
Unknown0x1f8[2] = 200.000000 (offset 0x200)
Unknown0x1f8[3] = 600.000000 (offset 0x204)
Unknown0x208[0] = 88103 (offset 0x208)
Unknown0x208[1] = 88104 (offset 0x20c)
Unknown0x208[2] = 88105 (offset 0x210)
Unknown0x208[3] = 88118 (offset 0x214)
Unknown0x208[4] = 88119 (offset 0x218)
Unknown0x208[5] = 88120 (offset 0x21c)
Unknown0x220[0] = 0 (offset 0x220)
Unknown0x220[1] = 15 (offset 0x224)
Unknown0x220[2] = 0 (offset 0x228)
Unknown0x220[3] = 0 (offset 0x22c)
Unknown0x220[4] = 0 (offset 0x230)
Unknown0x220[5] = 0 (offset 0x234)
Unknown0x220[6] = 0 (offset 0x238)
Unknown0x220[7] = 0 (offset 0x23c)
Unknown0x220[8] = 1 (offset 0x240)
Unknown0x220[9] = 0 (offset 0x244)
Unknown0x220[10] = 0 (offset 0x248)
Unknown0x220[11] = 1 (offset 0x24c)
Unknown0x220[12] = 0 (offset 0x250)
Unknown0x220[13] = 0 (offset 0x254)
Unknown0x258[0] = 50536 (offset 0x258)
Unknown0x258[1] = 5 (offset 0x25a)
Unknown0x25c = 1 (offset 0x25c)
Unknown0x350 = 0.000000 (offset 0x350)
Unknown0x354 = 6.000000 (offset 0x354)

Code: Select all

ShortName = Gunthak (offset 0x40)
LongName = The Gulf of Gunthak (offset 0x60)
Unknown0x177[0] = 200 (offset 0x177)
Unknown0x177[1] = 200 (offset 0x178)
Unknown0x177[2] = 200 (offset 0x179)
Unknown0x177[3] = 200 (offset 0x17a)
Unknown0x177[4] = 200 (offset 0x17b)
Unknown0x177[5] = 200 (offset 0x17c)
Unknown0x177[6] = 200 (offset 0x17d)
Unknown0x177[7] = 200 (offset 0x17e)
Unknown0x177[8] = 200 (offset 0x17f)
Unknown0x177[9] = 200 (offset 0x180)
Unknown0x177[10] = 200 (offset 0x181)
Unknown0x182 = 200 (offset 0x182)
Unknown0x184[0] = 100.000000 (offset 0x184)
Unknown0x184[1] = 100.000000 (offset 0x188)
Unknown0x184[2] = 100.000000 (offset 0x18c)
Unknown0x184[3] = 100.000000 (offset 0x190)
Unknown0x194[0] = 600.000000 (offset 0x194)
Unknown0x194[1] = 600.000000 (offset 0x198)
Unknown0x194[2] = 600.000000 (offset 0x19c)
Unknown0x194[3] = 600.000000 (offset 0x1a0)
Unknown0x1a4 = 0.400000 (offset 0x1a4)
Unknown0x1ac[0] = 16908544 (offset 0x1ac)
Unknown0x1ac[1] = 1 (offset 0x1b0)
Unknown0x1ac[2] = 256 (offset 0x1b4)
Unknown0x1ac[3] = -256 (offset 0x1b8)
Unknown0x1ac[4] = -1 (offset 0x1bc)
Unknown0x1ac[5] = -1 (offset 0x1c0)
Unknown0x1ac[6] = -1 (offset 0x1c4)
Unknown0x1ac[7] = -1 (offset 0x1c8)
Unknown0x1ac[8] = -1 (offset 0x1cc)
Unknown0x1ac[9] = -1 (offset 0x1d0)
Unknown0x1ac[10] = -1 (offset 0x1d4)
Unknown0x1ac[11] = 255 (offset 0x1d8)
Unknown0x1ac[12] = 4 (offset 0x1dc)
Unknown0x1ac[13] = 2 (offset 0x1e0)
Unknown0x1ac[14] = 0 (offset 0x1e4)
[b]ZoneExpModifier = 0.850000 (offset 0x1e8)[/b]
Unknown0x1f8[0] = 10000.000000 (offset 0x1f8)
Unknown0x1f8[1] = -300.000000 (offset 0x1fc)
Unknown0x1f8[2] = 100.000000 (offset 0x200)
Unknown0x1f8[3] = 600.000000 (offset 0x204)
Unknown0x208[0] = 88109 (offset 0x208)
Unknown0x208[1] = 88110 (offset 0x20c)
Unknown0x208[2] = 88111 (offset 0x210)
Unknown0x208[3] = 88124 (offset 0x214)
Unknown0x208[4] = 88125 (offset 0x218)
Unknown0x208[5] = 88126 (offset 0x21c)
Unknown0x220[0] = 0 (offset 0x220)
Unknown0x220[1] = 1 (offset 0x224)
Unknown0x220[2] = 0 (offset 0x228)
Unknown0x220[3] = 0 (offset 0x22c)
Unknown0x220[4] = 0 (offset 0x230)
Unknown0x220[5] = 0 (offset 0x234)
Unknown0x220[6] = 0 (offset 0x238)
Unknown0x220[7] = 0 (offset 0x23c)
Unknown0x220[8] = 1 (offset 0x240)
Unknown0x220[9] = 0 (offset 0x244)
Unknown0x220[10] = 0 (offset 0x248)
Unknown0x220[11] = 1 (offset 0x24c)
Unknown0x220[12] = 0 (offset 0x250)
Unknown0x220[13] = 0 (offset 0x254)
Unknown0x258[0] = 5404 (offset 0x258)
Unknown0x258[1] = 68 (offset 0x25a)
Unknown0x25c = 1 (offset 0x25c)
Unknown0x350 = -10.000000 (offset 0x350)
Unknown0x354 = 6.000000 (offset 0x354)

Posted: Sat May 17, 2003 4:07 am
by anOrcPawn00
I used that struct and the info Amadeus posted about the ZEM to write a /zem command. Be warned this is my first time messing with MQ code and I only have a fairly weak command of C/C++ so if you use this code, it's at your own risk (tho it seems to work for me). Comments or corrections are very welcome as I'm trying to figure out how to help add/fix things.

Edit: Found a problem with this being called instead of /who when I do "/ all name". No clue why atm, will have to look into it, tho I suspect it could have something to do with me putting it first in szNewCommands

In EQLib.cpp:

Code: Select all

// ***************************************************************************
// Function:	DisplayZem
// Description: Displays the ZEM of the current zone to chat screen
// 2003-05-17	anOrcPawn00
// ***************************************************************************

VOID DisplayZem(VOID)

{
	float BASE_ZEM = 75.0;
	float zem = 0;
	float bonus = 0;

	if (!EQADDR_ZONEINFO) return;

	CHAR out[MAX_STRING] = {0};

	PZONEINFO ZoneInfo = EQADDR_ZONEINFO;

	if (ZoneInfo && ZoneInfo->ZoneExpModifier) {
		zem = ZoneInfo->ZoneExpModifier * 100;
		bonus = zem - BASE_ZEM;
		sprintf(out, "Zone experience modifier: %.1f%% (%.1f%% %s)", zem, (bonus<0) ? 0-bonus : bonus, (bonus<0) ? "penalty" : "bonus" );
		WriteChatBuffer(out, USERCOLOR_DEFAULT);
	}
}
In EQLib.cpp in ParseINIFile():

Code: Select all

GetPrivateProfileString("Memory Locations","Zoneinfo","0",szBuffer,MAX_STRING,ClientINI);				EQADDR_ZONEINFO = (PZONEINFO)strtoul(szBuffer,NULL,16);
In EQLib.cpp in TakeControlOfCommandList() in szNewCommands:

Code: Select all

{"/zem",		"DisplayZem"},						//2003-05-17 anOrcPawn00
In EQLib.h:

Code: Select all

PZONEINFO EQADDR_ZONEINFO = 0;							//2003-05-17 anOrcPawn00
In MQ.h:

Code: Select all

extern "C" EQLIB_API VOID	DisplayZem		(VOID);				//2003-05-17 anOrcPawn00
and with Amadeus's struct & offset added in the appropriate places.


Tho thinking about it, if .75 is the base value, wouldn't then 1.00 be actually a 33.33% bonus (1/3 more than normal) rather than a 25% bonus? Or 1.50 be a 100% bonus rather than 75% bonus?[/code]

Posted: Sun May 18, 2003 10:44 am
by Homer
I would like that /zem command, so I tried to add the sections to the appropriate files, but it couldn't compile and I don't know enough about C++ to make it work. Could you add the /zem command to the CVS please?

Amadeus: What program do you use to get those sections from memory? Then I could go in there and check zem if its not added to CVS.

Posted: Sun May 18, 2003 3:01 pm
by Amadeus
That output is created using windbg.exe and the mqext.dll that is created when you compile MQ (it's in the current CVS now).

I would hold off a bit on adding the /zem command since I might be able to figure out some more of the zone flags soon and create a more complex function that would give more information than just the ZEM.

Posted: Sun May 18, 2003 4:47 pm
by Vaft
Personally, I would rather see a $zone(zem) function instead of /zem command.. Just because eventually we'd be able to do things like $zone(shortname), etc, or whatever other interesting information can be found in the zone structure.

But nice work on the structure & command!

Posted: Mon May 19, 2003 2:13 am
by anOrcPawn00
That makes sense. I'm gonna try to figure out how $zone() is done and add $zone(zem), $zone(bonus). This could be extended with additional keywords as Amadeus decodes the rest of the fields in the struct.

Posted: Tue May 20, 2003 8:52 am
by Klandis
This ZEM should be taken with a grain of salt at least in PoP zones.
These values came up
eartha 1.4
earthb 1.4
water 1.6
storms 1.7
justice 1.4
torment 1.4
ssra 1.0
cazic 0.85
vexthal 0.85

As you can see, torment which is notoriously bad for exping gets same value as earth, which is one of the best exp zones and storms which is so-so gets highest. I believe exp bonus in pop zones, and maybe cazic, is counted on a per-mob basis as ~same level mobs can be worth differently in different parts of the zone.

This might still be relevant for old world zones, someone should check nurga droga and runnyeye. They are supposed to have a good zem, at least above the usual dungeon bonus.

Posted: Tue May 20, 2003 8:55 am
by Mckorr
Don't forget Kurn's. One of the best exp zones for lowbies.

Posted: Tue May 20, 2003 9:27 am
by eq_freak
I believe exp bonus in pop zones, and maybe cazic, is counted on a per-mob basis as ~same level mobs can be worth differently in different parts of the zone.
I have never noticed this, got any examples I could test? But now you mention it, I vaguely seem to recall an interview saying that with PoP they got the ability to increase exp pr mob(bosses). Or did I dream that up? Cant remember where it was :)

But there are also other factors to consider, for instance mobs in PoStorms hit rather hard, and they mitigate slow. So despite the superhigh ZEM, not all mobs there are good exp/effort(although I am sure that there probably are a few gems hidden there).

PS: Paludal Caverns is 160 ZEM(or 1.6 in the above format), no wonder its a popular n00b zone :)

Posted: Tue May 20, 2003 10:33 am
by Klandis
> I have never noticed this, got any examples I could test?

Most notable is in plane of fire, mobs near entrance are lvl64 and give weak exp, while the golems in 'field of gib' are level 66 and give massive amounts.
Another example in plane of justice, mobs in the trials should be worth more than same level mobs elsewhere in zone.

Posted: Tue May 20, 2003 3:07 pm
by Amadeus
Those ZEM figures look about right to me.

Posted: Tue May 20, 2003 3:17 pm
by Mckorr
Seems to me I remember reading that Runnyeye and Kurns are 18% bonus... there's a bonus for Befallen too, not that anyone spends much time there.

Posted: Wed May 21, 2003 1:52 am
by Zorg
Ever since a few months before PoP, there's been an additional exp bonus from a kill if the mob's level is close to yours. I'm not sure what the cut-off is, 5 levels below you or less I think, and the bonus increases with the relative level. So any complete function or macro to determine the exact exp given by a certain mob would have to calculate the bonus by using the mob's level and the player's level

Posted: Wed May 21, 2003 2:04 am
by Amadeus
There could be data in the spawnstruct too that gives exp bonus...who the hell would know? ;)