It is currently Sat Dec 16, 2017 5:39 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 131 posts ]  Go to page Previous  1 ... 5, 6, 7, 8, 9  Next
Author Message
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Tue Sep 05, 2017 9:37 pm 
Offline
User avatar

Joined: Sat Jul 12, 2014 3:04 pm
Posts: 950
How is it generating stamps[STAMP_Y(i)]? The thing I suspect is happening is that that equality stops being true after a WORRIOR has moved one pixel up, so it tries to handle their movement as though normally in-bounds instead of walking into the playfield, and says "hey you're outside where you should be" and clips the WORRIOR's Y, causing the other 23 to happen all at once.

This would happen if you're doing a modulo-24 to get "what's the current cell", as one guess.

rainWORRIOR wrote:
The only thing that's maybe weird to me is if I press up just a little bit then stop, now pressing either left or right will move me upwards until the next grid, which feels a little weird, but maybe not something that needs to be addressed at all. (It's easy to learn this quirk, and it resolves itself pretty quickly anyway.)
I guess he took my suggestion.


Last edited by Myask on Tue Sep 05, 2017 10:25 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Tue Sep 05, 2017 10:20 pm 
Offline

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 98
The macros that generate the appropriate data are here:

Code:
/**
 * 8 objects on screen, two players and 6 enemies.
 */
#define STAMP_NUM_FIELDS     9                    // Number of fields in each stamp slot
#define STAMP_NUM_SLOTS      8                    // Number of slots in stamp structure
#define STAMP_CENTER_BIAS_X  12                   // Offset to apply to box multiply to center sprite (X)
#define STAMP_CENTER_BIAS_Y  10                   // Offset to apply to box multiply to center sprite (Y)

#define RADAR_SPR_OFFSET_X   88                   // Radar sprite top-left offset X
#define RADAR_SPR_OFFSET_Y   176                  // Radar sprite top-left offset Y

#define STAMP_NUM(x)         (x*STAMP_NUM_FIELDS) // Stamp Number
#define STAMP_X(x)           (STAMP_NUM(x)+0)     // Stamp Field: X pixel position
#define STAMP_Y(x)           (STAMP_NUM(x)+1)     // Stamp Field: Y pixel position
#define STAMP_TYPE(x)        (STAMP_NUM(x)+2)     // Stamp Field: Type
#define STAMP_STATE(x)       (STAMP_NUM(x)+3)     // Stamp Field: state (which frames to use).
#define STAMP_LAST_STATE(x)  (STAMP_NUM(x)+4)
#define STAMP_FRAME(x)       (STAMP_NUM(x)+5)     // Stamp Field: Current frame
#define STAMP_DELAY(x)       (STAMP_NUM(x)+6)     // Stamp Field: Delay
#define STAMP_XTRA_A(x)      (STAMP_NUM(x)+7)     // Stamp Field: Extra A (Player Timer)
#define STAMP_XTRA_B(x)      (STAMP_NUM(x)+8)     // Stamp Field: Extra B (Player Pad Data)

#define PLAYER_PAD(x)        (stamps[STAMP_XTRA_B(x)])    // Alias for reading stored player pad value.
#define PLAYER_PAD_RIGHT(x)  (PLAYER_PAD(x)&1<<0) // is player pressing right?
#define PLAYER_PAD_LEFT(x)   (PLAYER_PAD(x)&1<<1) // is player pressing left?
#define PLAYER_PAD_DOWN(x)   (PLAYER_PAD(x)&1<<2) // is player pressing down?
#define PLAYER_PAD_UP(x)     (PLAYER_PAD(x)&1<<3) // is player pressing up?
#define PLAYER_PAD_IDLE(x)   (PLAYER_PAD(x)==0x00)      // is player idle?

#define PIXEL_BOX_X(x)       ((x*24)+STAMP_CENTER_BIAS_X)             // Convert Box X coordinates to pixels
#define PIXEL_BOX_Y(x)       ((x*24)+STAMP_CENTER_BIAS_Y)             // Convert Box Y coordinates to pixels
#define BOX_PIXEL_X(x)       (div24(x-STAMP_CENTER_BIAS_X))           // Convert Stamp X coordinates to Box X
#define BOX_PIXEL_Y(x)       (div24(x-STAMP_CENTER_BIAS_Y))           // Convert Stamp Y coordinates to Box Y

