Read-only archive of the Armageddon Games Forums Archive (2000–2026) · About this archive

NPCs fail to appear after writing new values to the packfile.

21 replies · 6,769 views · Started 18 December 2016

For some reason, just adding the script types after edefSCRIPT and before edefLAST caused all of the values in the enemy editor to corrupt themselves. I'm not sure why.

Thus, instead of mucking with that table, I added an entirely new array for them/

Here's what I've done:

I added:

//zdefs.h
enum { scriptDEF1, scriptDEF2, scriptDEF3, scriptDEF4, criptDEF5, scriptDEF6, scriptDEF7, scriptDEF8, scriptDEF9, scriptDEF10, scriptDEFLAST };

in struct guydata, I added byte scriptdefense[scriptDEFLAST];

//guys.h
Likewise, I added public byte scriptdefense[scriptDEFLAST]; to the guydata struct.

//zq_class.cpp

To writeguys(), I added:


for(int j=0; j < scriptDEFLAST; j++)
{
if(!p_putc(guysbuf.scriptdefense[j],f))
{
new_return(51);
}
}

I further tried this with a return of 50, disabling the misc12 writeout, to verify that it wasn't the return value.

//ffscript
I added all the required ZScript things to the ZScript files. That part [i]does work
and writing to, and reading from n->ScripDefense[10] works flawlessly.

//guys.cpp

I added:


for(int w=0; w < scriptDEFLAST; w++)
scriptdefense[w]=d->scriptdefense[w];

inside enemy::enemy(fix X,fix Y,int Id,int Clk) : sprite()

Finally, I worked on zq_custom.cpp

I added jwin stuff, which does seem to work:

Tables stuff:
[spoiler]


static int enedata_defense3_list[] =
{
193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,-1
};

//

static TABPANEL enedata_tabs[] =
{
{ (char *)"Data 1", D_SELECTED, enedata_data_list, 0, NULL },
{ (char *)"Data 2", 0, enedata_data2_list, 0, NULL },
{ (char *)"Misc. Flags", 0, enedata_flags_list, 0, NULL },
//{ (char *)"Flags 2", 0, enedata_flags2_list, 0, NULL },
{ (char *)"Defenses 1", 0, enedata_defense_list, 0, NULL },
{ (char *)"Defenses 2", 0, enedata_defense2_list, 0, NULL },
{ (char *)"Spawn Flags", 0, enedata_flags3_list, 0, NULL },
{ (char *)"Defenses 3", 0, enedata_defense3_list, 0, NULL },
{ NULL, 0, NULL, 0, NULL }
};

//table

//193 - sccript 1
{ jwin_text_proc, 6, 51, 80, 8, vc(14), vc(1), 0, 0, 0, 0, (void *) "Script 1 Weapon Defense:", NULL, NULL },
{ jwin_text_proc, 6, 67, 80, 8, vc(14), vc(1), 0, 0, 0, 0, (void *) "Script 2 Weapon Defense:", NULL, NULL },
{ jwin_text_proc, 6, 83, 80, 8, vc(14), vc(1), 0, 0, 0, 0, (void *) "Script 3 Weapon Defense:", NULL, NULL },
{ jwin_text_proc, 6, 99, 80, 8, vc(14), vc(1), 0, 0, 0, 0, (void *) "Script 4 Weapon Defense:", NULL, NULL },
{ jwin_text_proc, 6, 115, 80, 8, vc(14), vc(1), 0, 0, 0, 0, (void *) "Script 5 Weapon Defense:", NULL, NULL },
{ jwin_text_proc, 6, 131, 80, 8, vc(14), vc(1), 0, 0, 0, 0, (void *) "Script 6 Weapon Defense:", NULL, NULL },
{ jwin_text_proc, 6, 147, 80, 8, vc(14), vc(1), 0, 0, 0, 0, (void *) "Script 7 Weapon Defense:", NULL, NULL },
{ jwin_text_proc, 6, 163, 80, 8, vc(14), vc(1), 0, 0, 0, 0, (void *) "Script 8 Weapon Defense:", NULL, NULL },
{ jwin_text_proc, 6, 179, 80, 8, vc(14), vc(1), 0, 0, 0, 0, (void *) "Script 9 Weapon Defense:", NULL, NULL },
{ jwin_text_proc, 6, 196, 80, 8, vc(14), vc(1), 0, 0, 0, 0, (void *) "Script 10 Weapon Defense:", NULL, NULL },
//203 script 1 pulldown
{ jwin_droplist_proc, 126, 51-4, 115, 16, jwin_pal[jcTEXTFG], jwin_pal[jcTEXTBG], 0, 0, 0, 0, (void *) &defense_list, NULL, NULL },
{ jwin_droplist_proc, 126, 67-4, 115, 16, jwin_pal[jcTEXTFG], jwin_pal[jcTEXTBG], 0, 0, 0, 0, (void *) &defense_list, NULL, NULL },
{ jwin_droplist_proc, 126, 83-4, 115, 16, jwin_pal[jcTEXTFG], jwin_pal[jcTEXTBG], 0, 0, 0, 0, (void *) &defense_list, NULL, NULL },
{ jwin_droplist_proc, 126, 99-4, 115, 16, jwin_pal[jcTEXTFG], jwin_pal[jcTEXTBG], 0, 0, 0, 0, (void *) &defense_list, NULL, NULL },
{ jwin_droplist_proc, 126, 115-4, 115, 16, jwin_pal[jcTEXTFG], jwin_pal[jcTEXTBG], 0, 0, 0, 0, (void *) &defense_list, NULL, NULL },
{ jwin_droplist_proc, 126, 131-4, 115, 16, jwin_pal[jcTEXTFG], jwin_pal[jcTEXTBG], 0, 0, 0, 0, (void *) &defense_list, NULL, NULL },
{ jwin_droplist_proc, 126, 147-4, 115, 16, jwin_pal[jcTEXTFG], jwin_pal[jcTEXTBG], 0, 0, 0, 0, (void *) &defense_list, NULL, NULL },
{ jwin_droplist_proc, 126, 163-4, 115, 16, jwin_pal[jcTEXTFG], jwin_pal[jcTEXTBG], 0, 0, 0, 0, (void *) &defense_list, NULL, NULL },
{ jwin_droplist_proc, 126, 179-4, 115, 16, jwin_pal[jcTEXTFG], jwin_pal[jcTEXTBG], 0, 0, 0, 0, (void *) &defense_list, NULL, NULL },
{ jwin_droplist_proc, 126, 196-4, 115, 16, jwin_pal[jcTEXTFG], jwin_pal[jcTEXTBG], 0, 0, 0, 0, (void *) &defense_list, NULL, NULL },


{ NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
};


[/spoiler]

..and in the edit_enemyedit() function:

[spoiler]

//Read in the enemy deences to the editor.
for(int j=0; j <= edefBYRNA; j++)
{
enedata_dlg[j+161].d1 = guysbuf[index].defense[j];
}

enedata_dlg[192].d1 = guysbuf[index].defense[edefSCRIPT];

enedata_dlg[203].d1 = guysbuf[index].scriptdefense[scriptDEF1];
enedata_dlg[204].d1 = guysbuf[index].scriptdefense[scriptDEF2];
enedata_dlg[205].d1 = guysbuf[index].scriptdefense[scriptDEF3];
enedata_dlg[206].d1 = guysbuf[index].scriptdefense[scriptDEF4];
enedata_dlg[207].d1 = guysbuf[index].scriptdefense[scriptDEF5];
enedata_dlg[208].d1 = guysbuf[index].scriptdefense[scriptDEF6];
enedata_dlg[209].d1 = guysbuf[index].scriptdefense[scriptDEF7];
enedata_dlg[210].d1 = guysbuf[index].scriptdefense[scriptDEF8];
enedata_dlg[211].d1 = guysbuf[index].scriptdefense[scriptDEF9];
enedata_dlg[212].d1 = guysbuf[index].scriptdefense[scriptDEF10];

///

//Read in the enemy deences to the editor.
for(int j=0; j <= edefBYRNA; j++)
{
enedata_dlg[j+161].d1 = guysbuf[index].defense[j];
}

enedata_dlg[192].d1 = guysbuf[index].defense[edefSCRIPT];

enedata_dlg[203].d1 = guysbuf[index].scriptdefense[scriptDEF1];
enedata_dlg[204].d1 = guysbuf[index].scriptdefense[scriptDEF2];
enedata_dlg[205].d1 = guysbuf[index].scriptdefense[scriptDEF3];
enedata_dlg[206].d1 = guysbuf[index].scriptdefense[scriptDEF4];
enedata_dlg[207].d1 = guysbuf[index].scriptdefense[scriptDEF5];
enedata_dlg[208].d1 = guysbuf[index].scriptdefense[scriptDEF6];
enedata_dlg[209].d1 = guysbuf[index].scriptdefense[scriptDEF7];
enedata_dlg[210].d1 = guysbuf[index].scriptdefense[scriptDEF8];
enedata_dlg[211].d1 = guysbuf[index].scriptdefense[scriptDEF9];
enedata_dlg[212].d1 = guysbuf[index].scriptdefense[scriptDEF10];

///

//Write enemy defences to the test buffer.
for(int j=0; j <= edefBYRNA; j++)
{
test.defense[j] = enedata_dlg[j+161].d1;
}

test.defense[edefSCRIPT] = enedata_dlg[192].d1;

//test.scriptdefense[scriptDEF1] = enedata_dlg[203].d1;
test.scriptdefense[scriptDEF2] = enedata_dlg[204].d1;
test.scriptdefense[scriptDEF3] = enedata_dlg[205].d1;
test.scriptdefense[scriptDEF4] = enedata_dlg[206].d1;
test.scriptdefense[scriptDEF5] = enedata_dlg[207].d1;
test.scriptdefense[scriptDEF6] = enedata_dlg[208].d1;
test.scriptdefense[scriptDEF7] = enedata_dlg[209].d1;
test.scriptdefense[scriptDEF8] = enedata_dlg[210].d1;
test.scriptdefense[scriptDEF9] = enedata_dlg[211].d1;
//test.scriptdefense[scriptDEF10] = enedata_dlg[212].d1;


[/spoiler]

What did I miss here?

I do not see anything that should prevent an npc from spawning out of these mods...?!

Yet...somehow when writing the data out to the pack file, all of the npc data is corrupted. Edit an enemy, and load a quest where it has been edited, saved, and reopened, and look at the npc tables.

In the test quest, if you click on the screen to freeze it, you can briefly see that ZC is trying to create an npc object, but can't. It does not return as a valid NPC, meaning that Screen->LoadNPC(1) returns invalid, and it never moves.

Source files, binaries, and a test quest.

If I disable the write-out (zq_class.cpp) though, and I otherwise edit an npc and save, it works as normal.

???

Saffith wrote:You changed the saving code, but not the loading code. That's not going to go well.

Fair enough...and where, in what file, is that located?

I was trying to figure out earlier if this was stored in a quest header definition, but I couldn't, and I still cannot find it?!

Edit: Oh, I see. qst.cpp

Do I need to do more than this:


if(guyversion >= 22)
{
if(!p_igetl(&(tempguy.misc11),f,keepdata))
{
return qe_invalid;
}

if(!p_igetl(&(tempguy.misc12),f,keepdata))
{
return qe_invalid;
}

for(int j=0; j<scriptDEFLAST; j++)
{
if(!p_getc(&(tempguy.scriptdefense[j]),f,keepdata))
{
return qe_invalid;
}
}
}

I also need to know what defines the 'guyversion' input, so that I can add a new minversion; but I guess I'll find out if this works first.

Well, that clearly isn't sufficient. I missed something else, as now I have junk data everywhere. Any ideas?

How sensitive are the guydata class and struct, regarding insertion points? I inserted scriptdefense[] at the end of the public decs, in the class (guys.h); and as the very last entry in the strucct in zdefs.h. I can't see this causing data corruption on this scale.

Oh, sweet dear little baby infant Jesus.....

Please, please, pleeeease, be extremely careful when changing packfile formats. Even I go into "serious mode" when doing anything with that file.

Gleeok wrote:Oh, sweet dear little baby infant Jesus.....

Please, please, pleeeease, be extremely careful when changing packfile formats. Even I go into "serious mode" when doing anything with that file.

it would be extremely helpful to know what in the world adding one variable is doing that is causing such massive corruption. Hell, why did expanding one enum do the same blasted thing?

Obviously I wouldn't retain anything for a release that is horribly broken, nor commit it to a main, but holy flidd, look at this nonsense:

http://timelord.insomnia247.nl/zc/zc_dev/ZC_2.54_Sources_Beta_29.zip <-- Code and binaries.

All I did was add in a tiny bit of code to read in, and write out script defs. It would be very nice to be able to set them from the enemy editor, and I know of no other way to do it. What exactly is it that I'm doing wrongly here?

When I increased the enum for the weapon defense types--which by its very nature, expanded the sizes of the arrays, and the functions that called and wrote to them--it did something very similar. All the values were corrupted, and things went bloody otherworldly.

How does one properly expand these things without the universe imploding?

