Jump to content

Recommended Posts

Where is the program counter when it crashes? If its "off in the weeds" that can be difficult to track down without enabling instruction tracing.

 

The 8 bit variable has a 16 bit number added to it (could that be LVLP?) and that is used for the screen pointer (from what I recall of the game's disassembly).

I was thinking the 8 bit variable might have been the variable I was using for the color of the Landership. I originally had it as LNDC=CS_Tan and then changed it to #LNDC=CS_Tan, but was having the same problem.

 

I'll be honest, as I'm still a rookie at programming, my troubleshooting has been looking at the code and trying to find what I did wrong based on symptoms. When you talk about the "Program Counter" is that something that I would find in the Dump file?

 

The symptom is that during round 3 , after playing for a little while, the game starts to lag. Then the Landership and Player Lives Counter start to scramble. Then it slows to a stop and crashes. Sometimes if I let my ship be destroyed, it would fix it temporarily, but that doesn't always work. In some cases I could get through round 3 and it would crash during round 4. It almost seems like it could be a bit of a log jam. Like there are too many things happening at once and it crashes.

I was thinking the 8 bit variable might have been the variable I was using for the color of the Landership. I originally had it as LNDC=CS_Tan and then changed it to #LNDC=CS_Tan, but was having the same problem.

Without looking at the disassembly again, and correlating that to the variables used in the game's *.lst file, I can't tell.

 

I'll be honest, as I'm still a rookie at programming, my troubleshooting has been looking at the code and trying to find what I did wrong based on symptoms. When you talk about the "Program Counter" is that something that I would find in the Dump file?

When the game crashes in jzintv (using the command line) it gives you some information. Part of that info is the Program Counter (PC), and the type of crash e.g. "off in the weeds", "HALT" etc.

 

When jzintv crashes (when used at the command line) it will give you some information. The Program Counter (PC) is part of that info.

The symptom is that during round 3 , after playing for a little while, the game starts to lag. Then the Landership and Player Lives Counter start to scramble. Then it slows to a stop and crashes. Sometimes if I let my ship be destroyed, it would fix it temporarily, but that doesn't always work. In some cases I could get through round 3 and it would crash during round 4. It almost seems like it could be a bit of a log jam. Like there are too many things happening at once and it crashes.

Without taking a look at the game's source code I can't suggest anything sensible.

Add STACK_CHECK anywhere in your code. Your stack may be overflowing causing behavior problem. There is 25 16-bit variable reserved to stack. This detection will check if 25th slot stack have been filled. If so, it'll freeze the game and write stack overflow to the top of the screen.

 

I made a code that will dump the content of the stack on to your screen. Have something like if cont.key=9 then goto debug to trigger the code below.

debug:
sprite 0,0,0,0
sprite 1,0,0,0
sprite 2,0,0,0
sprite 3,0,0,0
sprite 4,0,0,0
sprite 5,0,0,0
sprite 6,0,0,0
sprite 7,0,0,0

#debug=peek($2f0)
print at 20+0 color 2,<5> #debug

#debug=peek($2f1)
print at 20+7 color 2,<5> #debug

#debug=peek($2f2)
print at 20+14 color 2,<5> #debug

#debug=peek($2f3)
print at 40+0 color 2,<5> #debug

#debug=peek($2f4)
print at 40+7 color 2,<5> #debug

#debug=peek($2f5)
print at 40+14 color 2,<5> #debug

#debug=peek($2f6)
print at 60+0 color 2,<5> #debug

#debug=peek($2f7)
print at 60+7 color 2,<5> #debug

#debug=peek($2f8)
print at 60+14 color 2,<5> #debug

#debug=peek($2f9)
print at 80+0 color 2,<5> #debug

#debug=peek($2fa)
print at 80+7 color 2,<5> #debug

#debug=peek($2fb)
print at 80+14 color 2,<5> #debug

#debug=peek($2fc)
print at 100+0 color 2,<5> #debug

#debug=peek($2fd)
print at 100+7 color 2,<5> #debug

#debug=peek($2fe)
print at 100+14 color 2,<5> #debug

#debug=peek($2ff)
print at 120+0 color 2,<5> #debug

#debug=peek($300)
print at 120+7 color 2,<5> #debug

#debug=peek($301)
print at 120+14 color 2,<5> #debug

#debug=peek($302)
print at 140+0 color 2,<5> #debug

#debug=peek($303)
print at 140+7 color 2,<5> #debug

#debug=peek($304)
print at 140+14 color 2,<5> #debug

#debug=peek($305)
print at 160+0 color 2,<5> #debug

#debug=peek($306)
print at 160+7 color 2,<5> #debug

#debug=peek($307)
print at 160+14 color 2,<5> #debug


#debug=peek($308)
print at 187 color 6,<5> #debug

halt:
goto halt

If your stack is overflowing, then you're jumping your code out of a gosub routine. Don't use goto to jump out of procedure. So check for that and make sure your code is returning from the sub-routine.

Groovybee, by no means am I expecting you to chase this down for me, but if you or anyone else wants to look at the .BAS file, I've attached it here.

 

I hope all experienced programmers will be able to be able to hold back their laughter when they see this rat's nest that I call game code. :)

 

 

Kiwi, I just saw your post. Thank you for that. I'll give it a try and see what I find.

inv30E.bas

Edited by dalves

I made a code that will dump the content of the stack on to your screen.

Interesting approach. A better approach would be to enter the jzintv debugger by hitting F4, and then type "m $2F0" (without quotes and pressing enter at the end) at the debugger's prompt in order to see the contents of the memory.

Lines 1176-1178 in PLAYHIT

	IF #LIVES=0 THEN GOTO END
	IF PHB=1 THEN PHB=0:GOTO GAME
	IF PHB=2 THEN PHB=0:LNDAX=80:LNDBX=88:LNDAY=0:LNDBY=0:LNDSP=20:GOTO INTRO
Is jumping out of the procedure.

 

Interesting approach. A better approach would be to enter the jzintv debugger by hitting F4, and then type "m $2F0" (without quotes and pressing enter at the end) at the debugger's prompt in order to see the contents of the memory.

I used jzintvlauncher to boot jzintv. For some reason, the -d made jzintv refuse to run. So this is my work around seeing the stack. Indeed I was jumping out of the procedure every time I died. After dying 14+ times, it cause the arrow and other 16-bit variable objects act to funny because the stack content it in it place.

Edited by Kiwi

I had originally had the PLAYHIT: segment as a destination for a GOTO statement triggered by the collision detection. I then changed it to a Gosub command and had a problem with it crashing in all emulators. I changed it back to a GOTO statement, but obviously forgot to remove the Procedure and End from the PLAYHIT segment. I'll try that and see if it helps. Thanks a bunch for seeing that.

  • Like 1

I used jzintvlauncher to boot jzintv. For some reason, the -d made jzintv refuse to run.

jzintv should drop to the command line at that point. You need to enter "r" (without quotes and ending with enter) to start the game.

  • Like 1

I had originally had the PLAYHIT: segment as a destination for a GOTO statement triggered by the collision detection. I then changed it to a Gosub command and had a problem with it crashing in all emulators. I changed it back to a GOTO statement, but obviously forgot to remove the Procedure and End from the PLAYHIT segment. I'll try that and see if it helps. Thanks a bunch for seeing that.

Ideally, GOTOing out of a PROCEDURE should be flagged by IntyBASIC as an error.

  • Like 1

I suppose there could be cases when you have two subroutines, and depending on what is going on in one of them, you might want to jump into the other subroutine and exit from there. Quite a bit convoluted and hard to follow, but a warning perhaps. To have the compiler follow the source code to see if your subroutine ever exits would be beyond the scope of a compiler.

Kiwi, I used your code and it prints to the screen perfectly. As I am new to checking for stack overflow, what should I be looking for in the numbers that print to the screen?

 

When I ran the debug right before the crash every number slot had the same number which was something like 26124. When I searched my code for Goto statements, I apparently have several nested in Gosub routines. I thought I was mindful not to do that, but obviously I was sloppy. I'll clean that up this weekend and hopefully that will fix the crashing.

 

Thanks again to everyone for the help.

Edited by dalves

Yeah, the same number.

post-24767-0-66600600-1479508896_thumb.gif

For example, the red numbers are numbers from address $2F0-$307. This is the stack. $308 is the top of the deck. Your 16-bit variables are assigned at $309 and up.

 

The number 65535 are $FFFF, so they aren't being used. It may be a different number on the real console as I tested on LTO. The Yellow number is 00000. If this is a number other than 00000, it'll trigger the STACK_CHECK routine. If you see the same number in your stack that's not $FFFF, then your stack is growing. I actually tried to incorporated the routine once STACK_CHECK ran by copying the asm in the .asm to either the prologue or epilogue, it worked printed like 12 numbers but it crashed and closed the window before it printed the rest of the number. I probably did too much work in one frame.

I've got it up and running now. Works fine on JZINV, Nostalgia, and MESS. It seems like GOTOING out of PROCEDURE was the main cause of the problems. I still have some glitches with the score. Its been hard to confirm because I have to focus on keeping my ship alive. That said, I'm thinking it may be when my score hits 6 digits. The score seems to generate random number before it starts counting correctly again. Anyway, he's the latest ROM.

INV30C.rom

I've got it up and running now. Works fine on JZINV, Nostalgia, and MESS. It seems like GOTOING out of PROCEDURE was the main cause of the problems. I still have some glitches with the score. Its been hard to confirm because I have to focus on keeping my ship alive. That said, I'm thinking it may be when my score hits 6 digits. The score seems to generate random number before it starts counting correctly again. Anyway, he's the latest ROM.

 

Its common during game development for the game's coder to put in "god mode". It could be activated in debug code or from a magic key press or even from a menu option. Once in "god mode" you can enable infinite lives, have infinite time, skip levels etc (it all depends on your game). Adding such a mode to your own game you can see how it progresses and debug more complex features. It also comes in handy for the beta testers too.

  • Like 2

I've got it up and running now. Works fine on JZINV, Nostalgia, and MESS. It seems like GOTOING out of PROCEDURE was the main cause of the problems. I still have some glitches with the score. Its been hard to confirm because I have to focus on keeping my ship alive. That said, I'm thinking it may be when my score hits 6 digits. The score seems to generate random number before it starts counting correctly again. Anyway, he's the latest ROM.

 

When you invoke GOSUB, the processor jumps to a subroutine which then does the following:

  • Save the calling point address for return in the stack
  • Execute the code in the procedure
  • Pop the return address from the stack to return to where we started.

That's the magic of GOSUB. Be aware that it is not the GOSUB that actually uses the stack, it is the fact that you define a "PROCEDURE" and "END"; the compiler injects the "PUSH into stack" and "POP" out of stack automatically for you. invoking GOSUB just calls a subroutine that happens to save the return address in the stack. You can also leave early by invoking "RETURN," which will just pop the return address from the stack and return.

 

Therefore, the issue is in jumping out of the sub-routine without letting it get to the end or without invoking RETURN, like using GOTO. Although bad practice, that in itself is not really that critical. The problem really comes when you repeatedly call the same sub-routine and use a GOTO to exit it. It means that the return address is repeatedly pushed into the stack but never popped out, which consumes the stack until it blows.

 

Does this make sense?

 

 

 

 

Ideally, GOTOing out of a PROCEDURE should be flagged by IntyBASIC as an error.

 

At least a warning. I do that in Assembly to "chain call" routines as a pattern to improve execution performance. That said, I guess a case could be made that if you're using IntyBASIC, you should stick to the higher level pattern and avoid such tricks. In any case, the compiler should signal so that the programmer is made aware. Most of the time it is inadvertent.

 

-dZ.

Thanks for the suggestion Groovybee and for the explanation DZ. The way you described it makes a lot of sense to me.

 

Recently I've been curious about way to work around the 8 sprite on screen limitations. I was thinking about games like Space Armada, with rows of targets and wondered how those were done. I've seen the term of "sequencing GRAM" and wondered if that was similar to how I animated the side bar scrolling for my Worm War 1 game. If this is the case, I was wondering if anyone out there knows of any examples out there. I'm curious how you would draw a row of aliens with GRAM cards but be able to isolate each one as a target.

Hi dalves,

 

The trick of something like Space Armada (or Worm Whomper) is to cycle GRAM while painting the cards in the BACKTAB.

 

"GRAM cycling" or "sequencing" is just updating the visual state of a sprite by changing its GRAM card periodically. It is a technique that is used to animate sprites as well as simulate their movements across the BACKTAB.

 

First off, you should be aware of the trade offs:

* Each individual object will consume at least one GRAM card, possibly more.

 

* The BACKTAB resolution does not support "double-vertical resolution" like MOBs, so they may look a but chunkier.

 

* Additional overhead is incurred in accounting for transitions from one BACKTAB card to another.

 

Now, for the good stuff:

* you can have as many individual objects as necessary, and avoid the 8 MOB limitation.

 

* You can mix-and-match techniques and transition objects from MOBs to BACKTAB and vice-versa.

 

There are a few techniques. One technique is the one employed by Mattel Major League Baseball. In this technique, they use a MOB for moving the man around the screen, and then "park" him on the BACKTAB when at rest. This affords you all the flexibility and power of a MOB while moving, and allows you to move more than 8 objects provided you don't move more than 8 at a time. Every time you "unpark" an object, you reuse one of the MOBs. So you can "move then park" cycling through your objects and give the illusion that there are many moving objects, when in fact they are taking turns. This effect is rather simple to implement. The effort is then in keeping track of which objects are moving at any time, and in "parking" and "unparking" them.

 

Another technique is that employed by Space Armada: in that game, they don't move the objects at all, they actually scroll the screen horizontally! Each individual monster type gets one card in GRAM, which is animated periodically, individually. These GRAM cards are then used many times across the BACKTAB, giving the illusion that there are many objects when in fact it is only a handful of individual monsters repeated over and over. Then they keep track of the status of each BACKTAB cell individually, to see if a monster is there or it has been shot down. This technique is also easy to implement, but only supports static objects, or movement in unison by scrolling.

 

Yet a third technique is the one used in Worm Whomper. This is the most advanced and technically difficult, but also the most effective and versatile one. An object is allocated 1 card in GRAM per axis transition supported. That is, if your object will move horizontally or vertically and have the opportunity to straddle in between two adjacent BACKTAB cards, you need 2 GRAM cards. If your object can move up and down and left and right in straight lines but only at the center tile, you will need 3 GRAM cards (the base one, the one to straddle horizontally, and the one to straddle vertically), etc. The more cards it can overlap simultaneously, the more GRAM cards you need per object.

 

Since you cannot move a BACKTAB card, you simulate movement by animating the GRAM under that card. This involves pre-computing "shifted" positions of the graphic at each point within the tile. This is where the multiple GRAM cards come in: you also pre-compute the transition of moving in and out of the 8x8 cell and the transition between cards on each axis.

 

Keep in mind that if the object can "animate," you will also need to pre-compute the shifted positions of each animation frame. This eats lots of ROM, but that can be handled.

 

As an alternative to pre-computing, you could shift the frames as you move the object, but that takes much more processing time, which is typically in shorter supply than ROM space.

 

In this technique, you keep track of the object position on the screen as well as its position within cards (the offset within the 8x8 BACKTAB cell) and update the GRAM with the appropriate pre-computed shifted card. If the object is between cards, you must update all GRAM cards allocated for the axes of movement.

 

As the object reaches the edge of a card and is about to enter an adjacent one, you need to also update the BACKTAB data of the new card to point to the GRAM. You also need to keep track of each object individually, and deal with collisions yourself.

 

This requires quite a bit of processing, but you can generalize it all to re-use it per object. In the end, it can give the illusion that a great number of objects are moving simultaneously. Just take a look at Worm Whomper's frantic action.

 

dZ.

  • Like 2

Hi DZ, Thank you a TON for that description. It is really helpful in understanding the various ways you can work around some of the limitations.

 

The one thing I wondered about was how to do the collision detection with the Backtab. Still being kind of new at it, I'm used to the "IF Col(x) AND HIT_SPRITE(x)" form of collision detection. I have seen some examples of collision detection with the background. I wasn't sure if you would use a command similar to the sprite collision detection or if it would work more like sprite collision with the background, but you'll have to indicate certain Backtab locations where your "Target" would be.

I used software solution to do MOB vs Backtab collision.

charx=(arrowX-4)/8
chary=(arrowY-4)/8

Mcard=PEEK($200+charx+chary*20)
Mcard=Mcard/8

if Mcard=21 then poke ($200+charx+chary*20),$08B1
if Mcard>3 AND Mcard<23 then arrowA=0:arrowX=0:arrowY=0

For example, I shoot an arrow. I want to get the backtab so I subtract arrow variable by 4, so they are somewhat center. Then divide by 8. Backtab memory address start at $200 so I add char, and then chary is multiplied by 20. Then store the value to an 8 bit variable to shave the 8 bit from the 16 bit variable. I divide by 8 to shave off the color bit of the card. Now I can get card number 0-31. After that, I do comparisons. If Mcard=21 is probably what you want. This load $08B1 tile information to wherever the arrow hit. In this case, a window get broken and get this broken window tile. Mcard>3 AND Mcard<23, are solid blocks. It will kill the arrow immediately and make it available to refire when it detect those values.

I used software solution to do MOB vs Backtab collision.

charx=(arrowX-4)/8
chary=(arrowY-4)/8

Mcard=PEEK($200+charx+chary*20)
Mcard=Mcard/8

if Mcard=21 then poke ($200+charx+chary*20),$08B1
if Mcard>3 AND Mcard<23 then arrowA=0:arrowX=0:arrowY=0
For example, I shoot an arrow. I want to get the backtab so I subtract arrow variable by 4, so they are somewhat center. Then divide by 8. Backtab memory address start at $200 so I add char, and then chary is multiplied by 20. Then store the value to an 8 bit variable to shave the 8 bit from the 16 bit variable. I divide by 8 to shave off the color bit of the card. Now I can get card number 0-31. After that, I do comparisons. If Mcard=21 is probably what you want. This load $08B1 tile information to wherever the arrow hit. In this case, a window get broken and get this broken window tile. Mcard>3 AND Mcard<23, are solid blocks. It will kill the arrow immediately and make it available to refire when it detect those values.

 

With the "shifted" technique I mentioned above, you do something similar, but you also need to account for the offset of the object within the card (i.e., the shifted amount).

 

Essentially, it's bounding box collision detection, where the position of the bounding box is influenced by the logical position of the object within the play-field.

 

dZ.

Like Dz-Jay says, once you leave MOB on MOB or MOB on Backtab, your only course of action is software calculation, which is actually 1 or 2 frames faster since you aren't waiting for the hardware collisions.

 

Here is a really rough and definitely buggy sample of Worm Whomper style pre shifted grams I did in a much earlier version of IntyBASIC, noticeable because I use RAND instead of RANDOM. It still works with the current version.

[Click to animate]

post-38229-0-15058700-1479760080_thumb.gif

 

With careful planning and careful use of DEFINE I could have made the rocks also rotate.

post-38229-0-54854800-1479760155.png

 

The code and graphics

Rockssamplecode.zip

 

 

 

  • Like 4

Speaking of backtab animated creatures, here are the imfamous "Hockey Robots of Death!", appearing for the first time in a basic program...

 

post-14916-0-49210700-1479833486_thumb.gif <-- click to animate

 

The robot has a 4 frame animation. It moves 2 pixels every frame, so it takes 4 frames to complete an animation cycle and move completely from one backtab position to the next. Source code is included....

 

 

hrod.zip

 

 

Catsfolly

 

 

  • Like 5

Both samples are extremely cool! how goes that both of you don't have coded a Berzerk clone? ;)

As a Berzerk/Frenzy fan (I have a Frenzy arcade cabinet in my basement that I have had for 20+ years) I'm real picky. I wouldn't waste a lot of time working on it until we can convert the samples properly. I recreated the various words and phrases with the stock allophones about 10 minutes after you added Intellivoice support to IntyBASIC. The voice from the arcade is so ingrained in my head that I couldn't stand the allophone-based versions. When we can convert the actual original samples to proper Intellivoice compatible samples then sometime might happen. The game itself wouldn't be hard, Frenzy would require some work handling all the shoot-able wall blocks, but the voice is a show stopper for me. Someone might want to do a version, but it would always seem half-assed to me since I know what the Intellivision can do. I tried software based speech conversions but I wasn't happy with the results either.

  • Like 1

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...