#define STAMP_X_TO_RADAR(x)  RADAR_SPR_OFFSET_X+BOX_PIXEL_X(x)*8          // Convert box position to radar sprite position
#define STAMP_Y_TO_RADAR(x)  RADAR_SPR_OFFSET_Y+BOX_PIXEL_Y(x)*8          // Convert box position to radar sprite position

#define BOX_WALL_RIGHT(x)    (x&1<<4)            // Box has right wall
#define BOX_WALL_DOWN(x)     (x&1<<5)            // Box has down wall
#define BOX_WALL_LEFT(x)     (x&1<<6)            // Box has left wall
#define BOX_WALL_UP(x)       (x&1<<7)            // Box has up wall


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Tue Sep 05, 2017 10:30 pm 
Offline
User avatar

Joined: Sat Jul 12, 2014 3:04 pm
Posts: 950
if handle_player_in_box(); is supposed to handle the entire walk out of the box, it's not got the right condition on it; it should be something more like if (stamps[STAMP_Y(i)]>PIXEL_BOX_Y(5)) (with a +1 in there on the RHS if ejection is how you handle walls rather than prevention)


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Tue Sep 05, 2017 10:32 pm 
Offline

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 98
handle_player_in_box is the routine that handles when the player is about to be ejected onto the playfield (with the countdown).

handle_player_in_field is used for everything else.

I may rename the former routine, if I can think of a better name for it... I was thinking "penalty box" like hockey :P ;)

-Thom


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Tue Sep 05, 2017 10:39 pm 
Offline

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 98
to expand a bit, the macro PIXEL_BOX_Y takes a box # and converts it to a pixel offset (for sprite coordinates). Y=6 is a special box location that is only shared by the two penalty boxes.

STAMP_X and STAMP_Y are sprite pixel coordinates.


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Tue Sep 05, 2017 10:56 pm 
Offline

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 98
other bits of interesting code, handle_pad_idle() which handles when player motion stops:

Code:
/**
 * handle_pad_idle()
 */
void handle_pad_idle(void)
{
  // Change to idle state if pad is idle.
  switch(stamps[STAMP_LAST_STATE(i)])
    {
    case STATE_PLAYER_RIGHT:
      stamps[STAMP_STATE(i)]=STATE_PLAYER_RIGHT_IDLE;
      break;
    case STATE_PLAYER_LEFT:
      stamps[STAMP_STATE(i)]=STATE_PLAYER_LEFT_IDLE;
      break;
    case STATE_PLAYER_UP:
      stamps[STAMP_STATE(i)]=STATE_PLAYER_UP_IDLE;
      break;
    case STATE_PLAYER_DOWN:
      stamps[STAMP_STATE(i)]=STATE_PLAYER_DOWN_IDLE;
      break;
    }
}


and handle_player_in_box():

Code:
/**
 * handle_player_in_box()
 * Handle when player is in box.
 */
void handle_player_in_box(void)
{
  if (stamps[STAMP_XTRA_A(i)]>0)
    {
      if (stamps[STAMP_XTRA_B(i)] != 0)
        {
          stamps[STAMP_XTRA_A(i)]=0;
        }
      else
        {
          stamps[STAMP_Y(i)]=PIXEL_BOX_Y(6)-1; // 6 is the Y for the box.
          if (sec==0) // 0 means approximately 1 second elapsed.
            stamps[STAMP_XTRA_A(i)]--;         // Decrement timer
        }
    }
  else
    {
      stamps[STAMP_Y(i)]=PIXEL_BOX_Y(5); // Pop out of box.
      if (i==0)
        {
          yellow_door_state=CLOSED;
        }
      else
        {
          blue_door_state=CLOSED;
        }
    }
}