All of my changes to the files associated with this are in that archive. Care to review?

This is driving me bonkers. Adding the array is easy. Adding entries to the editor is easy. Hell, I could even add in the weapon checks, and these values could be set up by script. ... but people want to use the enemy editor, and despite --AFAIK-- doing everything properly, it's going bonkers. I have no idea if I would ever need to go into this again, but if I don't, someone will want to do it, and we really need to know what's going on.

I'm certainly open to any 'better way' of handling it.

Should I just make an array in zdefs with byte scriptdefs[npcMax][defSCRIPTMAX] and write all the values to that? Wouldn't I need to save that out just the same?

Can you post just the code you changed in ZC (Not ZQuest; and not any script, ffc, or ZScript code)? I'll take a look.

If you comment out everything you added to save/load guys does the enemy data still get corrupted?

Gleeok wrote:Can you post just the code you changed in ZC (Not ZQuest; and not any script, ffc, or ZScript code)? I'll take a look.

If you comment out everything you added to save/load guys does the enemy data still get corrupted?

No, if I comment it out, then everything works. Setting the defence values by script works like a champ, too.

I'll post the relevant sections here, and I'll upload the ZIP.

zdefs.cpp
[spoiler]


enum
{
scriptDEF1, scriptDEF2, scriptDEF3, scriptDEF4, scriptDEF5, scriptDEF6, scriptDEF7,
scriptDEF8, scriptDEF9, scriptDEF10, scriptDEFLAST
};

struct guydata
{
dword flags;
dword flags2;
word tile;
byte width;
byte height; //0=striped, 1+=rectangular
word s_tile; //secondary (additional) tile(s)
byte s_width;
byte s_height; //0=striped, 1+=rectangular
word e_tile;
byte e_width;
byte e_height;

short hp;

short family, cset, anim, e_anim, frate, e_frate;
short dp, wdp, weapon;

short rate, hrate, step, homing, grumble, item_set;
long misc1, misc2, misc3, misc4, misc5, misc6, misc7, misc8, misc9, misc10, misc11, misc12, misc13, misc14, misc15;
short bgsfx, bosspal, extend;
byte defense[edefLAST];

// short startx, starty;
// short foo1,foo2,foo3,foo4,foo5,foo6;
byte hitsfx, deadsfx;
byte scriptdefense[scriptDEFLAST];
};

[/spoiler]

Guys.cpp
[spoiler]

class enemy : public sprite
{
public:
guydata *d;
// Approximately all of these variables are accessed by either ffscript.cpp or inherited classes
int o_tile, frate, hp, hclk, clk3, stunclk, timer, fading, superman, mainguy, did_armos;
byte movestatus, item_set, grumble, posframe;
bool itemguy, count_enemy, dying, ceiling, leader, scored, script_spawned;
fix step, floor_y;

//d variables
dword flags;
dword flags2;

short family, dcset, anim;
short dp, wdp, wpn;

short rate, hrate, homing;
fix dstep;
long dmisc1, dmisc2, dmisc3, dmisc4, dmisc5, dmisc6, dmisc7, dmisc8, dmisc9, dmisc10, dmisc11, dmisc12, dmisc13, dmisc14, dmisc15;
short bgsfx, bosspal;
byte defense[edefLAST];

byte hitsfx,deadsfx;

fix getX();
fix getY();
int getID();
enemy(fix X,fix Y,int Id,int Clk); // : sprite()
virtual ~enemy();

// Supplemental animation code that all derived classes should call
// as a return value for animate().
// Handles the death animation and returns true when enemy is finished.
virtual bool Dead(int index);
// Basic animation code that all derived classes should call.
// The one with an index is the one that is called by
// the guys sprite list; index is the enemy's index in the list.
virtual bool animate(int index);

// auomatically kill off enemy (for rooms with ringleaders)
virtual void kickbucket();
// Stop BG SFX only if no other enemy is playing it
void stop_bgsfx(int index);
// Take damage or ignore it
virtual int takehit(weapon *w);
// override hit detection to check for invicibility, stunned, etc
virtual bool hit(sprite *s);
virtual bool hit(int tx,int ty,int tz,int txsz,int tysz,int tzsz);
virtual bool hit(weapon *w);
virtual void break_shield() {}; // Overridden by types that can have shields
virtual bool ignore_msg_freeze()
{
return false;
}
byte scriptdefense[scriptDEFLAST];

protected:
int clk2,sclk;
int starting_hp;
int ox, oy;
word s_tile; //secondary (additional) tile(s)

// to allow for different sfx on defeating enemy
virtual void death_sfx();
virtual void move(fix dx,fix dy);
virtual void removearmos(int ax,int ay);
virtual void move(fix s);
void leave_item();

// take damage or ignore it
virtual bool hitshield(int wpnx, int wpny, int xdir);
virtual int defend(int wpnId, int *power, int edef);
virtual int scriptdefend(int wpnId, int *power, int edef);
bool candamage(int power, int edef);
bool scriptcandamage(int power, int edef);
int defenditemclass(int wpnId, int *power);

bool dont_draw();
// base drawing function to be used by all derived classes instead of
// sprite::draw()
virtual void draw(BITMAP *dest);
// similar to the overblock function--can do up to a 32x32 sprite
void drawblock(BITMAP *dest,int mask);
virtual void drawshadow(BITMAP *dest, bool translucent);
void masked_draw(BITMAP *dest,int mx,int my,int mw,int mh);

// --==**==--
// Movement routines that can be used by derived classes as needed
// --==**==--
void fix_coords(bool bound=false);
// returns true if next step is ok, false if there is something there
bool canmove(int ndir,fix s,int special,int dx1,int dy1,int dx2,int dy2);
bool canmove(int ndir,fix s,int special);
bool canmove(int ndir,int special);
bool canmove(int ndir);
// 8-directional
void newdir_8(int rate,int homing, int special,int dx1,int dy1,int dx2,int dy2);
void newdir_8(int rate,int homing, int special);
// makes the enemy slide backwards when hit
// sclk: first byte is clk, second byte is dir
bool slide();
bool can_slide();
bool fslide();
// changes enemy's direction, checking restrictions
// rate: 0 = no random changes, 16 = always random change
// homing: 0 = none, 256 = always
// grumble 0 = none, 4 = strongest appetite
void newdir(int rate,int homing,int special);
void newdir();
fix distance_left();
// keeps walking around
void constant_walk(int rate,int homing,int special);
void constant_walk();
// falls through the Z axis;
void falldown();
int pos(int x,int y);
// for variable step rates
void variable_walk(int rate,int homing,int special);
// pauses for a while after it makes a complete move (to a new square)
void halting_walk(int rate,int homing,int special,int hrate, int haltcnt);
// 8-directional movement, aligns to 8 pixels
void constant_walk_8(int rate,int homing,int special);
// 8-directional movement, halting
void halting_walk_8(int newrate,int newhoming, int newclk,int special,int newhrate, int haltcnt);
// 8-directional movement, no alignment
void variable_walk_8(int rate,int homing,int newclk,int special);
// same as above but with variable enemy size
void variable_walk_8(int rate,int homing,int newclk,int special,int dx1,int dy1,int dx2,int dy2);
// the variable speed floater movement
// ms is max speed
// ss is step speed
// s is step count
// p is pause count
// g is graduality 😊
void floater_walk(int rate,int newclk,fix ms,fix ss,int s,int p, int g);
void floater_walk(int rate,int newclk,fix s);
// Checks if enemy is lined up with Link. If so, returns direction Link is
// at as compared to enemy. Returns -1 if not lined up. Range is inclusive.
int lined_up(int range, bool dir8);
// returns true if Link is within 'range' pixels of the enemy
bool LinkInRange(int range);
// Breathe fire
void FireBreath(bool seeklink);
// Shoot weapons
void FireWeapon();
// place the enemy in line with Link (red wizzrobes)
void place_on_axis(bool floater, bool solid_ok);
void update_enemy_frame();
void n_frame_n_dir(int frames, int dir, int f4);
void tiledir_small(int ndir, bool fourdir);
void tiledir_three(int ndir);
void tiledir(int ndir, bool fourdir);
void tiledir_big(int ndir, bool fourdir);
// Enemies that cannot ever be penetrated by weapons
bool cannotpenetrate();

private:
bool shieldCanBlock;
};

[/spoiler]

zq_class.cpp
[spoiler]

int writeguys(PACKFILE *f, zquestheader *Header)
{
//these are here to bypass compiler warnings about unused arguments
Header=Header;

dword section_id=ID_GUYS;
dword section_version=V_GUYS;
dword section_cversion=CV_GUYS;
dword section_size=0;

//section id
if(!p_mputl(section_id,f))
{
new_return(1);
}

//section version info
if(!p_iputw(section_version,f))
{
new_return(2);
}

if(!p_iputw(section_cversion,f))
{
new_return(3);
}

for(int writecycle=0; writecycle<2; ++writecycle)
{
fake_pack_writing=(writecycle==0);

//section size
if(!p_iputl(section_size,f))
{
new_return(4);
}

writesize=0;

//finally... section data
for(int i=0; i<MAXGUYS; i++)
{
if(!pfwrite((char *)guy_string[i], 64, f))
{
new_return(5);
}
}

for(int i=0; i<MAXGUYS; i++)
{
if(!p_iputl(guysbuf[i].flags,f))
{
new_return(6);
}

if(!p_iputl(guysbuf[i].flags2,f))
{
new_return(7);
}

if(!p_iputw(guysbuf[i].tile,f))
{
new_return(8);
}

if(!p_putc(guysbuf[i].width,f))
{
new_return(9);
}

if(!p_putc(guysbuf[i].height,f))
{
new_return(10);
}

if(!p_iputw(guysbuf[i].s_tile,f))
{
new_return(11);
}

if(!p_putc(guysbuf[i].s_width,f))
{
new_return(12);
}

if(!p_putc(guysbuf[i].s_height,f))
{
new_return(13);
}

if(!p_iputw(guysbuf[i].e_tile,f))
{
new_return(14);
}

if(!p_putc(guysbuf[i].e_width,f))
{
new_return(15);
}

if(!p_putc(guysbuf[i].e_height,f))
{
new_return(16);
}

if(!p_iputw(guysbuf[i].hp,f))
{
new_return(17);
}

if(!p_iputw(guysbuf[i].family,f))
{
new_return(18);
}

if(!p_iputw(guysbuf[i].cset,f))
{
new_return(19);
}

if(!p_iputw(guysbuf[i].anim,f))
{
new_return(20);
}

if(!p_iputw(guysbuf[i].e_anim,f))
{
new_return(21);
}

if(!p_iputw(guysbuf[i].frate,f))
{
new_return(22);
}

if(!p_iputw(guysbuf[i].e_frate,f))
{
new_return(23);
}

if(!p_iputw(guysbuf[i].dp,f))
{
new_return(24);
}

if(!p_iputw(guysbuf[i].wdp,f))
{
new_return(25);
}

if(!p_iputw(guysbuf[i].weapon,f))
{
new_return(26);
}

if(!p_iputw(guysbuf[i].rate,f))
{
new_return(27);
}

if(!p_iputw(guysbuf[i].hrate,f))
{
new_return(28);
}

if(!p_iputw(guysbuf[i].step,f))
{
new_return(29);
}

if(!p_iputw(guysbuf[i].homing,f))
{
new_return(30);
}

if(!p_iputw(guysbuf[i].grumble,f))
{
new_return(31);
}

if(!p_iputw(guysbuf[i].item_set,f))
{
new_return(32);
}

if(!p_iputl(guysbuf[i].misc1,f))
{
new_return(33);
}

if(!p_iputl(guysbuf[i].misc2,f))
{
new_return(34);
}

if(!p_iputl(guysbuf[i].misc3,f))
{
new_return(35);
}

if(!p_iputl(guysbuf[i].misc4,f))
{
new_return(36);
}

if(!p_iputl(guysbuf[i].misc5,f))
{
new_return(37);
}

if(!p_iputl(guysbuf[i].misc6,f))
{
new_return(38);
}

if(!p_iputl(guysbuf[i].misc7,f))
{
new_return(39);
}

if(!p_iputl(guysbuf[i].misc8,f))
{
new_return(40);
}

if(!p_iputl(guysbuf[i].misc9,f))
{
new_return(41);
}

if(!p_iputl(guysbuf[i].misc10,f))
{
new_return(42);
}

if(!p_iputw(guysbuf[i].bgsfx,f))
{
new_return(43);
}

if(!p_iputw(guysbuf[i].bosspal,f))
{
new_return(44);
}

if(!p_iputw(guysbuf[i].extend,f))
{
new_return(45);
}

for(int j=0; j < edefLAST; j++)
{
// if ( j < scriptDEFLAST ) {
// if(!p_putc(guysbuf[i].scriptdefense[j],f))
// {
// Z_message("Doing script defs\n"😉;
// new_return(46);
// }

// }
if(!p_putc(guysbuf[i].defense[j],f))
{
new_return(46);
}
}

if(!p_putc(guysbuf[i].hitsfx,f))
{
new_return(47);
}

if(!p_putc(guysbuf[i].deadsfx,f))
{
new_return(48);
}

if(!p_iputl(guysbuf[i].misc11,f))
{
new_return(49);
}
/*
for(int j=0; j < scriptDEFLAST; j++)
{
if(!p_putc(guysbuf[i].scriptdefense[j],f))
{
new_return(50);
}
}
*/
//dISABLING THIS TO BORROW ITS RETURN FOR A TEST -!ZoriaRPG

if(!p_iputl(guysbuf[i].misc12,f))
{
new_return(50);
}


//The stopped npcs from spawning!?
/*
for(int j=0; j < scriptDEFLAST; j++)
{
if(!p_putc(guysbuf[i].scriptdefense[j],f))
{
new_return(51);
}
}
*/
}

if(writecycle==0)
{
section_size=writesize;
}
}

if(writesize!=int(section_size) && save_warn)
{
char ebuf[80];
sprintf(ebuf, "%d != %d", writesize, int(section_size));
jwin_alert("Error: writeguys()","writesize != section_size",ebuf,NULL,"O&K",NULL,'k',0,lfont);
}

new_return(0);
}

