Jump to content
IGNORED

Now available IntyBASIC compiler v0.8 ! :)


nanochess

Recommended Posts

So, feature request? Could IntyBASIC support what you're essentially doing with the inlined ASM? Allow readability in the .bas file while avoiding using so many precious cycles hopping around the stack?

 

I would need to think about the inline functions, but don't expect it soon.

Link to comment
Share on other sites

Is there any way to break a long line of code into multiple lines in an editor with IntyBasic? In batariBasic, I believe you can do something like:

 

IF (condition) THEN _

x = 1: y = 2

 

Where _ implies that the line breaks and continues on the next line, so x = 1 and y = 2 remain conditional.

Edited by Cybearg
Link to comment
Share on other sites

I feel like an idiot for asking about this again, but I'm still having trouble zeroing in on what tile is beneath something, particularly when it varies by scrolling..

 

This code checks to see if a gift has fallen directly into a chimney (determined by seeing if the highest bit is set):

IF (COL3 AND 256) = 0 THEN RETURN
	#temp1 = ((pres_y - 4) /8) * 4
	temp1 = ((pres_x-8)/8)
	#temp1 = $200 + #temp1 + (#temp1 * 4) + temp1
	#temp2 = peek(#temp1)

IF (#temp2 AND $8000) <> 0 THEN GOSUB present_delivered: RETURN

This is pretty much code given to me in an earlier question I asked. However, it doesn't always quite work. There are times, at certain points in scrolling, where the gift will fall off the edge of the chimney when it should be a hit or, worse, it will wildly miss even when it's dead-center. Here is a ROM with an additional sprite that blocks out where the sprite's hitbox actually is, to give a better view:

gift_drop.bin

 

What would be a better algorithm? I've fiddled with it for hours, adding and subtracting, trying to factor in offset_x, even checking across 2 or 3 tiles in line, but none of them have reliable, always-correct hit detection. Any suggestions for a better algorithm for calculating which tile a sprite is actually touching?

Edited by Cybearg
Link to comment
Share on other sites

I've never done collision detection with tiles, but I can tell you from experience that collision detection can be a HARD problem. Most of my issues aren't the collision detection per se - it's that I'm moving sprites more than one pixel per loop at times, and sometimes the sprite makes it past what I'm trying to detect.

 

Your code is vastly different than the kinds of simple things I'm doing, but really take a close look at things and see if there's any way you might be moving a MOB more than you think, and by the you check for the collision flags, it's gone past. It's not always obvious when you play the game simply because things move to fast. Essentially what I had to do in some cases is to iterate all movements by a single pixel at a time, check for collision, and loop by the number of pixels I'm wanting something to move (because one pixel per frame is often too slow). You can take a performance hit doing this, but I'd rather not see sprites passing through each other.

 

I have no idea if this is your problem, but it's something worth checking. It's bitten me in the ass again and again. Your description of "I've tried all sorts of arithmetic and using offsets etc" just reminds me of a lot of hours messing with this stuff. And no, I still don't have it 100%. Either I'm stupid or collision detection is just plain hard. I'm going to be running hours-long debugger sessions pretty soon just to nail down my few edge cases (usually, but not always happening when the game speeds up a lot).

Edited by freeweed
Link to comment
Share on other sites

...

Yeah, if I was trying to get proper collision between sprites or sprites and backgrounds to prevent one from going through the other and it wasn't working out well, I'd probably do something akin to what you're suggesting there.

 

The problem here is more that, between the sprite moving to keep up with the scrolling and the fact that it's likely not aligned with the 8-pixel grid, there are bad spots where the x-index of the tile will be off, so it will think that a present has missed the chimney because it's checking for the chimney on the tile beside the chimney, even though the gift is touching the chimney itself. I need an efficient, reliable way to compensate for the x offset of scrolling and the x offset of the gift sprite relative to the background tile that it collides with.

Link to comment
Share on other sites

Nod. And it's one of those hard-to-nail-down but obvious-once-you-get-it kinda problems. It's actually why I haven't even considered coding scrolling yet - I'll need to mock up a demo just to figure out the math, because I'm sure my first 10 attempts will fail miserably.

Edited by freeweed
Link to comment
Share on other sites

I feel like an idiot for asking about this again, but I'm still having trouble zeroing in on what tile is beneath something, particularly when it varies by scrolling..

 

This code checks to see if a gift has fallen directly into a chimney (determined by seeing if the highest bit is set):

IF (COL3 AND 256) = 0 THEN RETURN
	#temp1 = ((pres_y - 4) /8) * 4
	temp1 = ((pres_x-8)/8)
	#temp1 = $200 + #temp1 + (#temp1 * 4) + temp1
	#temp2 = peek(#temp1)

IF (#temp2 AND $8000) <> 0 THEN GOSUB present_delivered: RETURN

This is pretty much code given to me in an earlier question I asked. However, it doesn't always quite work. There are times, at certain points in scrolling, where the gift will fall off the edge of the chimney when it should be a hit or, worse, it will wildly miss even when it's dead-center. Here is a ROM with an additional sprite that blocks out where the sprite's hitbox actually is, to give a better view:

attachicon.gifgift_drop.bin

 

What would be a better algorithm? I've fiddled with it for hours, adding and subtracting, trying to factor in offset_x, even checking across 2 or 3 tiles in line, but none of them have reliable, always-correct hit detection. Any suggestions for a better algorithm for calculating which tile a sprite is actually touching?

If the sprite is the same size as a tile, it could be touching 4 different tiles. Which one do you consider it to be "actually touching"?

 

I think for scrolling you would have to use the ( pres_x - x_offset) instead of pres_x, since that is where the sprite really is on the screen.

Link to comment
Share on other sites

If the sprite is the same size as a tile, it could be touching 4 different tiles. Which one do you consider it to be "actually touching"?

 

I think for scrolling you would have to use the ( pres_x - x_offset) instead of pres_x, since that is where the sprite really is on the screen.

And it's made even more complicated because the gift rotates, so it could be the width of a tile but offset up by 2 pixels, the height of a tile but offset right by 2 pixels, or rotated 45 degrees and fill the tile space more or less completely on each side.

 

I tried pres_x - offset_x because I thought the same thing, but it seems to make it even more unreliable than it already is. There are just some occasions when you can hit the chimney dead-center, but the hit detection checks the tile next to it. Probably in the case where it just did a full tile shift, though I'm not sure.

Edited by Cybearg
Link to comment
Share on other sites

Alright; I've carefully gone over it one iteration at a time and made a table of the best values. The winning formula seems to be:

 

x_index = (sprite_x - 5 - offset_x)/8

 

Of course, that means that there will be occasions when the sprite misses when it's half-touching on the left and half-touching on the right, but - 5 - offset_x seemed the most reasonable "center" for that.

Link to comment
Share on other sites

Now for a question that's more about basic game structure than anything specifically IntyBasic.

 

In the game I'm working on, the basic goal is dropping gifts into house chimneys while avoiding enemies. While I could make levels of completely unique pieces, it seems to me like making a series of separate screens containing a building or two that scroll in and then switching between what data is being scrolled in would be the better option. The alternative would be a single huge table of level data that would be difficult to build, harder to test, and non-reusable. The trade-off, of course, is that, unless tile data was analyzed and modified after being read in, duplicate buildings would be obvious in their recurring colors and exactly identical shapes.

 

For those of you out there with experience with this sort of thing, what is the wisest direction to pursue: one large, pre-designed level, or modular levels that can be rearranged to minimize ROM usage?

Edited by Cybearg
Link to comment
Share on other sites

I discovered an apparent bug in IntyBasic: the compiler seems to ignore everything after a poke()

 

For instance, if I type:

IF #temp3 > $8F THEN poke(#temp1 - 20, #temp3 - : GOTO post_delivered 
	poke(#temp1 - 20, $80) 
	poke(#temp1, (#temp2 XOR $8000)) ' Close off the chimney from more gifts
	
post_delivered:

Even if #temp3 is > $8F, it will still execute the following two pokes that it should be jumping over, because it ignores the GOTO.

 

Similarly, with this (the same thing, logically):

IF #temp3 > $8F THEN poke(#temp1 - 20, #temp3 -  ELSE poke(#temp1 - 20, $80): poke(#temp1, (#temp2 XOR $8000)) ' Close off the chimney from more gifts

The game never executes anything in the ELSE statement.

 

However, if I do this:

IF #temp3 > $8F THEN GOSUB decrement_chimney ELSE GOSUB close_chimney

...

decrement_chimney: PROCEDURE
	poke(#temp1 - 20, #temp3 - 
	END

close_chimney: PROCEDURE
	poke(#temp1 - 20, $80)
	poke(#temp1, (#temp2 XOR $8000)) ' Close off the chimney from more gifts
	END

Then the code executes as expected, with no problems.

 

Incidentally, how many cycles do peek()s and poke()s take? Are they expensive, or pretty light?

Edited by Cybearg
Link to comment
Share on other sites

Maybe I'm missing something here, but shouldn't this:

	MODE 0, 0, 0, 0, 0
	
	flags = 0;
	sprite_num = 0;

	FOR #i = 0 TO 480
	PRINT COLOR 1, "\95"
	NEXT #i
	PRINT AT 0 COLOR 0, "  "
	PRINT AT 20 COLOR 0, "  "
loop:
	IF CONT1.LEFT = 0 AND CONT1.RIGHT = 0 THEN flags = (flags AND $FE)
	IF CONT1.RIGHT AND (flags AND 1) = 0 THEN sprite_num = sprite_num + 1: flags = (flags XOR 1)
	IF CONT1.LEFT AND (flags AND 1) = 0 THEN sprite_num = sprite_num - 1: flags = (flags XOR 1)
	
	SPRITE 0, 8 + $700, 8 + $200, $7 + (sprite_num * 
	WAIT
	GOTO loop

... Give me a screen of all blue except black in the upper-left, where sprites can be cycled? Instead, I get off-white in that area, as if the MODE 0 isn't giving me the color I asked for. What's up with that?

Edited by Cybearg
Link to comment
Share on other sites

Maybe I'm missing something here, but shouldn't this:

	MODE 0, 0, 0, 0, 0
	
	flags = 0;
	sprite_num = 0;

	FOR #i = 0 TO 480
	PRINT COLOR 1, "\95"
	NEXT #i
	PRINT AT 0 COLOR 0, "  "
	PRINT AT 20 COLOR 0, "  "
loop:
	IF CONT1.LEFT = 0 AND CONT1.RIGHT = 0 THEN flags = (flags AND $FE)
	IF CONT1.RIGHT AND (flags AND 1) = 0 THEN sprite_num = sprite_num + 1: flags = (flags XOR 1)
	IF CONT1.LEFT AND (flags AND 1) = 0 THEN sprite_num = sprite_num - 1: flags = (flags XOR 1)
	
	SPRITE 0, 8 + $700, 8 + $200, $7 + (sprite_num * 
	WAIT
	GOTO loop
... Give me a screen of all blue except black in the upper-left, where sprites can be cycled? Instead, I get off-white in that area, as if the MODE 0 isn't giving me the color I asked for. What's up with that?

 

You should put a WAIT after MODE, also if you write 480 values instead of 240, you aren't initializing the screen pointer, you... well... errr... are writing everywhere in memory.

 

Including some important variables.

Link to comment
Share on other sites

Oh, woopsie! Thanks for pointing that out!

 

On an unrelated note, what are the tiles from $D5 to $FF? Supposedly there are 256 GROM tiles, but it just looks like gibberish to me. Is it consistent, intentional jibberish that fits together somehow, or is it just RAM or code being read as card values? Any reason one would want to use it? Is there any way to reclaim those cards so they can be used?

Edited by Cybearg
Link to comment
Share on other sites

Oh, woopsie! Thanks for pointing that out!

 

On an unrelated note, what are the tiles from $D5 to $FF? Supposedly there are 256 GROM tiles, but it just looks like gibberish to me. Is it consistent, intentional jibberish that fits together somehow, or is it just RAM or code being read as card values? Any reason one would want to use it? Is there any way to reclaim those cards so they can be used?

Once upon a time the Intellivision designers wanted to incorporate some very important routines in ROM, but they ran out of space, so they used part of the GROM.

 

You're seeing some Intellivision routines.

Link to comment
Share on other sites

I discovered an apparent bug in IntyBasic: the compiler seems to ignore everything after a poke()

 

For instance, if I type:

IF #temp3 > $8F THEN poke(#temp1 - 20, #temp3 - : GOTO post_delivered 
	poke(#temp1 - 20, $80) 
	poke(#temp1, (#temp2 XOR $8000)) ' Close off the chimney from more gifts
	
post_delivered:

Even if #temp3 is > $8F, it will still execute the following two pokes that it should be jumping over, because it ignores the GOTO.

 

Similarly, with this (the same thing, logically):

IF #temp3 > $8F THEN poke(#temp1 - 20, #temp3 -  ELSE poke(#temp1 - 20, $80): poke(#temp1, (#temp2 XOR $8000)) ' Close off the chimney from more gifts

The game never executes anything in the ELSE statement.

 

However, if I do this:

IF #temp3 > $8F THEN GOSUB decrement_chimney ELSE GOSUB close_chimney

...

decrement_chimney: PROCEDURE
	poke(#temp1 - 20, #temp3 - 
	END

close_chimney: PROCEDURE
	poke(#temp1 - 20, $80)
	poke(#temp1, (#temp2 XOR $8000)) ' Close off the chimney from more gifts
	END

Then the code executes as expected, with no problems.

 

Incidentally, how many cycles do peek()s and poke()s take? Are they expensive, or pretty light?

 

 

The IntyBasic manual describes "poke" as:

 

 

POKE address,data

 

Poke memory with data

Apparently, surrounding the address and data part with a set of parentheses confuses the basic compiler (even though it may be fine in some other versions of basic). If you take out the surrounding parentheses, it seems to work.

 

A call to poke with all constants generates 5 lines of assembly code:

; 	poke $200, 3

	MVII #512,R0
	PSHR R0
	MVII #3,R0
	PULR R4
	MVO@ R0,R4

Coding directly in assembly, you could write:

; 	poke $200, 3
	
	MVII #3,R0
	MVO  R0,$200


The basic generated code is longer because it is using a variable for the address to write to, which is common for poke statements.

  • Like 1
Link to comment
Share on other sites

I missed your post.

 

I discovered an apparent bug in IntyBasic: the compiler seems to ignore everything after a poke()

 

For instance, if I type:

IF #temp3 > $8F THEN poke(#temp1 - 20, #temp3 - : GOTO post_delivered 

 

The right syntax for your POKE is:

 

poke #temp1 - 20, #temp3 - 8
Otherwise IntyBASIC will generate a error saying "missing comma" and will ignore the rest of line, probably you're missing the error in the output because the screen rolls fast.
Link to comment
Share on other sites

Ah, I see. Well, the pokes still work with the wrong syntax, funny enough.

 

How many cycles are used up by a poke compared to setting a normal value, like a = 5?

When you run the IntyBasic compiler, it creates an .asm file, which contains the lines of basic as comments, followed by the assembly code generated.

 

Here is what I got for the line "a=5".


; 	a = 5
	MVII #5,R0
	MVO R0,V1

If I am reading the cp1610_ref.pdf document, correctly, that would take 8 cycles for the mvii, and 11 cycles for the mvo, for a total of 19 cycles...

  • Like 1
Link to comment
Share on other sites

I seem to be having some odd issues with memory getting written in unexpected ways (I presume). Or maybe I'm out of memory (doubt it)?

 

I'm just starting to implement a modular system to allow multiple enemy types to dynamically share sprites 4-7. When the screen scrolls in, it checks the cards for being card 1-15 and, if it is, it replaced that card with a normal, blank card and spawns an enemy in that location (if an enemy slot is available).

 

To accomplish these different enemies, I dimmed a fair chunk of memory:

	dim e_type(4)
	e_type(0) = 0
	e_type(1) = 0
	e_type(2) = 0
	e_type(3) = 0
	dim e_state(4)
	dim e_frame(4)
	dim e_mind(
	dim e_x(4)
	dim e_y(4)
	dim e_origin_y(4)

The e_type is what kind of enemy it is, 0 for disabled. e_state handles the enemy's internal state (walking, attacking, waiting, etc.), e_frame handles which frame the enemy is on, e_mind gives two bytes per enemy that will be used as internal memory, like remembering a coordinate the enemy is aiming at or a location the enemy is walking to, e_x and e_y are obvious, and e_origin_y is the y-origin the enemy is based at, which will mostly be used with formula tables to create enemies that move in parabolic wave or swirling patterns.

 

The enemies are then drawn on-screen like so:

IF e_type(0) <> 0 THEN temp1 = e_frame(0): SPRITE 4, e_x(0) + $300, e_y(0) + $100, enemy_sprites(temp1) + enemy_colors(temp1) ELSE SPRITE 4, 0, 0, 0

The problem is, even though e_y is only set when the enemy is first initialized:

set_enemies: PROCEDURE
	FOR temp1 = 19 TO 139 STEP 20
		#temp1 = peek($200 + temp1)
		temp2 = (#temp1 AND $FF8) / 8
		IF temp2 > 0 AND temp2 < 16 THEN poke $200 + temp1, 0: GOTO enemy_detected
	NEXT temp1
	RETURN
	
enemy_detected:
	FOR temp3 = 0 TO 4
		IF e_type(temp3) = 0 THEN e_type(temp3) = temp2: e_y(temp3) = (temp1 / 20) * 8: e_origin_y(temp3) = temp1 * 8: e_x(temp3) = 152: e_state(temp3) = 0: e_mind(temp3 * 2) = 0: e_mind((temp3 * 2) + 1) = 0: RETURN
	NEXT temp3
END

... and e_x is only set during the normal updating procedure:

update_enemies: PROCEDURE
	FOR temp1 = 0 TO 4
	IF e_type(temp1) = 0 THEN GOTO enemy_set
		e_x(temp1) = e_x(temp1) - 1
		IF e_x(temp1) <= 8 THEN e_type(temp1) = 0: GOTO enemy_set
		
enemy_set:
	NEXT temp1
END

... For some reason, e_y is getting modified, resulting in the enemy flying upwards and switching to a 16-line sprite at times. Additionally, even if I modify the SPRITE declaration to draw the sprite at, say, 24 instead of the variable e_y, the sprite will move left (as it should) then vanish (it shouldn't), then it appears off the right edge of the screen, moving left until it meets the left edge of the screen before disappearing (as it should). I have no idea why it vanishes there, as if the x_value goes so low, it temporarily undoes the visibility bit or something.

 

Here is the full source code and a compiled binary to show what I'm talking about:

main.bas

output.bin

Any ideas what's going on here?

Edited by Cybearg
Link to comment
Share on other sites

Here is the full source code and a compiled binary to show what I'm talking about:

attachicon.gifmain.bas

attachicon.gifoutput.bin

Any ideas what's going on here?

 

Any chance that you could provide the symbol table generated by the assembler?

 

By the way, cute game! I think the world really needs more Christmas-themed games. :)

Edited by DZ-Jay
Link to comment
Share on other sites

I seem to be having some odd issues with memory getting written in unexpected ways (I presume). Or maybe I'm out of memory (doubt it)?

 

I'm just starting to implement a modular system to allow multiple enemy types to dynamically share sprites 4-7. When the screen scrolls in, it checks the cards for being card 1-15 and, if it is, it replaced that card with a normal, blank card and spawns an enemy in that location (if an enemy slot is available).

 

To accomplish these different enemies, I dimmed a fair chunk of memory:

	dim e_type(4)
	e_type(0) = 0
	e_type(1) = 0
	e_type(2) = 0
	e_type(3) = 0
	dim e_state(4)
	dim e_frame(4)
	dim e_mind(
	dim e_x(4)
	dim e_y(4)
	dim e_origin_y(4)

The e_type is what kind of enemy it is, 0 for disabled. e_state handles the enemy's internal state (walking, attacking, waiting, etc.), e_frame handles which frame the enemy is on, e_mind gives two bytes per enemy that will be used as internal memory, like remembering a coordinate the enemy is aiming at or a location the enemy is walking to, e_x and e_y are obvious, and e_origin_y is the y-origin the enemy is based at, which will mostly be used with formula tables to create enemies that move in parabolic wave or swirling patterns.

 

The enemies are then drawn on-screen like so:

IF e_type(0) <> 0 THEN temp1 = e_frame(0): SPRITE 4, e_x(0) + $300, e_y(0) + $100, enemy_sprites(temp1) + enemy_colors(temp1) ELSE SPRITE 4, 0, 0, 0

The problem is, even though e_y is only set when the enemy is first initialized:

set_enemies: PROCEDURE
	FOR temp1 = 19 TO 139 STEP 20
		#temp1 = peek($200 + temp1)
		temp2 = (#temp1 AND $FF8) / 8
		IF temp2 > 0 AND temp2 < 16 THEN poke $200 + temp1, 0: GOTO enemy_detected
	NEXT temp1
	RETURN
	
enemy_detected:
	FOR temp3 = 0 TO 4
		IF e_type(temp3) = 0 THEN e_type(temp3) = temp2: e_y(temp3) = (temp1 / 20) * 8: e_origin_y(temp3) = temp1 * 8: e_x(temp3) = 152: e_state(temp3) = 0: e_mind(temp3 * 2) = 0: e_mind((temp3 * 2) + 1) = 0: RETURN
	NEXT temp3
END

... and e_x is only set during the normal updating procedure:

update_enemies: PROCEDURE
	FOR temp1 = 0 TO 4
	IF e_type(temp1) = 0 THEN GOTO enemy_set
		e_x(temp1) = e_x(temp1) - 1
		IF e_x(temp1) <= 8 THEN e_type(temp1) = 0: GOTO enemy_set
		
enemy_set:
	NEXT temp1
END

... For some reason, e_y is getting modified, resulting in the enemy flying upwards and switching to a 16-line sprite at times. Additionally, even if I modify the SPRITE declaration to draw the sprite at, say, 24 instead of the variable e_y, the sprite will move left (as it should) then vanish (it shouldn't), then it appears off the right edge of the screen, moving left until it meets the left edge of the screen before disappearing (as it should). I have no idea why it vanishes there, as if the x_value goes so low, it temporarily undoes the visibility bit or something.

 

Here is the full source code and a compiled binary to show what I'm talking about:

attachicon.gifmain.bas

attachicon.gifoutput.bin

Any ideas what's going on here?

I don't know if it's the only problem, but it looks like your "for" loops are running one too many times.

 

update_enemies: PROCEDURE

FOR temp1 = 0 TO 4 <<<<---- this will loop 5 times, with the values of 0, 1,2,3,4 ...

IF e_type(temp1) = 0 THEN GOTO enemy_set

e_x(temp1) = e_x(temp1) - 1

IF e_x(temp1) <= 8 THEN e_type(temp1) = 0: GOTO enemy_set

 

enemy_set:

NEXT temp1

END

 

I'm guessing it should be: FOR temp1 = 0 TO 3

  • Like 1
Link to comment
Share on other sites

 

Any chance that you could provide the symbol table generated by the assembler?

 

By the way, cute game! I think the world really needs more Christmas-themed games. :)

Thanks! It's pretty bare-bones at the moment, but I have some ideas, and when those run dry, I'll be posting updates on the forums for feedback. It seems to have worked well for GOSUB.

 

I don't know if it's the only problem, but it looks like your "for" loops are running one too many times.

 

update_enemies: PROCEDURE

FOR temp1 = 0 TO 4 <<<<---- this will loop 5 times, with the values of 0, 1,2,3,4 ...

IF e_type(temp1) = 0 THEN GOTO enemy_set

e_x(temp1) = e_x(temp1) - 1

IF e_x(temp1) <= 8 THEN e_type(temp1) = 0: GOTO enemy_set

 

enemy_set:

NEXT temp1

END

 

I'm guessing it should be: FOR temp1 = 0 TO 3

D'oh! This is exactly the problem! I was overflowing into memory of other arrays. Changing those 4s to 3s has fixed the problem. Thanks! I'm too used to C-syntax of for (i = 0; i < 4; i++)

 

Is there any way to stop sprites from doing that funky stutter when they near x = 0 and instead just gracefully go off-screen?

Edited by Cybearg
Link to comment
Share on other sites

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...