sec is a variable that simply counts from 49 to 0 (I am using shiru's drop-frame consistent PAL tick rate).

get_current_box() is a function that sets a quad of variables, a,b,c,d:

Code:
/**
 * get_current_box()
 * Get the current dungeon box for player
 * i = the stamp to return in a,b,c,d
 * a = the X box
 * b = the Y box
 * c = the dungeon box #
 * d = the box data.
 */
void get_current_box(void)
{
  a=div24(stamps[STAMP_X(i)]+8);
  b=div24(stamps[STAMP_Y(i)]+8);
  c=(b*10)+a; // C is now the box #
  d=dungeon[c];
  score1[0]=div24(stamps[STAMP_X(0)]+8)+1;
  score1[1]=div24(stamps[STAMP_Y(0)]+8)+1;
}


These are then used for collision detection. Since the whole maze is on a grid, and everything is bound to move along that grid, full bounding box collision detection is unnecessary for traversing the maze. (player to player/enemy detection will be another story)

I will also change the move_monsters() code to utilize the same code (with the exception that directions will be picked randomly), so that monster movement isn't so pedestrian. (Right now, monster movement is very rank and file).

It will also make computer AI easier, as all it needs to do is pick the closest monster, and attempt a straight line to it, while shooting when it's in the same lateral position on the grid.

Yes, I KNOW this code is really weird. I've never written C code that uses this many globals or goto's (and I've written CODECs!)... but you can't really write clean C code for a 6502 and have it fit or be somewhat efficient.

-Thom


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Tue Sep 05, 2017 11:14 pm 
Offline
User avatar

Joined: Sat Jul 12, 2014 3:04 pm
Posts: 950
oh, so the WORRIOR *is* supposed to instantly pop out of the box into the middle of the adjacent map cell? I thought they were supposed to walk in.


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Tue Sep 05, 2017 11:24 pm 
Offline

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 98
Myask wrote:
oh, so the WORRIOR *is* supposed to instantly pop out of the box into the middle of the adjacent map cell? I thought they were supposed to walk in.


You can witness the behavior by watching the arcade longplays on YouTube.

-Thom


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Wed Sep 06, 2017 9:17 am 
Offline
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 2983
Location: Tampere, Finland
tschak909 wrote:
Code:
#define STAMP_NUM(x)         (x*STAMP_NUM_FIELDS) // Stamp Number

Side note: It's a good idea to get into habit of adding extra parenthesis around macro variables:
Code:
#define STAMP_NUM(x)         ((x)*STAMP_NUM_FIELDS) // Stamp Number

Otherwise you can run into really nasty bugs with things like STAMP_NUM(1+2) (expands to 1+2*STAMP_NUM_FIELDS).

_________________
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: kkfos.aspekt.fi


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Wed Sep 06, 2017 9:56 am 
Offline

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 98
Ah yes, good idea. :)

-Thom


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Fri Sep 08, 2017 10:40 pm 
Offline

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 98
Still debugging the glitch that Kasumi found, this one is a quantum bug, as it hides when being explicitly observed! :P

It's definitely a problem, and I'm suspecting that my i variable is being reset intermittently (and I mean very infrequently, I have yet to find a consistently reproducible pattern that causes this behavior!)

-Thom


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Sat Sep 09, 2017 9:23 pm 
Offline

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 98
Narrowed it down to the following bit of conditions:

* pressing up or down
* in a horizontal corridor (last state = left | right)
* state goes from not aligned to aligned

this one is weiird. I wonder what i'm doing to cause this funkiness?

-Thom


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Mon Sep 11, 2017 2:18 pm 
Offline
User avatar

Joined: Sat Jul 12, 2014 3:04 pm
Posts: 950
tschak909 wrote:
Myask wrote:
oh, so the WORRIOR *is* supposed to instantly pop out of the box into the middle of the adjacent map cell? I thought they were supposed to walk in.


You can witness the behavior by watching the arcade longplays on YouTube.

-Thom
Having looked at such…
The arcade game slides the WORRIOR into the playfield over ~0.1s (at least, 3 @youtube's 30FPS*, each with a new interpolated Y-value, so 6 frames on NTSC NES). Your version does not; it waits three frames after an input and then instantly moves the WORRIOR from inside the bullpen to the adjacent maze square.


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Mon Sep 11, 2017 11:08 pm 
Offline

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 98
Noted. I will try to refine this once I figure out WTF is going on with player 2 affecting player 1 motion.

-Thom


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Sat Sep 16, 2017 3:08 pm 
Offline

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 98
To anyone here, could use a second pair of eyes.

Man, this is bonkers, have been trying to debug the errant motion, and while I can reproduce it, I can't narrow down the errant code...

(for reference, code is here: http://github.com/tschak909/wow.git)

If I do a diagonal motion, then the moment that I enter alignment into a given box, the yellow player will turn and idle in the selected vertical direction. This is downright goofy, as I do not modify the current player index at any point inside the loop, and yet, somehow i becomes 0 even when i is 1, and suddenly snaps back to 1.

I know this is because I am abusing globals, I'm trying to keep code generation down by not putting things in the stack frame...

-Thom


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 131 posts ]  Go to page Previous  1 ... 5, 6, 7, 8, 9  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 4 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group