[/spoiler]

...continued...

qst.cpp
[spoiler]

int readguys(PACKFILE *f, zquestheader *Header, bool keepdata)
{
dword dummy;
word dummy2;
word guyversion=0;

if(Header->zelda_version >= 0x193)
{
//section version info
if(!p_igetw(&guyversion,f,true))
{
return qe_invalid;
}

//al_trace("Guys version %d\n", guyversion);
if(!p_igetw(&dummy2,f,true))
{
return qe_invalid;
}

//section size
if(!p_igetl(&dummy,f,true))
{
return qe_invalid;
}
}

if(guyversion > 3)
{
for(int i=0; i<MAXGUYS; i++)
{
char tempname[64];

// rev. 1511 : guyversion = 23. upped to 512 editable enemies. -Gleeok
// if guyversion < 23 then there is only 256 enemies in the packfile, so default the rest.
if(guyversion < 23 && i >= OLDBETAMAXGUYS && keepdata)
{
memset(tempname, 0, sizeof(char)*64);
sprintf(tempname, "e%03d", i);
strcpy(guy_string[i], tempname);

continue;
}

if(!pfread(tempname, 64, f, keepdata))
{
return qe_invalid;
}

// Don't retain names of uneditable enemy entries!
if(keepdata)
{
// for version upgrade to 2.5
if(guyversion < 23 && i >= 177)
{
// some of the older builds have names such as 'zz123',
// (this order gets messed up with some eXXX and some zzXXX)
// so let's update to the newer naming convection. -Gleeok
char tmpbuf[64];
memset(tmpbuf, 0, sizeof(char)*64);
sprintf(tmpbuf, "zz%03d", i);

if(memcmp(tempname, tmpbuf, size_t(5)) == 0)
{
memset(tempname, 0, sizeof(char)*64);
sprintf(tempname, "e%03d", i);
}
}

if(i >= OLDMAXGUYS || strlen(tempname)<1 || tempname[strlen(tempname)-1]!=' '😉
{
strcpy(guy_string[i], tempname);
}
else
{
strcpy(guy_string[i],old_guy_string[i]);
}
}
}
}
else
{
if(keepdata)
{
for(int i=0; i<eMAXGUYS; i++)
{
sprintf(guy_string[i],"zz%03d",i);
}

for(int i=0; i<OLDMAXGUYS; i++)
{
strcpy(guy_string[i],old_guy_string[i]);
}
}
}


//finally... section data
if(keepdata)
{
init_guys(guyversion); //using default data for now...

// Goriya guy fix
if((Header->zelda_version < 0x211)||((Header->zelda_version == 0x211)&&(Header->build<7)))
{
if(get_bit(quest_rules,qr_NEWENEMYTILES))
{
guysbuf[gGORIYA].tile=130;
guysbuf[gGORIYA].e_tile=130;
}
}
}

if(Header->zelda_version < 0x193)
{
if(get_bit(deprecated_rules,46))
{
guysbuf[eDODONGO].cset=14;
guysbuf[eDODONGO].bosspal=spDIG;
}
}

// Not sure when this first changed, but it's necessary for 2.10, at least
if(Header->zelda_version <= 0x210)
{
guysbuf[eGLEEOK1F].misc6 = 16;
guysbuf[eGLEEOK2F].misc6 = 16;
guysbuf[eGLEEOK3F].misc6 = 16;
guysbuf[eGLEEOK4F].misc6 = 16;

guysbuf[eWIZ1].misc4 = 1;
guysbuf[eBATROBE].misc4 = 1;
guysbuf[eSUMMONER].misc4 = 1;
guysbuf[eWWIZ].misc4 = 1;
}

// The versions here may not be correct
// zelda_version>=0x211 handled at guyversion<24
if(Header->zelda_version <= 0x190)
{
guysbuf[eCENT1].misc3 = 0;
guysbuf[eCENT2].misc3 = 0;
guysbuf[eMOLDORM].misc2 = 0;
}
else if(Header->zelda_version <= 0x210)
{
guysbuf[eCENT1].misc3 = 1;
guysbuf[eCENT2].misc3 = 1;
guysbuf[eMOLDORM].misc2 = 0;
}

if(guyversion<=2)
{
return readlinksprites2(f, guyversion==2?0:-1, 0, keepdata);
}

if(guyversion > 3)
{
guydata tempguy;

for(int i=0; i<MAXGUYS; i++)
{
if(guyversion < 23 && keepdata) // May 2012 : 512 max enemies
{
if(i >= OLDBETAMAXGUYS)
{
memset(&guysbuf[i], 0, sizeof(guydata));
continue;
}
}

memset(&tempguy, 0, sizeof(guydata));

if(!p_igetl(&(tempguy.flags),f,keepdata))
{
return qe_invalid;
}

if(!p_igetl(&(tempguy.flags2),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.tile),f,keepdata))
{
return qe_invalid;
}

if(!p_getc(&(tempguy.width),f,keepdata))
{
return qe_invalid;
}

if(!p_getc(&(tempguy.height),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.s_tile),f,keepdata))
{
return qe_invalid;
}

if(!p_getc(&(tempguy.s_width),f,keepdata))
{
return qe_invalid;
}

if(!p_getc(&(tempguy.s_height),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.e_tile),f,keepdata))
{
return qe_invalid;
}

if(!p_getc(&(tempguy.e_width),f,keepdata))
{
return qe_invalid;
}

if(!p_getc(&(tempguy.e_height),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.hp),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.family),f,keepdata))
{
return qe_invalid;
}

if(guyversion < 9 && (i==eDKNUT1 || i==eDKNUT2 || i==eDKNUT3 || i==eDKNUT4 || i==eDKNUT5)) // Whoops, forgot about Darknuts...
{
if(get_bit(quest_rules,qr_NEWENEMYTILES))
{
tempguy.s_tile=tempguy.e_tile+120;
tempguy.s_width=tempguy.e_width;
tempguy.s_height=tempguy.e_height;
}
else tempguy.s_tile=860;
}

if(!p_igetw(&(tempguy.cset),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.anim),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.e_anim),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.frate),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.e_frate),f,keepdata))
{
return qe_invalid;
}

if(guyversion < 13) // April 2009
{
if(get_bit(deprecated_rules, qr_SLOWENEMYANIM_DEP))
{
tempguy.frate *= 2;
tempguy.e_frate *= 2;
}
}

if(guyversion < 14) // May 1 2009
{
if(tempguy.anim==a2FRMSLOW)
{
tempguy.anim=a2FRM;
tempguy.frate *= 2;
}

if(tempguy.e_anim==a2FRMSLOW)
{
tempguy.e_anim=a2FRM;
tempguy.e_frate *= 2;
}

if(tempguy.anim==aFLIPSLOW)
{
tempguy.anim=aFLIP;
tempguy.frate *= 2;
}

if(tempguy.e_anim==aFLIPSLOW)
{
tempguy.e_anim=aFLIP;
tempguy.e_frate *= 2;
}

if(tempguy.anim == aNEWDWALK) tempguy.anim = a4FRM4DIR;

if(tempguy.e_anim == aNEWDWALK) tempguy.e_anim = a4FRM4DIR;

if(tempguy.anim == aNEWPOLV || tempguy.anim == a4FRM3TRAP)
{
tempguy.anim=a4FRM4DIR;
tempguy.s_tile=(get_bit(quest_rules,qr_NEWENEMYTILES) ? tempguy.e_tile : tempguy.tile)+20;
}

if(tempguy.e_anim == aNEWPOLV || tempguy.e_anim == a4FRM3TRAP)
{
tempguy.e_anim=a4FRM4DIR;
tempguy.s_tile=(get_bit(quest_rules,qr_NEWENEMYTILES) ? tempguy.e_tile : tempguy.tile)+20;
}
}

if(!p_igetw(&(tempguy.dp),f,keepdata))
{
return qe_invalid;
}

//correction for guy fire
if(guyversion < 6)
{
if(i == gFIRE)
tempguy.dp = 2;
}

if(!p_igetw(&(tempguy.wdp),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.weapon),f,keepdata))
{
return qe_invalid;
}

//correction for bosses using triple, "rising" fireballs
if(guyversion < 5)
{
if(i == eLAQUAM || i == eRAQUAM || i == eGOHMA1 || i == eGOHMA2 ||
i == eGOHMA3 || i == eGOHMA4)
{
if(tempguy.weapon == ewFireball)
tempguy.weapon = ewFireball2;
}
}

if(!p_igetw(&(tempguy.rate),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.hrate),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.step),f,keepdata))
{
return qe_invalid;
}

// HIGHLY UNORTHODOX UPDATING THING, part 2
if(fixpolsvoice && tempguy.family==eePOLSV)
{
tempguy.step /= 2;
}

if(!p_igetw(&(tempguy.homing),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.grumble),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.item_set),f,keepdata))
{
return qe_invalid;
}

if(guyversion>=22) // Version 22: Expand misc attributes to 32 bits
{
if(!p_igetl(&(tempguy.misc1),f,keepdata))
{
return qe_invalid;
}

if(!p_igetl(&(tempguy.misc2),f,keepdata))
{
return qe_invalid;
}

if(!p_igetl(&(tempguy.misc3),f,keepdata))
{
return qe_invalid;
}

if(!p_igetl(&(tempguy.misc4),f,keepdata))
{
return qe_invalid;
}

if(!p_igetl(&(tempguy.misc5),f,keepdata))
{
return qe_invalid;
}

if(!p_igetl(&(tempguy.misc6),f,keepdata))
{
return qe_invalid;
}

if(!p_igetl(&(tempguy.misc7),f,keepdata))
{
return qe_invalid;
}

if(!p_igetl(&(tempguy.misc8),f,keepdata))
{
return qe_invalid;
}

if(!p_igetl(&(tempguy.misc9),f,keepdata))
{
return qe_invalid;
}

if(!p_igetl(&(tempguy.misc10),f,keepdata))
{
return qe_invalid;
}
}
else
{
short tempMisc;

if(!p_igetw(&tempMisc,f,keepdata))
{
return qe_invalid;
}

tempguy.misc1=tempMisc;

if(!p_igetw(&tempMisc,f,keepdata))
{
return qe_invalid;
}

tempguy.misc2=tempMisc;

if(!p_igetw(&tempMisc,f,keepdata))
{
return qe_invalid;
}

tempguy.misc3=tempMisc;

if(!p_igetw(&tempMisc,f,keepdata))
{
return qe_invalid;
}

tempguy.misc4=tempMisc;

if(!p_igetw(&tempMisc,f,keepdata))
{
return qe_invalid;
}

tempguy.misc5=tempMisc;

if(guyversion < 13) // April 2009 - a tiny Wizzrobe update
{
if(tempguy.family == eeWIZZ && !(tempguy.misc1))
tempguy.misc5 = 74;
}

if(!p_igetw(&tempMisc,f,keepdata))
{
return qe_invalid;
}

tempguy.misc6=tempMisc;

if(!p_igetw(&tempMisc,f,keepdata))
{
return qe_invalid;
}

tempguy.misc7=tempMisc;

if(!p_igetw(&tempMisc,f,keepdata))
{
return qe_invalid;
}

tempguy.misc8=tempMisc;

if(!p_igetw(&tempMisc,f,keepdata))
{
return qe_invalid;
}

tempguy.misc9=tempMisc;

if(!p_igetw(&tempMisc,f,keepdata))
{
return qe_invalid;
}

tempguy.misc10=tempMisc;
}

if(!p_igetw(&(tempguy.bgsfx),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.bosspal),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.extend),f,keepdata))
{
return qe_invalid;
}

if(guyversion >= 16) // November 2009 - Super Enemy Editor
{
for(int j=0; j<edefLAST; j++)
{
if(!p_getc(&(tempguy.defense[j]),f,keepdata))
{
return qe_invalid;
}
}
}

