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

Screen->LoadNPC() bug

21 replies · 4,890 views · Started 09 January 2007

I have a script that gets the number of NPCs on the screen, then loops through them changing their X values but only the first one is affected. Here is an example:

int NumNPCs = Screen->NumNPCs();
int i;
npc CurNPC;
for (i=0; i < NumNPCs; i++)
{
CurNPC = Screen->LoadNPC(i);
CurNPC->X = 100;
}

This will only change the X position of the first NPC, even when many are on screen. The NPCs were created with the "Enemies" menu for the screen, not through script.

Ok I wrote a small test script for this bug. I made a single room with 3 bats in it and this script should make the bats move along the x-axis (but not the y-axis) and wrap around the screen. It works fine for the first bat but has no effect on the other 2 (or more). Am I doing something wrong or is this really a bug (and no this is not the real use, just a test case😊 ?

ffc script testNPC1
{

void run()
{
npc CurNPC;
int i;
while (true)
{
int NPC_Cnt = Screen->NumNPCs();
for (i=0; i < NPC_Cnt; i++)
{
CurNPC = Screen->LoadNPC(i);
CurNPC->X++;
if ( CurNPC->X > 256 ) { CurNPC->X = 0; }
CurNPC->Y = 128;
}
Waitframe();
}
}

}

There's a similar problem with FFCs: scripts only seem to affect FFC #1.
It seems REFNPC and REFFFC are both stuck at 0. That's definitely a bug.

Also, blue knight, if you post your scripts inside [code] tags, it'll preserve the indentation.

not sure about REFFFC, as that seems to work correctly. However, the REFNPC thing is a bug. it's fixed.

Thanks for the response. Will the fix be available in B17 or is there a 16c planned (with this fix and the drawcombo/tile fix hopefully 😊 ? And Saffith, thanks for the tip about the code tags, I'll definitely keep that in mind.

Saffith wrote:It does? Damn. Something is making scripts only affect FFC #1. Must be something else, I guess...

Whatever it is appears to be limited to use of the "this->" variable. If you explicitly define a new ffc, say "this_ffc", and use this_ffc instead of this, everything is great. It sounds like even that isn't working for NPCs.

No, this one's different. Scripts all run as though they were attached to FFC #1. So if, for example, you put a ChaserTrap script on FFC 1 and a Vacuum script on FFC 2, FFC 1 will both suck Link toward it and dash at him, and #2 will do nothing at all.
I haven't tried using C-Dawg's method, though.

It's not quite as simple as I thought, though. Hoping to find a simpler example, I used these:

ffc script Test1
{
void run()
{
while(true)
{
this->X+=2;
Waitframe();
}
}
}

ffc script Test2
{
void run()
{
while(true)
{
this->X-=1;
Waitframe();
}
}
}

I was expecting that to make FFC 1 move one pixel to the right each frame, but it actually worked exactly as it should have.

Saffith, I bet if you changed the code to this, you would recreate the errors:


ffc script Test1
{
void run()
{
while(true)
{
this->X=this->X+2
Waitframe();
}
}
}

ffc script Test2
{
void run()
{
while(true)
{
this->X=this->X-1;
Waitframe();
}
}
}

Check it out.

The script I posted above, which before would only affect the first NPC, now crashes zelda-w.exe when it starts on a screen with more then 1 enemy.

I did some more testing: if have call LoadNPC(0), no matter how many NPCs are on screen, it'll crash. If there is 1 or more enemies, you can call LoadNPC(1) with no crash but changing the values doesn't actually do anything to the on-screen NPC. So it appears that the old bug is still there but now it crashes if you access an on-screen NPC (which happens to only be 0 due to the other bug).

Ok here's the ZScript code again:


ffc script npc_test1
{
void run()
{
npc CurNPC;
while (true)
{
int NPC_Cnt = Screen->NumNPCs();
int i;
if ( NPC_Cnt > 0 )
{
for (i=0; i < NPC_Cnt; i++)
{
CurNPC = Screen->LoadNPC(i);
CurNPC->X++;
if ( CurNPC->X > 256 ) { CurNPC->X = 0; }
CurNPC->Y = 128;
}
}
Waitframe();
}
}
}

Ok here's the ZASM code:


npc_test1
SETV d2,0
SETR d3,REFFFC
PUSHR d3
PUSHR d2
PUSHR d2
PUSHR d2
SETR d4,SP
SETR d6,d4
ADDV d6,3
SETV d2,0
STOREI d2,d6
SETV d2,0
SETV d2,0.0001
COMPAREV d2,0
GOTOTRUE 178
PUSHR d4
SETV d2,22
PUSHR d2
SETR d2,gd0
PUSHR d2
GOTO 187
POP d4
SETR d6,d4
ADDV d6,2
STOREI d2,d6
SETR d6,d4
ADDV d6,1
SETV d2,0
STOREI d2,d6
SETR d6,d4
ADDV d6,2
LOADI d2,d6
PUSHR d2
SETV d2,0
POP d3
COMPARER d3,d2
GOTOMORE 40
SETV d2,0
GOTO 44
GOTOFALSE 43
SETV d2,0
GOTO 44
SETV d2,0.0001
SETV d3,0
COMPAREV d2,0
GOTOTRUE 171
SETV d2,0
SETR d6,d4
ADDV d6,1
STOREI d2,d6
SETV d2,0
SETR d6,d4
ADDV d6,1
LOADI d2,d6
PUSHR d2
SETR d6,d4
ADDV d6,2
LOADI d2,d6
POP d3
COMPARER d3,d2
GOTOLESS 64
SETV d2,0
GOTO 68
GOTOFALSE 67
SETV d2,0
GOTO 68
SETV d2,0.0001
SETV d3,0
COMPAREV d2,0
GOTOTRUE 170
PUSHR d4
SETV d2,81
PUSHR d2
SETR d2,gd0
PUSHR d2
SETR d6,d4
ADDV d6,1
LOADI d2,d6
PUSHR d2
GOTO 192
POP d4
SETR d6,d4
ADDV d6,3
STOREI d2,d6
PUSHR d4
SETV d2,93
PUSHR d2
SETR d6,d4
ADDV d6,3
LOADI d2,d6
PUSHR d2
GOTO 197
POP d4
PUSHR d2
ADDV d2,1
PUSHR d4
SETV d3,107
PUSHR d3
PUSHR d2
SETR d6,d4
ADDV d6,3
LOADI d2,d6
POP d3
PUSHR d2
PUSHR d3
GOTO 202
POP d4
POP d2
PUSHR d4
SETV d2,117
PUSHR d2
SETR d6,d4
ADDV d6,3
LOADI d2,d6
PUSHR d2
GOTO 197
POP d4
PUSHR d2
SETV d2,256
POP d3
COMPARER d3,d2
GOTOMORE 125
SETV d2,0
GOTO 129
GOTOFALSE 128
SETV d2,0
GOTO 129
SETV d2,0.0001
SETV d3,0
COMPAREV d2,0
GOTOTRUE 145
SETV d2,0
PUSHR d4
SETV d3,144
PUSHR d3
PUSHR d2
SETR d6,d4
ADDV d6,3
LOADI d2,d6
POP d3
PUSHR d2
PUSHR d3
GOTO 202
POP d4
SETV d2,0
SETV d2,128
PUSHR d4
SETV d3,158
PUSHR d3
PUSHR d2
SETR d6,d4
ADDV d6,3
LOADI d2,d6
POP d3
PUSHR d2
PUSHR d3
GOTO 208
POP d4
SETV d3,0
SETR d6,d4
ADDV d6,1
LOADI d2,d6
PUSHR d2
ADDV d2,1
SETR d6,d4
ADDV d6,1
STOREI d2,d6
POP d2
GOTO 51
SETV d3,0
SETV d2,0
PUSHR d4
SETV d2,176
PUSHR d2
GOTO 184
POP d4
GOTO 12
SETV d2,0
SETV d3,0
POP d3
POP d3
POP d3
QUIT
WAITFRAME
POP d3
GOTOR d3
POP d3
SETR d5,d3
SETR d2,NPCCOUNT
POP d3
GOTOR d3
POP d2
POP d5
SUBV d2,1
POP d3
GOTOR d3
POP d3
SETR REFNPC,d3
SETR d2,NPCX
POP d3
GOTOR d3
POP d2
POP d3
SETR REFNPC,d3
SETR NPCX,d2
POP d3
GOTOR d3
POP d2
POP d3
SETR REFNPC,d3
SETR NPCY,d2
POP d3
GOTOR d3

Okay, good news, it isn't a bug. Bad new, I misinformed you. LoadNPC is indeed 1-based, with 1 referring to the first enemy, and so on and so forth :/

Well that is more consistent with FFCs which I KNOW are 1 based, I use LoadFFC() alot for my scrolling script (which is actually why I need this to work, you can probably guess why😊

Edit - I just testing it in my original script (the sidescrolling one which will now have support for properly scrolling enemies!) and everything works great, thanks for the fix and info.

You're right, I should have pointed out the documented behavior instead of blindly accepting what jman was saying. However everyone makes mistakes 😊 As for the benign action, I would recommend a compile error on LoadNPC(0) (and LoadFFC(0) for that matter). While this won't find the case of using a variable (although you could look at range of the variable when used in a loop), atleast when you try it by itself you'll see the error. Otherwise just output a Trace()-like message to the log and do nothing.

Starting in the next beta, ZC should print an error message to allegro.log instead of crashing when you try to reference an illegal NPC.