if(guyversion >= 18)
{
if(!p_getc(&(tempguy.hitsfx),f,keepdata))
{
return qe_invalid;
}

if(!p_getc(&(tempguy.deadsfx),f,keepdata))
{
return qe_invalid;
}
}

if(guyversion >= 22)
{
if(!p_igetl(&(tempguy.misc11),f,keepdata))
{
return qe_invalid;
}

if(!p_igetl(&(tempguy.misc12),f,keepdata))
{
return qe_invalid;
}

/*

//!ZoriaRPG : We need a new min version for this to prevent bricking older quests

for(int j=0; j<scriptDEFLAST; j++)
{
if(!p_getc(&(tempguy.scriptdefense[j]),f,keepdata))
{
return qe_invalid;
}
}
*/
}
else if(guyversion >= 19)
{
short tempMisc;

if(!p_igetw(&tempMisc,f,keepdata))
{
return qe_invalid;
}

tempguy.misc11=tempMisc;

if(!p_igetw(&tempMisc,f,keepdata))
{
return qe_invalid;
}

tempguy.misc12=tempMisc;
}

//miscellaneous other corrections
//fix the mirror wizzrobe -DD
if(guyversion < 7)
{
if(i == eMWIZ)
{
tempguy.misc2 = 0;
tempguy.misc4 = 1;
}
}

if(guyversion < 8)
{
if(i == eGLEEOK1 || i == eGLEEOK2 || i == eGLEEOK3 || i == eGLEEOK4 || i == eGLEEOK1F || i == eGLEEOK2F || i == eGLEEOK3F || i == eGLEEOK4F)
{
// Some of these are deliberately different to NewDefault/defdata.cpp, by the way. -L
tempguy.misc5 = 4; //neck length in segments
tempguy.misc6 = 8; //neck offset from first body tile
tempguy.misc7 = 40; //offset for each subsequent neck tile from the first neck tile
tempguy.misc8 = 168; //head offset from first body tile
tempguy.misc9 = 228; //flying head offset from first body tile

if(i == eGLEEOK1F || i == eGLEEOK2F || i == eGLEEOK3F || i == eGLEEOK4F)
{
tempguy.misc6 += 10; //neck offset from first body tile
tempguy.misc8 -= 12; //head offset from first body tile
}
}
}

if(guyversion < 10) // December 2007 - Dodongo CSet fix
{
if(get_bit(deprecated_rules,46) && tempguy.family==eeDONGO && tempguy.misc1==0)
tempguy.bosspal = spDIG;
}

if(guyversion < 11) // December 2007 - Spinning Tile fix
{
if(tempguy.family==eeSPINTILE)
{
tempguy.flags |= guy_superman;
tempguy.item_set = 0; // Don't drop items
tempguy.step = 300;
}
}

if(guyversion < 12) // October 2008 - Flashing Bubble, Rope 2, and Ghini 2 fix
{
if(get_bit(deprecated_rules, qr_NOROPE2FLASH_DEP))
{
if(tempguy.family==eeROPE)
{
tempguy.flags2 &= ~guy_flashing;
}
}

if(get_bit(deprecated_rules, qr_NOBUBBLEFLASH_DEP))
{
if(tempguy.family==eeBUBBLE)
{
tempguy.flags2 &= ~guy_flashing;
}
}

if((tempguy.family==eeGHINI)&&(tempguy.misc1))
{
if(get_bit(deprecated_rules, qr_GHINI2BLINK_DEP))
{
tempguy.flags2 |= guy_blinking;
}

if(get_bit(deprecated_rules, qr_PHANTOMGHINI2_DEP))
{
tempguy.flags2 |= guy_transparent;
}
}
}

if(guyversion < 15) // July 2009 - Guy Fire and Fairy fix
{
if(i==gFIRE)
{
tempguy.e_anim = aFLIP;
tempguy.e_frate = 24;
}

if(i==gFAIRY)
{
tempguy.e_anim = a2FRM;
tempguy.e_frate = 16;
}
}

if(guyversion < 16) // November 2009 - Super Enemy Editor part 1
{
if(i==0) Z_message("Updating guys to version 16...\n"😉;

update_guy_1(&tempguy);

if(i==eMPOLSV)
{
tempguy.defense[edefARROW] = edCHINK;
tempguy.defense[edefMAGIC] = ed1HKO;
tempguy.defense[edefREFMAGIC] = ed1HKO;
}
}

if(guyversion < 17) // December 2009
{
if(tempguy.family==eePROJECTILE)
{
tempguy.misc1 = 0;
}
}

if(guyversion < 18) // January 2010
{
bool boss = (tempguy.family == eeAQUA || tempguy.family==eeDONGO || tempguy.family == eeMANHAN || tempguy.family == eeGHOMA || tempguy.family==eeDIG
|| tempguy.family == eeGLEEOK || tempguy.family==eePATRA || tempguy.family == eeGANON || tempguy.family==eeMOLD);

tempguy.hitsfx = (boss && tempguy.family != eeMOLD && tempguy.family != eeDONGO && tempguy.family != eeDIG) ? WAV_GASP : 0;
tempguy.deadsfx = (boss && (tempguy.family != eeDIG || tempguy.misc10 == 0)) ? WAV_GASP : WAV_EDEAD;

if(tempguy.family == eeAQUA)
for(int j=0; j<edefLAST; j++) tempguy.defense[j] = default_guys[eRAQUAM].defense[j];
else if(tempguy.family == eeMANHAN)
for(int j=0; j<edefLAST; j++) tempguy.defense[j] = default_guys[eMANHAN].defense[j];
else if(tempguy.family==eePATRA)
for(int j=0; j<edefLAST; j++) tempguy.defense[j] = default_guys[eGLEEOK1].defense[j];
else if(tempguy.family==eeGHOMA)
{
for(int j=0; j<edefLAST; j++)
tempguy.defense[j] = default_guys[eGOHMA1].defense[j];

tempguy.defense[edefARROW] = ((tempguy.misc1==3) ? edCHINKL8 : (tempguy.misc1==2) ? edCHINKL4 : 0);

if(tempguy.misc1==3 && !tempguy.weapon) tempguy.weapon = ewFlame;

tempguy.misc1--;
}
else if(tempguy.family == eeGLEEOK)
{
for(int j=0; j<edefLAST; j++)
tempguy.defense[j] = default_guys[eGLEEOK1].defense[j];

if(tempguy.misc3==1 && !tempguy.weapon) tempguy.weapon = ewFlame;
}
else if(tempguy.family == eeARMOS)
{
tempguy.family=eeWALK;
tempguy.hrate = 0;
tempguy.misc10 = tempguy.misc1;
tempguy.misc1 = tempguy.misc2 = tempguy.misc3 = tempguy.misc4 = tempguy.misc5 = tempguy.misc6 = tempguy.misc7 = tempguy.misc8 = 0;
tempguy.misc9 = e9tARMOS;
}
else if(tempguy.family == eeGHINI && !tempguy.misc1)
{
tempguy.family=eeWALK;
tempguy.hrate = 0;
tempguy.misc1 = tempguy.misc2 = tempguy.misc3 = tempguy.misc4 = tempguy.misc5 = tempguy.misc6 =
tempguy.misc7 = tempguy.misc8 = tempguy.misc9 = tempguy.misc10 = 0;
}

// Spawn animation flags
if(tempguy.family == eeWALK && (tempguy.flags2&cmbflag_armos || tempguy.flags2&cmbflag_ghini))
tempguy.flags |= guy_fadeflicker;
else
tempguy.flags &= 0x0F00000F; // Get rid of the unused flags!
}

if(guyversion < 20) // April 2010
{
if(tempguy.family == eeTRAP)
{
tempguy.misc2 = tempguy.misc10;

if(tempguy.misc10>=1)
{
tempguy.misc1++;
}

tempguy.misc10 = 0;
}

// Bomb Blast fix
if(tempguy.weapon==ewBomb && tempguy.family!=eeROPE && (tempguy.family!=eeWALK || tempguy.misc2 != e2tBOMBCHU))
tempguy.weapon = ewLitBomb;
else if(tempguy.weapon==ewSBomb && tempguy.family!=eeROPE && (tempguy.family!=eeWALK || tempguy.misc2 != e2tBOMBCHU))
tempguy.weapon = ewLitSBomb;
}

if(guyversion < 21) // September 2011
{
if(tempguy.family == eeKEESE || tempguy.family == eeKEESETRIB)
{
if(tempguy.family == eeKEESETRIB)
{
tempguy.family = eeKEESE;
tempguy.misc2 = e2tKEESETRIB;
tempguy.misc1 = 0;
}

tempguy.rate = 2;
tempguy.hrate = 8;
tempguy.homing = 0;
tempguy.step= (tempguy.family == eeKEESE && tempguy.misc1 ? 100:62);
}
else if(tempguy.family == eePEAHAT || tempguy.family==eePATRA)
{
if(tempguy.family == eePEAHAT)
{
tempguy.rate = 4;
tempguy.step = 62;
}
else
tempguy.step = 25;

tempguy.hrate = 8;
tempguy.homing = 0;
}
else if(tempguy.family == eeDIG || tempguy.family == eeMANHAN)
{
if(tempguy.family == eeMANHAN)
tempguy.step=50;

tempguy.hrate = 16;
tempguy.homing = 0;
}
else if(tempguy.family == eeGLEEOK)
{
tempguy.rate = 2;
tempguy.homing = 0;
tempguy.hrate = 9;
tempguy.step=89;
}
else if(tempguy.family == eeGHINI)
{
tempguy.rate = 4;
tempguy.hrate = 12;
tempguy.step=62;
tempguy.homing = 0;
}

// Bigdig random rate fix
if(tempguy.family==eeDIG && tempguy.misc10==1)
{
tempguy.rate = 2;
}
}

if(guyversion < 24) // November 2012
{
if(tempguy.family==eeLANM)
tempguy.misc3 = 1;
else if(tempguy.family==eeMOLD)
tempguy.misc2 = 0;
}

if(keepdata)
{
guysbuf[i] = tempguy;
}
}
}

return 0;
}

[/spoiler]

zq_custom.cpp
[spoiler]

void edit_enemydata(int index)
{
char hp[8], dp[8], wdp[8], rat[8], hrt[8], hom[8], grm[8], spd[8],
frt[8], efr[8], bsp[8];
char w[8],h[8],sw[8],sh[8],ew[8],eh[8];
char name[64];
char ms[12][8];
char enemynumstr[75];

//disable the missing dialog items!
//else they will lurk in the background
//stealing mouse focus -DD
for(int i=0; enedata_flags2_list[i] != -1; i++)
{
enedata_dlg[enedata_flags2_list[i]].proc = d_dummy_proc;
enedata_dlg[enedata_flags2_list[i]].x = 0;
enedata_dlg[enedata_flags2_list[i]].y = 0;
enedata_dlg[enedata_flags2_list[i]].w = 0;
enedata_dlg[enedata_flags2_list[i]].h = 0;
}

sprintf(enemynumstr,"Enemy %d: %s", index, guy_string[index]);
enedata_dlg[0].dp = enemynumstr;
enedata_dlg[0].dp2 = lfont;
enedata_dlg[2].d1 = guysbuf[index].tile;
enedata_dlg[2].d2 = guysbuf[index].cset;
enedata_dlg[3].d1 = guysbuf[index].s_tile;
enedata_dlg[3].d2 = guysbuf[index].cset;
enedata_dlg[4].d1 = guysbuf[index].e_tile;
enedata_dlg[4].d2 = guysbuf[index].cset;

// Enemy weapon list
if(guysbuf[index].weapon==wNone)
{
enedata_dlg[45].d1 = 0;
}
else
{
if(biew_cnt==-1)
{
build_biew_list();
}

for(int j=0; j<biew_cnt; j++)
{
if(biew[j].i == guysbuf[index].weapon - wEnemyWeapons)
enedata_dlg[45].d1 = j;
}
}

// Enemy family list
if(bief_cnt==-1)
{
build_bief_list();
}

for(int j=0; j<bief_cnt; j++)
{
if(bief[j].i == guysbuf[index].family)
enedata_dlg[46].d1 = j;
}

// Enemy animation list
if(biea_cnt==-1)
{
build_biea_list();
}

for(int j=0; j<biea_cnt; j++)
{
if(biea[j].i == guysbuf[index].anim)
enedata_dlg[47].d1 = j;

if(biea[j].i == guysbuf[index].e_anim)
enedata_dlg[48].d1 = j;
}


enedata_dlg[49].d1 = guysbuf[index].item_set;

sprintf(w,"%d",guysbuf[index].width);
sprintf(h,"%d",guysbuf[index].height);
sprintf(sw,"%d",guysbuf[index].s_width);
sprintf(sh,"%d",guysbuf[index].s_height);
sprintf(ew,"%d",guysbuf[index].e_width);
sprintf(eh,"%d",guysbuf[index].e_height);
enedata_dlg[30].dp = w;
enedata_dlg[31].dp = h;
enedata_dlg[32].dp = sw;
enedata_dlg[33].dp = sh;
enedata_dlg[34].dp = ew;
enedata_dlg[35].dp = eh;

sprintf(hp,"%d",guysbuf[index].hp);
sprintf(dp,"%d",guysbuf[index].dp);
sprintf(wdp,"%d",guysbuf[index].wdp);
sprintf(grm,"%d",guysbuf[index].grumble);
enedata_dlg[37].dp = hp;
enedata_dlg[38].dp = dp;
enedata_dlg[39].dp = wdp;
enedata_dlg[40].dp = grm;

sprintf(rat,"%d",guysbuf[index].rate);
sprintf(hrt,"%d",guysbuf[index].hrate);
sprintf(hom,"%d",guysbuf[index].homing);
sprintf(spd,"%d",guysbuf[index].step);
enedata_dlg[41].dp = rat;
enedata_dlg[42].dp = hrt;
enedata_dlg[43].dp = hom;
enedata_dlg[44].dp = spd;

sprintf(name,"%s",guy_string[index]);
enedata_dlg[36].dp = name;

sprintf(ms[0],"%ld",guysbuf[index].misc1);
sprintf(ms[1],"%ld",guysbuf[index].misc2);
sprintf(ms[2],"%ld",guysbuf[index].misc3);
sprintf(ms[3],"%ld",guysbuf[index].misc4);
sprintf(ms[4],"%ld",guysbuf[index].misc5);
sprintf(ms[5],"%ld",guysbuf[index].misc6);
sprintf(ms[6],"%ld",guysbuf[index].misc7);
sprintf(ms[7],"%ld",guysbuf[index].misc8);
sprintf(ms[8],"%ld",guysbuf[index].misc9);
sprintf(ms[9],"%ld",guysbuf[index].misc10);
sprintf(ms[10],"%ld",guysbuf[index].misc11);
sprintf(ms[11],"%ld",guysbuf[index].misc12);

//Read in the enemy deences to the editor.
for(int j=0; j <= edefBYRNA; j++)
{
enedata_dlg[j+161].d1 = guysbuf[index].defense[j];
}

enedata_dlg[192].d1 = guysbuf[index].defense[edefSCRIPT];

enedata_dlg[203].d1 = guysbuf[index].scriptdefense[scriptDEF1];
enedata_dlg[204].d1 = guysbuf[index].scriptdefense[scriptDEF2];
enedata_dlg[205].d1 = guysbuf[index].scriptdefense[scriptDEF3];
enedata_dlg[206].d1 = guysbuf[index].scriptdefense[scriptDEF4];
enedata_dlg[207].d1 = guysbuf[index].scriptdefense[scriptDEF5];
enedata_dlg[208].d1 = guysbuf[index].scriptdefense[scriptDEF6];
enedata_dlg[209].d1 = guysbuf[index].scriptdefense[scriptDEF7];
enedata_dlg[210].d1 = guysbuf[index].scriptdefense[scriptDEF8];
enedata_dlg[211].d1 = guysbuf[index].scriptdefense[scriptDEF9];
enedata_dlg[212].d1 = guysbuf[index].scriptdefense[scriptDEF10];

/*
for(int j=0; j <= 9; j++)
{
enedata_dlg[j+203].d1 = guysbuf[index].scriptdefense[j];
}
*/

sprintf(frt,"%d",guysbuf[index].frate);
sprintf(efr,"%d",guysbuf[index].e_frate);
enedata_dlg[140].dp = frt;
enedata_dlg[141].dp = efr;

//sprintf(sfx,"%d",guysbuf[index].bgsfx);
enedata_dlg[182].d1= (int)guysbuf[index].bgsfx;
enedata_dlg[183].d1= (int)guysbuf[index].hitsfx;
enedata_dlg[184].d1= (int)guysbuf[index].deadsfx;

sprintf(bsp,"%d",guysbuf[index].bosspal);

if(guysbuf[index].cset == 14)
{
enedata_dlg[143].flags = D_SELECTED;
}
else
{
enedata_dlg[143].flags = 0;
}

enedata_dlg[53].dp = bsp;

for(int i=0; i<32; i++)
enedata_dlg[74+i].flags = (guysbuf[index].flags & (1<<i)) ? D_SELECTED : 0;

enedata_dlg[186].d1 = (guysbuf[index].flags & guy_fadeinstant ? 2
: guysbuf[index].flags & guy_fadeflicker ? 1 : 0);

for(int i=0; i<16; i++)
enedata_dlg[106+i].flags = (guysbuf[index].flags2 & (1<<i)) ? D_SELECTED : 0;

int ret;
guydata test;
memset(&test, 0, sizeof(guydata));

if(is_large)
{
large_dialog(enedata_dlg);
}

setEnemyLabels(guysbuf[index].family);

do
{
for(int i=0; i<10; i++)
{
if(enedata_dlg[64+i].proc==jwin_droplist_proc)
{
int size = 0;
((ListData*)enedata_dlg[64+i].dp)->listFunc(-1,&size);
// Bound ms[i] as well as enedata_dlg[64+i].d1
sprintf(ms[i],"%d",vbound(atoi(ms[i]), 0, size));
enedata_dlg[64+i].d1 = atoi(ms[i]);
}
else
enedata_dlg[64+i].dp = ms[i];
}

enedata_dlg[189].dp = ms[10];
enedata_dlg[190].dp = ms[11];

ret = zc_popup_dialog(enedata_dlg,3);

test.tile = enedata_dlg[2].d1;
test.cset = enedata_dlg[2].d2;
test.s_tile = enedata_dlg[3].d1;
test.e_tile = enedata_dlg[4].d1;

test.width = vbound(atoi(w),0,20);
test.height = vbound(atoi(h),0,20);
test.s_width = vbound(atoi(sw),0,20);
test.s_height = vbound(atoi(sh),0,20);
test.e_width = vbound(atoi(ew),0,20);
test.e_height = vbound(atoi(eh),0,20);

test.weapon = enedata_dlg[45].d1 != 0 ? biew[enedata_dlg[45].d1].i + wEnemyWeapons : wNone;
test.family = bief[enedata_dlg[46].d1].i;
test.anim = biea[enedata_dlg[47].d1].i;
test.e_anim = biea[enedata_dlg[48].d1].i;
test.item_set = enedata_dlg[49].d1;

test.hp = vbound(atoi(hp), 0, 32767); //0x7FFF, not 0xFFFF?
test.dp = vbound(atoi(dp), 0, 32767);
test.wdp = vbound(atoi(wdp), 0, 32767);
test.grumble = vbound(atoi(grm), 0, 4);

test.rate = vbound(atoi(rat), 0, (test.family == eeFIRE || test.family == eeOTHER)?32767:16);
test.hrate = vbound(atoi(hrt), 0, (test.family == eeFIRE || test.family == eeOTHER)?32767:16);
test.homing = vbound(atoi(hom), 0, (test.family == eeFIRE || test.family == eeOTHER)?32767:256);
test.step = vbound(atoi(spd),0, (test.family == eeFIRE || test.family == eeOTHER)?32767:1000);

test.frate = vbound(atoi(frt),0,256);
test.e_frate = vbound(atoi(efr),0,256);
test.bosspal = vbound(atoi(bsp),-1,29);
test.bgsfx = enedata_dlg[182].d1;
test.hitsfx = enedata_dlg[183].d1;
test.deadsfx = enedata_dlg[184].d1;

test.misc1 = (enedata_dlg[64].proc==jwin_droplist_proc) ? enedata_dlg[64].d1 : atol(ms[0]);
test.misc2 = (enedata_dlg[65].proc==jwin_droplist_proc) ? enedata_dlg[65].d1 : atol(ms[1]);
test.misc3 = (enedata_dlg[66].proc==jwin_droplist_proc) ? enedata_dlg[66].d1 : atol(ms[2]);
test.misc4 = (enedata_dlg[67].proc==jwin_droplist_proc) ? enedata_dlg[67].d1 : atol(ms[3]);
test.misc5 = (enedata_dlg[68].proc==jwin_droplist_proc) ? enedata_dlg[68].d1 : atol(ms[4]);
test.misc6 = (enedata_dlg[69].proc==jwin_droplist_proc) ? enedata_dlg[69].d1 : atol(ms[5]);
test.misc7 = (enedata_dlg[70].proc==jwin_droplist_proc) ? enedata_dlg[70].d1 : atol(ms[6]);
test.misc8 = (enedata_dlg[71].proc==jwin_droplist_proc) ? enedata_dlg[71].d1 : atol(ms[7]);
test.misc9 = (enedata_dlg[72].proc==jwin_droplist_proc) ? enedata_dlg[72].d1 : atol(ms[8]);
test.misc10 = (enedata_dlg[73].proc==jwin_droplist_proc) ? enedata_dlg[73].d1 : atol(ms[9]);
test.misc11 = atol(ms[10]);
test.misc12 = atol(ms[11]);

//Write enemy defences to the test buffer.
for(int j=0; j <= edefBYRNA; j++)
{
test.defense[j] = enedata_dlg[j+161].d1;
}

test.defense[edefSCRIPT] = enedata_dlg[192].d1;

//test.scriptdefense[scriptDEF1] = enedata_dlg[203].d1;
test.scriptdefense[scriptDEF2] = enedata_dlg[204].d1;
test.scriptdefense[scriptDEF3] = enedata_dlg[205].d1;
test.scriptdefense[scriptDEF4] = enedata_dlg[206].d1;
test.scriptdefense[scriptDEF5] = enedata_dlg[207].d1;
test.scriptdefense[scriptDEF6] = enedata_dlg[208].d1;
test.scriptdefense[scriptDEF7] = enedata_dlg[209].d1;
test.scriptdefense[scriptDEF8] = enedata_dlg[210].d1;
test.scriptdefense[scriptDEF9] = enedata_dlg[211].d1;
//test.scriptdefense[scriptDEF10] = enedata_dlg[212].d1;

//Taking these out, in the event that I'm doing something out of bounds.

/*
for(int j=0; j <= 9; j++)
{
test.scriptdefense[j] = enedata_dlg[j+203].d1;
}
*/

for(int i=0; i<32; i++)
test.flags |= (enedata_dlg[74+i].flags & D_SELECTED) ? (1<<i) : 0;

test.flags &= ~(guy_fadeinstant|guy_fadeflicker);
test.flags |= (enedata_dlg[186].d1==2 ? guy_fadeinstant : enedata_dlg[186].d1==1 ? guy_fadeflicker : 0);

for(int i=0; i<16; i++)
test.flags2 |= (enedata_dlg[106+i].flags & D_SELECTED) ? (1<<i) : 0;

if(enedata_dlg[143].flags & D_SELECTED)
test.cset = 14;

if(ret==5)
{
//store the test buffer into the npc
strcpy(guy_string[index],name);
guysbuf[index] = test;
saved = false;
}
else if(ret==46)
{
setEnemyLabels(bief[enedata_dlg[46].d1].i);
}
else if(ret==178)
{
for(int j=1; j <= edefBYRNA; j++)
{
enedata_dlg[j+161].d1 = enedata_dlg[161].d1;
}

enedata_dlg[192].d1 = enedata_dlg[161].d1;

//Clear to 0
enedata_dlg[203].d1 = enedata_dlg[161].d1;
enedata_dlg[204].d1 = enedata_dlg[161].d1;
enedata_dlg[205].d1 = enedata_dlg[161].d1;
enedata_dlg[206].d1 = enedata_dlg[161].d1;
enedata_dlg[207].d1 = enedata_dlg[161].d1;
enedata_dlg[208].d1 = enedata_dlg[161].d1;
enedata_dlg[209].d1 = enedata_dlg[161].d1;
enedata_dlg[210].d1 = enedata_dlg[161].d1;
enedata_dlg[211].d1 = enedata_dlg[161].d1;
enedata_dlg[212].d1 = enedata_dlg[161].d1;

/*
for(int j=1; j <= 9; j++)
{
enedata_dlg[j+203].d1 = enedata_dlg[203].d1;
}
*/
}
}
while(ret != 5 && ret != 6 && ret != 0);

}

[/spoiler]

Search for 'scriptdefs' in those functions. The codeblocks that I commented out to prevent corruption are commented out in blocks.

Entire Package

As I said, the defs do work, when set by script. All of that is in place, save for an exception based on a quest version, to use the old checking method.

If you need to read the table for the jwin stuff, it's in there.

Once we get the data corruption sorted, this feature is effectively ready to use.

Okay, I just took a look at it all. *phew*

Fix #1: The saving code is corrupting the quest file, the loading code looks fine...-ish (see fix #2). Put the serializing of scriptdefenses[] after the serializing of guy->misc12.
Fix #2:


if(guyversion >= 23) // Add new guyversion conditional statement
{
for(int j=0; j<scriptDEFLAST; j++)
{
if(!p_getc(&(tempguy.scriptdefense[j]),f,keepdata))
{
return qe_invalid;
}
}
}

Fix #3: Save guysversion as the current version (23).

I don't see anything else right now. Try that and let me know if it works.

Gleeok wrote:Okay, I just took a look at it all. *phew*

Fix #1: The saving code is corrupting the quest file, the loading code looks fine...-ish (see fix #2). Put the serializing of scriptdefenses[] after the serializing of guy->misc12.
Fix #2:


if(guyversion >= 23) // Add new guyversion conditional statement
{
for(int j=0; j<scriptDEFLAST; j++)
{
if(!p_getc(&(tempguy.scriptdefense[j]),f,keepdata))
{
return qe_invalid;
}
}
}

Fix #3: Save guysversion as the current version (23).

I don't see anything else right now. Try that and let me know if it works.

Where do I change the defs for guyversion, and add the new version; or did you mean that 23 is current? I'd still need to know where to set that.

ZoriaRPG wrote:Where do I change the defs for guyversion, and add the new version; or did you mean that 23 is current? I'd still need to know where to set that.

V_GUYS in zdefs.h.

Gleeok wrote:V_GUYS in zdefs.h.

Oh, must have glossed over it. probably because I didn't know the current version, and it didn't match the known ID.

Anyhow, still massive data corruption:

User posted image
The default bubble enemy, upon loading the base quest template with this patch.

qst.cpp

[spoiler]

int readguys(PACKFILE *f, zquestheader *Header, bool keepdata)
{
dword dummy;
word dummy2;
word guyversion=0;

if(Header->zelda_version >= 0x193)
{
//section version info
if(!p_igetw(&guyversion,f,true))
{
return qe_invalid;
}

//al_trace("Guys version %d\n", guyversion);
if(!p_igetw(&dummy2,f,true))
{
return qe_invalid;
}

//section size
if(!p_igetl(&dummy,f,true))
{
return qe_invalid;
}
}

if(guyversion > 3)
{
for(int i=0; i<MAXGUYS; i++)
{
char tempname[64];

// rev. 1511 : guyversion = 23. upped to 512 editable enemies. -Gleeok
// if guyversion < 23 then there is only 256 enemies in the packfile, so default the rest.
if(guyversion < 23 && i >= OLDBETAMAXGUYS && keepdata)
{
memset(tempname, 0, sizeof(char)*64);
sprintf(tempname, "e%03d", i);
strcpy(guy_string[i], tempname);

continue;
}

if(!pfread(tempname, 64, f, keepdata))
{
return qe_invalid;
}

// Don't retain names of uneditable enemy entries!
if(keepdata)
{
// for version upgrade to 2.5
if(guyversion < 23 && i >= 177)
{
// some of the older builds have names such as 'zz123',
// (this order gets messed up with some eXXX and some zzXXX)
// so let's update to the newer naming convection. -Gleeok
char tmpbuf[64];
memset(tmpbuf, 0, sizeof(char)*64);
sprintf(tmpbuf, "zz%03d", i);

if(memcmp(tempname, tmpbuf, size_t(5)) == 0)
{
memset(tempname, 0, sizeof(char)*64);
sprintf(tempname, "e%03d", i);
}
}

if(i >= OLDMAXGUYS || strlen(tempname)<1 || tempname[strlen(tempname)-1]!=' '😉
{
strcpy(guy_string[i], tempname);
}
else
{
strcpy(guy_string[i],old_guy_string[i]);
}
}
}
}
else
{
if(keepdata)
{
for(int i=0; i<eMAXGUYS; i++)
{
sprintf(guy_string[i],"zz%03d",i);
}

for(int i=0; i<OLDMAXGUYS; i++)
{
strcpy(guy_string[i],old_guy_string[i]);
}
}
}


//finally... section data
if(keepdata)
{
init_guys(guyversion); //using default data for now...

// Goriya guy fix
if((Header->zelda_version < 0x211)||((Header->zelda_version == 0x211)&&(Header->build<7)))
{
if(get_bit(quest_rules,qr_NEWENEMYTILES))
{
guysbuf[gGORIYA].tile=130;
guysbuf[gGORIYA].e_tile=130;
}
}
}

if(Header->zelda_version < 0x193)
{
if(get_bit(deprecated_rules,46))
{
guysbuf[eDODONGO].cset=14;
guysbuf[eDODONGO].bosspal=spDIG;
}
}

// Not sure when this first changed, but it's necessary for 2.10, at least
if(Header->zelda_version <= 0x210)
{
guysbuf[eGLEEOK1F].misc6 = 16;
guysbuf[eGLEEOK2F].misc6 = 16;
guysbuf[eGLEEOK3F].misc6 = 16;
guysbuf[eGLEEOK4F].misc6 = 16;

guysbuf[eWIZ1].misc4 = 1;
guysbuf[eBATROBE].misc4 = 1;
guysbuf[eSUMMONER].misc4 = 1;
guysbuf[eWWIZ].misc4 = 1;
}

// The versions here may not be correct
// zelda_version>=0x211 handled at guyversion<24
if(Header->zelda_version <= 0x190)
{
guysbuf[eCENT1].misc3 = 0;
guysbuf[eCENT2].misc3 = 0;
guysbuf[eMOLDORM].misc2 = 0;
}
else if(Header->zelda_version <= 0x210)
{
guysbuf[eCENT1].misc3 = 1;
guysbuf[eCENT2].misc3 = 1;
guysbuf[eMOLDORM].misc2 = 0;
}

if(guyversion<=2)
{
return readlinksprites2(f, guyversion==2?0:-1, 0, keepdata);
}

if(guyversion > 3)
{
guydata tempguy;

for(int i=0; i<MAXGUYS; i++)
{
if(guyversion < 23 && keepdata) // May 2012 : 512 max enemies
{
if(i >= OLDBETAMAXGUYS)
{
memset(&guysbuf[i], 0, sizeof(guydata));
continue;
}
}

memset(&tempguy, 0, sizeof(guydata));

if(!p_igetl(&(tempguy.flags),f,keepdata))
{
return qe_invalid;
}

if(!p_igetl(&(tempguy.flags2),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.tile),f,keepdata))
{
return qe_invalid;
}

if(!p_getc(&(tempguy.width),f,keepdata))
{
return qe_invalid;
}

if(!p_getc(&(tempguy.height),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.s_tile),f,keepdata))
{
return qe_invalid;
}

if(!p_getc(&(tempguy.s_width),f,keepdata))
{
return qe_invalid;
}

if(!p_getc(&(tempguy.s_height),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.e_tile),f,keepdata))
{
return qe_invalid;
}

if(!p_getc(&(tempguy.e_width),f,keepdata))
{
return qe_invalid;
}

if(!p_getc(&(tempguy.e_height),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.hp),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.family),f,keepdata))
{
return qe_invalid;
}

if(guyversion < 9 && (i==eDKNUT1 || i==eDKNUT2 || i==eDKNUT3 || i==eDKNUT4 || i==eDKNUT5)) // Whoops, forgot about Darknuts...
{
if(get_bit(quest_rules,qr_NEWENEMYTILES))
{
tempguy.s_tile=tempguy.e_tile+120;
tempguy.s_width=tempguy.e_width;
tempguy.s_height=tempguy.e_height;
}
else tempguy.s_tile=860;
}

if(!p_igetw(&(tempguy.cset),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.anim),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.e_anim),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.frate),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.e_frate),f,keepdata))
{
return qe_invalid;
}

if(guyversion < 13) // April 2009
{
if(get_bit(deprecated_rules, qr_SLOWENEMYANIM_DEP))
{
tempguy.frate *= 2;
tempguy.e_frate *= 2;
}
}

if(guyversion < 14) // May 1 2009
{
if(tempguy.anim==a2FRMSLOW)
{
tempguy.anim=a2FRM;
tempguy.frate *= 2;
}

if(tempguy.e_anim==a2FRMSLOW)
{
tempguy.e_anim=a2FRM;
tempguy.e_frate *= 2;
}

if(tempguy.anim==aFLIPSLOW)
{
tempguy.anim=aFLIP;
tempguy.frate *= 2;
}

if(tempguy.e_anim==aFLIPSLOW)
{
tempguy.e_anim=aFLIP;
tempguy.e_frate *= 2;
}

if(tempguy.anim == aNEWDWALK) tempguy.anim = a4FRM4DIR;

if(tempguy.e_anim == aNEWDWALK) tempguy.e_anim = a4FRM4DIR;

if(tempguy.anim == aNEWPOLV || tempguy.anim == a4FRM3TRAP)
{
tempguy.anim=a4FRM4DIR;
tempguy.s_tile=(get_bit(quest_rules,qr_NEWENEMYTILES) ? tempguy.e_tile : tempguy.tile)+20;
}

if(tempguy.e_anim == aNEWPOLV || tempguy.e_anim == a4FRM3TRAP)
{
tempguy.e_anim=a4FRM4DIR;
tempguy.s_tile=(get_bit(quest_rules,qr_NEWENEMYTILES) ? tempguy.e_tile : tempguy.tile)+20;
}
}

if(!p_igetw(&(tempguy.dp),f,keepdata))
{
return qe_invalid;
}

//correction for guy fire
if(guyversion < 6)
{
if(i == gFIRE)
tempguy.dp = 2;
}

if(!p_igetw(&(tempguy.wdp),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.weapon),f,keepdata))
{
return qe_invalid;
}

//correction for bosses using triple, "rising" fireballs
if(guyversion < 5)
{
if(i == eLAQUAM || i == eRAQUAM || i == eGOHMA1 || i == eGOHMA2 ||
i == eGOHMA3 || i == eGOHMA4)
{
if(tempguy.weapon == ewFireball)
tempguy.weapon = ewFireball2;
}
}

if(!p_igetw(&(tempguy.rate),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.hrate),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.step),f,keepdata))
{
return qe_invalid;
}

// HIGHLY UNORTHODOX UPDATING THING, part 2
if(fixpolsvoice && tempguy.family==eePOLSV)
{
tempguy.step /= 2;
}

if(!p_igetw(&(tempguy.homing),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.grumble),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.item_set),f,keepdata))
{
return qe_invalid;
}

if(guyversion>=22) // Version 22: Expand misc attributes to 32 bits
{
if(!p_igetl(&(tempguy.misc1),f,keepdata))
{
return qe_invalid;
}

if(!p_igetl(&(tempguy.misc2),f,keepdata))
{
return qe_invalid;
}

if(!p_igetl(&(tempguy.misc3),f,keepdata))
{
return qe_invalid;
}

if(!p_igetl(&(tempguy.misc4),f,keepdata))
{
return qe_invalid;
}

if(!p_igetl(&(tempguy.misc5),f,keepdata))
{
return qe_invalid;
}

if(!p_igetl(&(tempguy.misc6),f,keepdata))
{
return qe_invalid;
}

if(!p_igetl(&(tempguy.misc7),f,keepdata))
{
return qe_invalid;
}

if(!p_igetl(&(tempguy.misc8),f,keepdata))
{
return qe_invalid;
}

if(!p_igetl(&(tempguy.misc9),f,keepdata))
{
return qe_invalid;
}

if(!p_igetl(&(tempguy.misc10),f,keepdata))
{
return qe_invalid;
}
}
else
{
short tempMisc;

if(!p_igetw(&tempMisc,f,keepdata))
{
return qe_invalid;
}

tempguy.misc1=tempMisc;

if(!p_igetw(&tempMisc,f,keepdata))
{
return qe_invalid;
}

tempguy.misc2=tempMisc;

if(!p_igetw(&tempMisc,f,keepdata))
{
return qe_invalid;
}

tempguy.misc3=tempMisc;

if(!p_igetw(&tempMisc,f,keepdata))
{
return qe_invalid;
}

tempguy.misc4=tempMisc;

if(!p_igetw(&tempMisc,f,keepdata))
{
return qe_invalid;
}

tempguy.misc5=tempMisc;

if(guyversion < 13) // April 2009 - a tiny Wizzrobe update
{
if(tempguy.family == eeWIZZ && !(tempguy.misc1))
tempguy.misc5 = 74;
}

if(!p_igetw(&tempMisc,f,keepdata))
{
return qe_invalid;
}

tempguy.misc6=tempMisc;

if(!p_igetw(&tempMisc,f,keepdata))
{
return qe_invalid;
}

tempguy.misc7=tempMisc;

if(!p_igetw(&tempMisc,f,keepdata))
{
return qe_invalid;
}

tempguy.misc8=tempMisc;

if(!p_igetw(&tempMisc,f,keepdata))
{
return qe_invalid;
}

tempguy.misc9=tempMisc;

if(!p_igetw(&tempMisc,f,keepdata))
{
return qe_invalid;
}

tempguy.misc10=tempMisc;
}

if(!p_igetw(&(tempguy.bgsfx),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.bosspal),f,keepdata))
{
return qe_invalid;
}

if(!p_igetw(&(tempguy.extend),f,keepdata))
{
return qe_invalid;
}

if(guyversion >= 16) // November 2009 - Super Enemy Editor
{
for(int j=0; j<edefLAST; j++)
{
if(!p_getc(&(tempguy.defense[j]),f,keepdata))
{
return qe_invalid;
}
}
}

if(guyversion >= 18)
{
if(!p_getc(&(tempguy.hitsfx),f,keepdata))
{
return qe_invalid;
}

if(!p_getc(&(tempguy.deadsfx),f,keepdata))
{
return qe_invalid;
}
}

if(guyversion >= 22)
{
if(!p_igetl(&(tempguy.misc11),f,keepdata))
{
return qe_invalid;
}

if(!p_igetl(&(tempguy.misc12),f,keepdata))
{
return qe_invalid;
}

}
if(guyversion >= 23) // Add new guyversion conditional statement
{
for(int j=0; j<scriptDEFLAST; j++)
{
if(!p_getc(&(tempguy.scriptdefense[j]),f,keepdata))
{
return qe_invalid;
}
}
}
else if(guyversion >= 19)
{
short tempMisc;

if(!p_igetw(&tempMisc,f,keepdata))
{
return qe_invalid;
}

tempguy.misc11=tempMisc;

if(!p_igetw(&tempMisc,f,keepdata))
{
return qe_invalid;
}

tempguy.misc12=tempMisc;
}

//miscellaneous other corrections
//fix the mirror wizzrobe -DD
if(guyversion < 7)
{
if(i == eMWIZ)
{
tempguy.misc2 = 0;
tempguy.misc4 = 1;
}
}

if(guyversion < 8)
{
if(i == eGLEEOK1 || i == eGLEEOK2 || i == eGLEEOK3 || i == eGLEEOK4 || i == eGLEEOK1F || i == eGLEEOK2F || i == eGLEEOK3F || i == eGLEEOK4F)
{
// Some of these are deliberately different to NewDefault/defdata.cpp, by the way. -L
tempguy.misc5 = 4; //neck length in segments
tempguy.misc6 = 8; //neck offset from first body tile
tempguy.misc7 = 40; //offset for each subsequent neck tile from the first neck tile
tempguy.misc8 = 168; //head offset from first body tile
tempguy.misc9 = 228; //flying head offset from first body tile

if(i == eGLEEOK1F || i == eGLEEOK2F || i == eGLEEOK3F || i == eGLEEOK4F)
{
tempguy.misc6 += 10; //neck offset from first body tile
tempguy.misc8 -= 12; //head offset from first body tile
}
}
}

if(guyversion < 10) // December 2007 - Dodongo CSet fix
{
if(get_bit(deprecated_rules,46) && tempguy.family==eeDONGO && tempguy.misc1==0)
tempguy.bosspal = spDIG;
}

if(guyversion < 11) // December 2007 - Spinning Tile fix
{
if(tempguy.family==eeSPINTILE)
{
tempguy.flags |= guy_superman;
tempguy.item_set = 0; // Don't drop items
tempguy.step = 300;
}
}

if(guyversion < 12) // October 2008 - Flashing Bubble, Rope 2, and Ghini 2 fix
{
if(get_bit(deprecated_rules, qr_NOROPE2FLASH_DEP))
{
if(tempguy.family==eeROPE)
{
tempguy.flags2 &= ~guy_flashing;
}
}

if(get_bit(deprecated_rules, qr_NOBUBBLEFLASH_DEP))
{
if(tempguy.family==eeBUBBLE)
{
tempguy.flags2 &= ~guy_flashing;
}
}

if((tempguy.family==eeGHINI)&&(tempguy.misc1))
{
if(get_bit(deprecated_rules, qr_GHINI2BLINK_DEP))
{
tempguy.flags2 |= guy_blinking;
}

if(get_bit(deprecated_rules, qr_PHANTOMGHINI2_DEP))
{
tempguy.flags2 |= guy_transparent;
}
}
}

if(guyversion < 15) // July 2009 - Guy Fire and Fairy fix
{
if(i==gFIRE)
{
tempguy.e_anim = aFLIP;
tempguy.e_frate = 24;
}

if(i==gFAIRY)
{
tempguy.e_anim = a2FRM;
tempguy.e_frate = 16;
}
}

if(guyversion < 16) // November 2009 - Super Enemy Editor part 1
{
if(i==0) Z_message("Updating guys to version 16...\n"😉;

update_guy_1(&tempguy);

if(i==eMPOLSV)
{
tempguy.defense[edefARROW] = edCHINK;
tempguy.defense[edefMAGIC] = ed1HKO;
tempguy.defense[edefREFMAGIC] = ed1HKO;
}
}

if(guyversion < 17) // December 2009
{
if(tempguy.family==eePROJECTILE)
{
tempguy.misc1 = 0;
}
}

if(guyversion < 18) // January 2010
{
bool boss = (tempguy.family == eeAQUA || tempguy.family==eeDONGO || tempguy.family == eeMANHAN || tempguy.family == eeGHOMA || tempguy.family==eeDIG
|| tempguy.family == eeGLEEOK || tempguy.family==eePATRA || tempguy.family == eeGANON || tempguy.family==eeMOLD);

tempguy.hitsfx = (boss && tempguy.family != eeMOLD && tempguy.family != eeDONGO && tempguy.family != eeDIG) ? WAV_GASP : 0;
tempguy.deadsfx = (boss && (tempguy.family != eeDIG || tempguy.misc10 == 0)) ? WAV_GASP : WAV_EDEAD;

if(tempguy.family == eeAQUA)
for(int j=0; j<edefLAST; j++) tempguy.defense[j] = default_guys[eRAQUAM].defense[j];
else if(tempguy.family == eeMANHAN)
for(int j=0; j<edefLAST; j++) tempguy.defense[j] = default_guys[eMANHAN].defense[j];
else if(tempguy.family==eePATRA)
for(int j=0; j<edefLAST; j++) tempguy.defense[j] = default_guys[eGLEEOK1].defense[j];
else if(tempguy.family==eeGHOMA)
{
for(int j=0; j<edefLAST; j++)
tempguy.defense[j] = default_guys[eGOHMA1].defense[j];

tempguy.defense[edefARROW] = ((tempguy.misc1==3) ? edCHINKL8 : (tempguy.misc1==2) ? edCHINKL4 : 0);

if(tempguy.misc1==3 && !tempguy.weapon) tempguy.weapon = ewFlame;

tempguy.misc1--;
}
else if(tempguy.family == eeGLEEOK)
{
for(int j=0; j<edefLAST; j++)
tempguy.defense[j] = default_guys[eGLEEOK1].defense[j];

if(tempguy.misc3==1 && !tempguy.weapon) tempguy.weapon = ewFlame;
}
else if(tempguy.family == eeARMOS)
{
tempguy.family=eeWALK;
tempguy.hrate = 0;
tempguy.misc10 = tempguy.misc1;
tempguy.misc1 = tempguy.misc2 = tempguy.misc3 = tempguy.misc4 = tempguy.misc5 = tempguy.misc6 = tempguy.misc7 = tempguy.misc8 = 0;
tempguy.misc9 = e9tARMOS;
}
else if(tempguy.family == eeGHINI && !tempguy.misc1)
{
tempguy.family=eeWALK;
tempguy.hrate = 0;
tempguy.misc1 = tempguy.misc2 = tempguy.misc3 = tempguy.misc4 = tempguy.misc5 = tempguy.misc6 =
tempguy.misc7 = tempguy.misc8 = tempguy.misc9 = tempguy.misc10 = 0;
}

// Spawn animation flags
if(tempguy.family == eeWALK && (tempguy.flags2&cmbflag_armos || tempguy.flags2&cmbflag_ghini))
tempguy.flags |= guy_fadeflicker;
else
tempguy.flags &= 0x0F00000F; // Get rid of the unused flags!
}

if(guyversion < 20) // April 2010
{
if(tempguy.family == eeTRAP)
{
tempguy.misc2 = tempguy.misc10;

if(tempguy.misc10>=1)
{
tempguy.misc1++;
}

tempguy.misc10 = 0;
}

// Bomb Blast fix
if(tempguy.weapon==ewBomb && tempguy.family!=eeROPE && (tempguy.family!=eeWALK || tempguy.misc2 != e2tBOMBCHU))
tempguy.weapon = ewLitBomb;
else if(tempguy.weapon==ewSBomb && tempguy.family!=eeROPE && (tempguy.family!=eeWALK || tempguy.misc2 != e2tBOMBCHU))
tempguy.weapon = ewLitSBomb;
}

if(guyversion < 21) // September 2011
{
if(tempguy.family == eeKEESE || tempguy.family == eeKEESETRIB)
{
if(tempguy.family == eeKEESETRIB)
{
tempguy.family = eeKEESE;
tempguy.misc2 = e2tKEESETRIB;
tempguy.misc1 = 0;
}

tempguy.rate = 2;
tempguy.hrate = 8;
tempguy.homing = 0;
tempguy.step= (tempguy.family == eeKEESE && tempguy.misc1 ? 100:62);
}
else if(tempguy.family == eePEAHAT || tempguy.family==eePATRA)
{
if(tempguy.family == eePEAHAT)
{
tempguy.rate = 4;
tempguy.step = 62;
}
else
tempguy.step = 25;

tempguy.hrate = 8;
tempguy.homing = 0;
}
else if(tempguy.family == eeDIG || tempguy.family == eeMANHAN)
{
if(tempguy.family == eeMANHAN)
tempguy.step=50;

tempguy.hrate = 16;
tempguy.homing = 0;
}
else if(tempguy.family == eeGLEEOK)
{
tempguy.rate = 2;
tempguy.homing = 0;
tempguy.hrate = 9;
tempguy.step=89;
}
else if(tempguy.family == eeGHINI)
{
tempguy.rate = 4;
tempguy.hrate = 12;
tempguy.step=62;
tempguy.homing = 0;
}

// Bigdig random rate fix
if(tempguy.family==eeDIG && tempguy.misc10==1)
{
tempguy.rate = 2;
}
}

if(guyversion < 24) // November 2012
{
if(tempguy.family==eeLANM)
tempguy.misc3 = 1;
else if(tempguy.family==eeMOLD)
tempguy.misc2 = 0;
}

if(keepdata)
{
guysbuf[i] = tempguy;
}
}
}

return 0;
}

[/spoiler]

zq_class.cpp

[spoiler]

int writeguys(PACKFILE *f, zquestheader *Header)
{
//these are here to bypass compiler warnings about unused arguments
Header=Header;

dword section_id=ID_GUYS;
dword section_version=V_GUYS;
dword section_cversion=CV_GUYS;
dword section_size=0;

//section id
if(!p_mputl(section_id,f))
{
new_return(1);
}

//section version info
if(!p_iputw(section_version,f))
{
new_return(2);
}

if(!p_iputw(section_cversion,f))
{
new_return(3);
}

for(int writecycle=0; writecycle<2; ++writecycle)
{
fake_pack_writing=(writecycle==0);

//section size
if(!p_iputl(section_size,f))
{
new_return(4);
}

writesize=0;

//finally... section data
for(int i=0; i<MAXGUYS; i++)
{
if(!pfwrite((char *)guy_string[i], 64, f))
{
new_return(5);
}
}

for(int i=0; i<MAXGUYS; i++)
{
if(!p_iputl(guysbuf[i].flags,f))
{
new_return(6);
}

if(!p_iputl(guysbuf[i].flags2,f))
{
new_return(7);
}

if(!p_iputw(guysbuf[i].tile,f))
{
new_return(8);
}

if(!p_putc(guysbuf[i].width,f))
{
new_return(9);
}

if(!p_putc(guysbuf[i].height,f))
{
new_return(10);
}

if(!p_iputw(guysbuf[i].s_tile,f))
{
new_return(11);
}

if(!p_putc(guysbuf[i].s_width,f))
{
new_return(12);
}

if(!p_putc(guysbuf[i].s_height,f))
{
new_return(13);
}

if(!p_iputw(guysbuf[i].e_tile,f))
{
new_return(14);
}

if(!p_putc(guysbuf[i].e_width,f))
{
new_return(15);
}

if(!p_putc(guysbuf[i].e_height,f))
{
new_return(16);
}

if(!p_iputw(guysbuf[i].hp,f))
{
new_return(17);
}

if(!p_iputw(guysbuf[i].family,f))
{
new_return(18);
}

if(!p_iputw(guysbuf[i].cset,f))
{
new_return(19);
}

if(!p_iputw(guysbuf[i].anim,f))
{
new_return(20);
}

if(!p_iputw(guysbuf[i].e_anim,f))
{
new_return(21);
}

if(!p_iputw(guysbuf[i].frate,f))
{
new_return(22);
}

if(!p_iputw(guysbuf[i].e_frate,f))
{
new_return(23);
}

if(!p_iputw(guysbuf[i].dp,f))
{
new_return(24);
}

if(!p_iputw(guysbuf[i].wdp,f))
{
new_return(25);
}

if(!p_iputw(guysbuf[i].weapon,f))
{
new_return(26);
}

if(!p_iputw(guysbuf[i].rate,f))
{
new_return(27);
}

if(!p_iputw(guysbuf[i].hrate,f))
{
new_return(28);
}

if(!p_iputw(guysbuf[i].step,f))
{
new_return(29);
}

if(!p_iputw(guysbuf[i].homing,f))
{
new_return(30);
}

if(!p_iputw(guysbuf[i].grumble,f))
{
new_return(31);
}

if(!p_iputw(guysbuf[i].item_set,f))
{
new_return(32);
}

if(!p_iputl(guysbuf[i].misc1,f))
{
new_return(33);
}

if(!p_iputl(guysbuf[i].misc2,f))
{
new_return(34);
}

if(!p_iputl(guysbuf[i].misc3,f))
{
new_return(35);
}

if(!p_iputl(guysbuf[i].misc4,f))
{
new_return(36);
}

if(!p_iputl(guysbuf[i].misc5,f))
{
new_return(37);
}

if(!p_iputl(guysbuf[i].misc6,f))
{
new_return(38);
}

if(!p_iputl(guysbuf[i].misc7,f))
{
new_return(39);
}

if(!p_iputl(guysbuf[i].misc8,f))
{
new_return(40);
}

if(!p_iputl(guysbuf[i].misc9,f))
{
new_return(41);
}

if(!p_iputl(guysbuf[i].misc10,f))
{
new_return(42);
}

if(!p_iputw(guysbuf[i].bgsfx,f))
{
new_return(43);
}

if(!p_iputw(guysbuf[i].bosspal,f))
{
new_return(44);
}

if(!p_iputw(guysbuf[i].extend,f))
{
new_return(45);
}

if(!p_putc(guysbuf[i].hitsfx,f))
{
new_return(47);
}

if(!p_putc(guysbuf[i].deadsfx,f))
{
new_return(48);
}

if(!p_iputl(guysbuf[i].misc11,f))
{
new_return(49);
}

if(!p_iputl(guysbuf[i].misc12,f))
{
new_return(50);
}


//This stopped npcs from spawning!?

for(int j=0; j < scriptDEFLAST; j++)
{
if(!p_putc(guysbuf[i].scriptdefense[j],f))
{
new_return(51);
}
}

}

if(writecycle==0)
{
section_size=writesize;
}
}

if(writesize!=int(section_size) && save_warn)
{
char ebuf[80];
sprintf(ebuf, "%d != %d", writesize, int(section_size));
jwin_alert("Error: writeguys()","writesize != section_size",ebuf,NULL,"O&K",NULL,'k',0,lfont);
}

new_return(0);
}

[/spoiler]

IDK if you want to try to debug a binary, or do a build.

Something that I did made it worse... Looks as if there is now corruption even with those two disabled. 😞

The odd thing, is that I didn't touch anything related to those, but I made a slight modification of the item editor. Saving the quest, and reopening it somehow scrambled the data. I'm not sure how, at this point. As soon as the quest is saved, the data is corrupted, so I'm, rolling back again to beta 30.

(The beta 30 sources are stable.)

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

I rolled it back to 30, which still compiled and ran with no issues (packfile saving of the new array is disabled).

I tried reintroducing your changes, this time moving the loading sequence a bit farther down the line. No difference.

You should probably see the result for yourself.

Here's Beta 33, which has your suggested changes implemented:

http://timelord.insomnia247.nl/zc/zc_dev/ZC_2.54_Sources_Beta_33_Packfile_Issues.zip

Can you take a fresh working version and add in a single simple write and read to get the hang of binary file IO?

For example: Write out an array of 10000 values "[] = { 0,1,2,3,4,5,6,7,8,9, ... }" , then read it back in and print it out. If you don't feel like using a debugger properly then you simply /have/ to generate some output that can help you find out what you are doing wrong.

Gleeok wrote:Can you take a fresh working version and add in a single simple write and read to get the hang of binary file IO?

For example: Write out an array of 10000 values "[] = { 0,1,2,3,4,5,6,7,8,9, ... }" , then read it back in and print it out. If you don't feel like using a debugger properly then you simply /have/ to generate some output that can help you find out what you are doing wrong.

I may have found my answer without changing to VS... I'm not sync'd with the tables n defdata.cpp. It felt as if there was a third element to this, and there surely is. Thus might account for values shifting like this; eh? From what I can tell, the new data insertion is offsetting te vales by 10, resulting in reading the defaults from the wrong locations.

What would be the right way to insert the new array into this table?
I suppose I could just revert to a larger size for Defense instead now, though.

    
// flags flags2 tile width, height s_tile s_width s_height etile e_width e_height hp family cset anim e_anim, frate e_frate dp wdp weapon rate hrate step homing grumble item_set misc1 misc2 misc3 misc4 m5 m6 m7 m8 m9 m10 m11 m12 m13 m14 m15 bgsfx bosspal extend
{ 0x00000001, 0x00000000, 85, 1, 0, 0, 0, 0, 85, 1, 1, 2, eeGUY, 8, aNONE, aNONE, 0, 0, 1, 1, wNone, 0, 0, 0, 0, 0, isNONE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 0, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, 0, WAV_EDEAD, },

Didn't change much. Until I set up the other laptop, this may need to wait, unless someone else on the team wants to muck with it.

Is there any other file in which this type of thing is set? Perhaps somewhere in the quest header definitions?

The tables have nothing to do with corrupted data though.

Have a look at some specs for the c language aggregate initialization rules: https://msdn.microsoft.com/en-us/library/81k8cwsz.aspx

The scriptdefense array at the end will be zero initialized.

[edit] Also, I have to ask it, (sorry if it seems obvious to you, just trying to help) not trying to sound like a ass or anything: Without properly reading the version correctly you'll never be able to read/write a quest file without it becoming corrupted. This is because without it you introduce a "chicken and egg" logic bug regardless. The only way around this is to compile two versions, one for saving and one for loading.

Gleeok wrote:The tables have nothing to do with corrupted data though.

Have a look at some specs for the c language aggregate initialization rules: https://msdn.microsoft.com/en-us/library/81k8cwsz.aspx

The scriptdefense array at the end will be zero initialized.

I was lookin at comments like this, and I wasn't sure if that dat table needed me to reserve the space; as this is the case for many entries, even with zero'd fields.

bool reset_guys()
{
// The .dat file's guys definitions are always synchronised with defdata.cpp's - even the tile settings.
init_guys(V_GUYS);
return true;
}

Things like this tend to make me consider that proper synchronisation is mandatory at all times, and that the fields are explicitly prepared.

[edit] Also, I have to ask it, (sorry if it seems obvious to you, just trying to help) not trying to sound like a ass or anything: Without properly reading the version correctly you'll never be able to read/write a quest file without it becoming corrupted. This is because without it you introduce a "chicken and egg" logic bug regardless. The only way around this is to compile two versions, one for saving and one for loading.

No, that's something that I need to know. Could you expand on that, and specify: By version, do you mean the defined ZC version, V_GUYS, or something else? Have I done this somewhere, that you have observed?

Tell me this though: Why is expanding the enum with defLAST alone enough to corrupt this, when everything that thie packfile and editor generation code does relies on s size read fro this entry's placement?

If I add defs to the enum before edefLAST, and compile, with no other changes, the corruption still occurs. Is there anything with an explicit size that I missed? i simply fail to believe that the code can't resize itself around this, unless it's because it is shifting the values and the code isn't adaptive enough to comply. Even so, if it shifts the values, I'd expect it to mismatch when reading another quest, not the quest in memory, which is what led me to believe that the default values from defdata were involved.

Also, you said that the latest guyversion is 24, but in zdefs, it was 24 without my intervention.

Sure. You add an extra 10 byte array and read an older quest-> guy 0 gets loaded fine, guy 1 gets offset 10 bytes and is garbage, guy 2 gets offset 20 bytes and is garbage, guy 3 gets offset 30 bytes and is garbage. The old quest file here is the chicken, and the new format is the egg. You have to be able to load the chicken into the egg here. Without knowing that the quest file is a chicken you're just shoving an egg up the chicken's ass and turning a chicken into an egg by unnatural means, and then hilarity ensues as you have a messed up looking chicken that's bleeding all over your couch screaming in pain. You then beat it to death with a bat and try to figure out what's wrong with the chicken, but you can't. Make sense? 😊

Moral of the story: Don't @#$% your chickens before they hatch. :P

Gleeok wrote:Sure. You add an extra 10 byte array and read an older quest-> guy 0 gets loaded fine, guy 1 gets offset 10 bytes and is garbage, guy 2 gets offset 20 bytes and is garbage, guy 3 gets offset 30 bytes and is garbage. The old quest file here is the chicken, and the new format is the egg. You have to be able to load the chicken into the egg here. Without knowing that the quest file is a chicken you're just shoving an egg up the chicken's ass and turning a chicken into an egg by unnatural means, and then hilarity ensues as you have a messed up looking chicken that's bleeding all over your couch screaming in pain. You then beat it to death with a bat and try to figure out what's wrong with the chicken, but you can't. Make sense? 😊

Moral of the story: Don't @#$% your chickens before they hatch. :P

Fantastic Analogy
Well played

Gleeok wrote:Sure. You add an extra 10 byte array and read an older quest-> guy 0 gets loaded fine, guy 1 gets offset 10 bytes and is garbage, guy 2 gets offset 20 bytes and is garbage, guy 3 gets offset 30 bytes and is garbage. The old quest file here is the chicken, and the new format is the egg. You have to be able to load the chicken into the egg here. Without knowing that the quest file is a chicken you're just shoving an egg up the chicken's ass and turning a chicken into an egg by unnatural means, and then hilarity ensues as you have a messed up looking chicken that's bleeding all over your couch screaming in pain. You then beat it to death with a bat and try to figure out what's wrong with the chicken, but you can't. Make sense? 😊

Oh, I know what's causing the offset. That's obvious. What I don't comprehend, is why when the loader reads the size of the defense array from the same place as the saver, why this occurs. Do I need to define a new guysversion for both sides, and load the new stuff only if guysversion is > N; because the editor panel doesn't do that at all for anything.

If I can't sort this, is it something you'd be willing to fix so that I have a basis of comparison on what you did?

Moral of the story: Don't @#$% your chickens before they hatch. :P

Gleeok wrote:Oh, sweet dear little baby infant Jesus.....

Please, please, pleeeease, be extremely careful when changing packfile formats. Even I go into "serious mode" when doing anything with that file.

This exactly.

There is unfortunately nothing "automatic" about the quest file format. The procedure for adding a field to the quest file is

1. Increment the appropriate section version number
2. Write the save code. Ensure you use the right packfile write command (bit length, endianness, etc) for the type of data you're trying to save.
3. In the quest loading code (in qst.cpp) in the place where you want to read in the new data, add a check for the section version number
- if it's less than the new version number, do NOT attempt to read the new data, but set the values for the new field to some reasonable default instead;
-- IMPORTANT: you might need to do this in several places in the code. Here is some fairly typical code structure:


if(s_version <= 2.0)
{
// some code for loading legacy 1.90 quests
}
else
{
// a **huge** block of code for loading modern quests

if(s_version <= 6.0)
{
// some code for handling 2.10 quests
}
else
{
// another huge block

// here is where you want to read in your new field
}
}


You need to make sure you cover *all possible* code paths when reading in the quest, and set default values correctly for all cases. In the example above, you will have to add code to set defaults in at least three places. There have been dozens of bugs in the past due to the old quest loading code not being updated properly as new fields are added.
- otherwise, read in the data from the file (using a matching command to the write command, obviously).

Then you test the shit out of the code, on both old quests and newly-created ones. The best-case scenario for a bug here is massive corruption when you try to load old quests. The worst case is a subtle bug that corrupts a quest only when it is loaded and then re-saved in ZQuest, totally screwing any quest author who encounters the bug and doesn't have regular backups of their WIP (yes, we tell them not to work on major projects using betas or RCs, but...)

Gleeok wrote:Sure. You add an extra 10 byte array and read an older quest-> guy 0 gets loaded fine, guy 1 gets offset 10 bytes and is garbage, guy 2 gets offset 20 bytes and is garbage, guy 3 gets offset 30 bytes and is garbage. The old quest file here is the chicken, and the new format is the egg. You have to be able to load the chicken into the egg here. Without knowing that the quest file is a chicken you're just shoving an egg up the chicken's ass and turning a chicken into an egg by unnatural means, and then hilarity ensues as you have a messed up looking chicken that's bleeding all over your couch screaming in pain. You then beat it to death with a bat and try to figure out what's wrong with the chicken, but you can't. Make sense? 😊

Oh, I know what's causing the offset. That's obvious. What I don't comprehend, is why when the loader reads the size of the defense array from the same place as the saver, why this occurs. Do I need to define a new guysversion for both sides, and load the new stuff only if guysversion is > N; because the editor panel doesn't do that at all for anything.

I fixed it, anyway; so now everything works and I need to verify that older quests work properly, next.

For any-one who might be curious, this is what I did in qst.cpp:


if(guyversion > 24) // Add new guyversion conditional statement
{
for(int j=0; j<scriptDEFLAST; j++)
{
if(!p_getc(&(tempguy.scriptdefense[j]),f,keepdata))
{
return qe_invalid;
}
}
}
//Forward the value from old quests to the new attributes.
if(guyversion <= 24) // Offset the values intentionally?
{
for(int j=0; j<scriptDEFLAST; j++)
{
tempguy.scriptdefense[j] = tempguy.defense[edefSCRIPT] ;
}
}