Jump to content
IGNORED

GoSub for INTV


atari2600land

Recommended Posts

Im liking the death counter. I only saw the fake ending not the true ending, could use some music/sound there. Not sure if that was your plan or only for the real ending. With the death counter and the octopi counter this could be used in the high score club or in a competition. Excellent game in my opinion. I played the atari version for about 5 minutes. I was so over that and went back to playing this one. This game definitely shows how much better the inty is over the atari.

Link to comment
Share on other sites

I added some music for the true ending. I tried to beat level 39 on my actual Intellivision 2 but after 15 minutes I gave up because my controllers are broken apparently. What moron designed the controllers? What other moron approved them? Argh! Down is the worst. I kept pressing down but nothing would happen some of the time. I wonder if there is a way to fix these stupid things so I can at least see the fake ending?! Also, I tried to write "Congratulations!" on the true ending, but before, while the letters were all there, now it was missing the i and o. So I tried all capital letters. Still missing an i and o. So I moved it down a row. All the letters showed up. Anyway, here is the version with true ending music added. And it all fits. I got all the stuff in and it's 15.5KB. Hardly any room to spare!

Edited by atari2600land
Link to comment
Share on other sites

Here is a version that corrects the sub's speed at both endings. It was going too fast. By the way, I have been able to beat level 39. It took a few more tries. I don't know who designed the controllers, but I want to give them a big huge talking to (or yelling at. Probably yelling at.)

Edited by atari2600land
  • Like 1
Link to comment
Share on other sites

Here is a version that corrects the sub's speed at both endings. It was going too fast. By the way, I have been able to beat level 39. It took a few more tries. I don't know who designed the controllers, but I want to give them a big huge talking to (or yelling at. Probably yelling at.)

Do you have trouble with these controllers when playing other games?

 

If not, I suspect that the problem is that the Intellivision controllers return 16 different direction values when the disc is pressed, and the gosub software is only check for 4 values - exactly up, down, left, and right.

 

You could try this - replace this code:

	if argh>8 then goto mazemain3

	if argh=8 and dirr=0 then turn=1
 	if argh=2 and dirr=1 then turn=1 

	if argh=8 then dir=1 
 	if argh=2 then dir=2 

 	if argh=4 then dir=3 
	if argh=1 then dir=4 

mazemain3:

With this code that checks more values...

	if argh>$18 then goto mazemain3

	if (argh= OR (argh=$09) OR (argh=$18) THEN dir=1 : if dirr=0 then turn=1
	if (argh=2) OR (argh=$06) OR (argh=$12) THEN dir=2 : if dirr=1 then turn=1
	if (argh=4) OR (argh=$0c) OR (argh=$14) THEN dir=3 
	if (argh=1) OR (argh=$03) OR (argh=$11) THEN dir=4

mazemain3:

Let me know if that helps on the real hardware....

 

Catsfolly

  • Like 1
Link to comment
Share on other sites

This helps greatly. Although I still have some troubles with the firing, but I suspect that's more to do with my controller than the code. By the way, adding this code got the game to be 16k. So I had to get rid of a few lines of unnecessary code to bring it back down to 15.5k.

Edited by atari2600land
  • Like 3
Link to comment
Share on other sites

This helps greatly. Although I still have some troubles with the firing, but I suspect that's more to do with my controller than the code. By the way, adding this code got the game to be 16k. So I had to get rid of a few lines of unnecessary code to bring it back down to 15.5k.

 

I don't know if you're using IntyBASIC v1.0 but it optimizes PRINT statements with strings.

 

Edit: Also the support for printing numbers directly, aligned to left or right, filled with zeroes or spaces

  • Like 2
Link to comment
Share on other sites

I like the new graphics and the status bar at the bottom. I have one recommendation, though. It still seems that you are clearing the screen and re-drawing every time that the level starts. This causes it to flicker for a frame or two. Could you instead re-draw the screen without clearing it? Or maybe there's no need to re-draw the screen at all, just reset the sprites.

 

-dZ.

Link to comment
Share on other sites

I like the new graphics and the status bar at the bottom. I have one recommendation, though. It still seems that you are clearing the screen and re-drawing every time that the level starts. This causes it to flicker for a frame or two. Could you instead re-draw the screen without clearing it? Or maybe there's no need to re-draw the screen at all, just reset the sprites.

 

-dZ.

Well, since on some levels some seaweed gets rearranged when the sub gets the key, it is necessary to redraw the seaweed.

Currently, the draw_room subroutine only draws the seaweed - it relies on a screen clear to draw the empty parts.

Here is a faster, smaller version that draws the seaweed and the blanks:

load_room: PROCEDURE
	rem set up the variables


	keyhave=0 : keynoisetimer=0
	if room<5 then keyhave=1 : keynoisetimer=11   

	#index			= room_data_size * room
	CHESTX			= room_data(#index)
	CHESTY			= room_data(#index+1)
	x1			= room_data(#index+2)
	y1			= room_data(#index+3)
	keyx			= room_data(#index+4)
	keyy			= room_data(#index+5)

	rem draw the maze
	#index = room * room_size
	 print color 5
        for y=22 to 202 step 20
          #line = room0(#index)
	   print at y
           for x=0 to 19
             if #line and $8000 then print "\318" else print " "
             #line = #line * 2
           next 
	   #index=#index+1
        next
	
        return
	end

With this version of load_room, the "cls" command can be removed from newmaze2.

newmaze2:
	dir=0	
	subtimer=0
	rem cls

After this, the screen doesn't flicker. (But the motion objects still flicker). It may be necessary to zero the motion objects before drawing the level to make sure that no hardware collision flags are set. I am not sure....

 

Catsfolly

Link to comment
Share on other sites

This helps greatly. Although I still have some troubles with the firing, but I suspect that's more to do with my controller than the code. By the way, adding this code got the game to be 16k. So I had to get rid of a few lines of unnecessary code to bring it back down to 15.5k.

 

The "problem" with the Intellivision disc is that it is not a joystick. When a player expects to press it like a button and get a distinct direction, he will find it difficult and complain about it being "broken."

 

The reality is that the disc was never intended to be used that way; it should be compared instead to one of those "analog sticks" on the PlayStation. The player is intended to "roll" his thumb on the disc and have it react to the motion.

 

So then, how do you make maze games or platformers, or any other 2-D game that requires precise directional control? Simple: you play to the strengths of the controller, and try to accommodate and compensate for its use case.

 

There are three main ways that this is typically done:

  1. Read only the cardinal points of the disc, that is, directions N=0, E=4, S=8, and W=12. This results in a very poor experience, since slightly straying the thumb to either side will cause it to hit a "dead zone" and stop responding to input. Older games and mostly crappy ones, support this method.
  2. Expand the cardinal points to cover the adjacent directional zones, that is, directions NNW=15, N=0, and NNE=1 all map to North; ENE=3, E=4, and ESE=5 map to East; SSE=7, S=8, and SSW=9 map to South; and finally WSW=11, W=12, and WNW=13 map to West. This improves the experience by making the usable areas of the disc larger, but still has a drawback that if the player's thumb happen to stray slightly more into a perfect diagonal, the game will not respond to it. This is the method employed by DK Arcade and D2K, since it tries to be true to the original, in which pressing the stick on a different direction that the one allowed in the path (e.g., pressing up while walking and there is no ladder to climb) would cause Mario to stop.
  3. Same as above for the usable zones, but include the perfect diagonals as well. The problem with this option is that a perfect diagonal, by definition is equidistant from two cardinal points; so in a game supporting only four directions, which one should you pick? The answer is to use heuristics; in other words, you take an educated guess based on all known information.

Option #2 is perfectly reasonable for most games, but I find option #3 superior, especially for maze games. Not coincidentally, it's the method I implemented in Christmas Carol, which leads to really fast and mostly accurate cornering.

 

So what are those heuristics and how does that work? The method I employ in Christmas Carol is surprisingly simple, and if I may say so myself, rather intuitive. The algorithm goes like this:

  • Keep track of the last known direction the player chose. This is the "current direction" of travel.
  • Keep track of the last raw input value acquired. This is the "last input."
  • When a new direction is detected, and it is not a perfect diagonal, replace the "current direction" with the new one--only if the raw input value is different than "last input."
  • When the new direction detected is a perfect diagonal, and its raw input value is different from the "last input," use the combination of the "current direction" and the diagonal to determine which is the most likely direction the player intended. For this, imagine yourself rolling your thumb on the disc. For instance, if your last direction was North and you roll your thumb towards East in order to turn right, then a perfect diagonal of North-East is just the game sampling the direction before your thumb completes its trip.

 

NOTE:

In the above, "raw input value" represents the true value read from the controller. That is, if you get NNE (value=1), it will be translated into "North," but you still keep track of the value so that you may detect when it changes. Thus, you only react on changed input, not just on whatever you read every frame.

 

If we ignore any purposely fed bad input, and assume that the player will be using the disc as it was intended, then we can expect perfect diagonals to be hit precisely while the player is rolling his thumb from one cardinal point to the other. The resulting mapping logic will look like this:
  • Diagonal: NE
    • If "current direction" is N, then replace it with E
    • If "current direction" is E, then replace it with N
    • If "current direction" is anything else, it's probably a sampling error, so pick whichever.
  • Diagonal: SE
    • If "current direction" is E, then replace it with S
    • If "current direction" is S, then replace it with E
    • If "current direction" is anything else, it's probably a sampling error, so pick whichever.
  • Diagonal: SW
    • If "current direction" is S, then replace it with W
    • If "current direction" is W, then replace it with S
    • If "current direction" is anything else, it's probably a sampling error, so pick whichever.
  • Diagonal: NW
    • If "current direction" is N, then replace it with W
    • If "current direction" is W, then replace it with N
    • If "current direction" is anything else, it's probably a sampling error, so pick whichever.

 

Of course, you can optimize this by creating a look-up table rather than a gazillion if-else statements. There are four possible values for the "current direction," one for each of the cardinal points. Likewise, there are four possible values for the perfect diagonals. This yields a table of 256 possible entries (44). However, you can simplify it, since most of the possible combinations are invalid.

 

Another optimization is that we really don't care what the current direction is, we only care about the axis of movement. For example, consider the case of Diagonal NE:

  • If "current direction" is N, then replace it with E
  • If "current direction" is E, then replace it with N
  • If "current direction" is anything else, it's probably a sampling error, so pick whichever.

That is the same as saying:

  • If going vertical, choose E
  • If going horizontally, choose N

This will automatically result in picking one or the other for any of the third cases where we assume a sampling error. (This is the reason why I said above that it leads to "mostly accurate cornering," since there are some edge cases which cannot be resolved. That said, these are very rare in practice.)

 

This reduces the possible options to 23, or 8 entries in your table. In Christmas Carol this is ultimately optimized by treating the diagonals as ordinal values from 0 to 3, and the axis of movement as an ordinal from 0 to 1; and the entire thing is combined into a 3-bit numeric value which represents the index into our table, from 0 to 7. In my game, the bitmap looks like this:

                ; Compose @@__diag_tbl look-up index:
                ;   +---+---+---+ //...
                ;   | A | INPUT |
                ;   +---+---+---+ //...
                ;     ^     ^
                ;     |     `----> The 2 Least Significant Bits of the input
                ;     `----------> The MOB's orientation axis
                ;                       0 = Vertical
                ;                       1 = Horizontal

And the actual table looks like this:

@@__diag_tbl:   ; Vertical:
                DECLE   SPR_DIR.Left                    ; - - 0 0 0 - NW
                DECLE   SPR_DIR.Left                    ; - - 0 0 1 - SW
                DECLE   SPR_DIR.Right                   ; - - 0 1 0 - NE
                DECLE   SPR_DIR.Right                   ; - - 0 1 1 - SE
                ; Horizontal
                DECLE   SPR_DIR.Up                      ; - - 1 0 0 - NW
                DECLE   SPR_DIR.Down                    ; - - 1 0 1 - SW
                DECLE   SPR_DIR.Up                      ; - - 1 1 0 - NE
                DECLE   SPR_DIR.Down                    ; - - 1 1 1 - SE

The algorithm used in Christmas Carol is below. The actual routines were included in the old P-Machinery v1.0. I've attached the relevant module to this post. The routines of interest are CTRL_GAMEPLAY which conditions the signal, and .JOYSTK_DECODE which performs the decoding.

last_raw = null;
last_dir = null;
curr_dir = null;

while (idle == true) {
  new_raw = getControllerInput();

  // Check if raw input changed
  if (new_raw != last_raw) {
    new_dir = convertRawToCardinal(new_raw); // returns 0..4 (N, E, S, W, Diagonal)

    // Check if it's a diagonal
    if (new_dir == Diagonal) {
      new_dir = convertDiagonalToCardinal(last_dir, new_dir);
    }

    // Only process if the new direction is different
    if (new_dir != last_dir) {
      last_dir = curr_dir;
      curr_dir = new_dir;

      triggerChangeDirectionEvent(last_dir, curr_dir);
    }
  }
}

So there you go, simple, straightforward, intuitive, and highly accurate heuristics to treat a 16-way directional disc as a 4-way joystick.

 

I hope this helps.

 

-dZ.

 

 

ctrl_util.asm

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

I've updated my explanation to mention the tracking of the last known input. Catsfolly brought up the point that you can't really switch directions whenever you detect a diagonal, or else you'll be flip-flopping like a fish. The trick is to only switch directions when the actual input detected changes.

Link to comment
Share on other sites

That was the intention of the joystick? To make your thumb roll around on it rather than treat it like a normal joystick? That's what I suspected, but I wasn't sure, it sounded too weird. Anyway, I updated the code so the screen doesn't flicker when the level changes. I can't tell if the sprites do or not. I think I'll stick with the way directions are being called in this version, I don't want to go over 15.5 k. Why not? I just would find it wasteful to use only, say, 17k out of a possible 32k. I've also put the latest basic file here so you can see all of it.

Edited by atari2600land
  • Like 1
Link to comment
Share on other sites

  • 2 weeks later...

I was checking this out again last night and discovered that only the left controller is working with the game. The right controller won't start the game or control it once it's going. Hopefully this isn't much effort to fix.

why do you use the player 2 controller? Even your flashback says player 1 on the left side. There are other games that use the left controller only as well.
Link to comment
Share on other sites

why do you use the player 2 controller? Even your flashback says player 1 on the left side. There are other games that use the left controller only as well.

 

Other games do that too? I guess I never noticed. My wife and I were playing some games last night, and I showed her Gosub. I was on the right and unable to play. Seemed inconvenient to have to switch controllers to take turns. Is it a big deal to make both available, as in Night Stalker, for instance?

Link to comment
Share on other sites

GoSub is a one-player game.

 

No problem. I was just alerting you to what I thought was a mistake. When two people are taking turns playing a one-player game, like Astrosmash, I think it's awkward to have to switch controllers.

 

Very nice job on this game! Simple but very challenging :thumbsup:

Link to comment
Share on other sites

why do you use the player 2 controller? Even your flashback says player 1 on the left side. There are other games that use the left controller only as well.

 

One thing I never really realized until recently, is that the majority of INTV games, when played single player, seem to allow controller 2 to be used as well. This has been IMMENSELY helpful when it comes to repairing old units, because I can quickly figure out if a controller is broken or not (as opposed to some other weird error). Also, it's highly handy for people who own consoles where controller 1 is broken, but controller 2 works fine - which is surprisingly common. I guess a lot of people wore out the P1 controller but hardly ever used P2.

 

Personally, it's something I think everyone should allow for in INTV homebrew, for single player games/modes. It allows your game to be even more useful. Especially to people with broken P1 controllers. It's not a lot of work to add it into your code, especially with IntyBASIC. Just take any CONT1 lines and duplicate them to CONT2. It shouldn't affect performance unless you're doing some horrible input handling.

  • Like 1
Link to comment
Share on other sites

I have a question about the Intellicart. When I put GoSub on it, there's a thin black border on my TV screen. However when I put in an Intellivision game without the Intellicart, there is no thin black border on the green title screen. Is this OK? Why does this happen?

Edited by atari2600land
Link to comment
Share on other sites

 

One thing I never really realized until recently, is that the majority of INTV games, when played single player, seem to allow controller 2 to be used as well. This has been IMMENSELY helpful when it comes to repairing old units, because I can quickly figure out if a controller is broken or not (as opposed to some other weird error). Also, it's highly handy for people who own consoles where controller 1 is broken, but controller 2 works fine - which is surprisingly common. I guess a lot of people wore out the P1 controller but hardly ever used P2.

 

Personally, it's something I think everyone should allow for in INTV homebrew, for single player games/modes. It allows your game to be even more useful. Especially to people with broken P1 controllers. It's not a lot of work to add it into your code, especially with IntyBASIC. Just take any CONT1 lines and duplicate them to CONT2. It shouldn't affect performance unless you're doing some horrible input handling.

 

Most single-player home-brews do. Joe Z. suggested this to me and I implemented it in Christmas Carol.

 

 

As a matter of fact, in my P-Machinery framework, if the programmer elected to use "single-player mode" for input decoding, both controllers are automatically read as one. The framework includes a "plug-in" mechanism to support multiple input decoders, and by default comes with a few built-in. For example, the programmer can choose:

 

    ; -------------------------------------------------
    ; "General" driver is a multi-purpose decoder that
    ; supports the Keypad, Disc, and Action Buttons.
    ; -------------------------------------------------
    IO.UseDecoder(GeneralP1)      ; Player 1 - Left controller only
    IO.UseDecoder(GeneralP2)      ; Player 2 - Right controller only
    IO.UseDecoder(GeneralSingle)  ; Single Player - Reads both controllers as one
    IO.UseDecoder(GeneralDouble)  ; Two Players - Reads both controllers individually.

    ; STATE.AddSub(state, ctrl, disp, opt)
    ;   Define a game phase sub-state and assign it a decoder.
    ;   Parameters are:
    ;     - state        The game state being defined
    ;     - ctrl         The name of the input decoder to use during game state
    ;     - disp         Pointer to dispatch table for event handlers supported by input decoder
    ;     - opt          Game state options (e.g., enable animations, mob movements, etc.)
    STATE.AddSub(GAMEPLAY, GeneralDouble, PLAY.Disp, PM.NULL)


Perhaps IntyBASIC could support "single" or "double" player modes.

 

 

 

I have a question about the Intellicart. When I put GoSub on it, there's a thin black border on my TV screen. However when I put in an Intellivision game without the Intellicart, there is no thin black border on the green title screen. Is this OK? Why does this happen?

 

That's the screen border. You can control it in IntyBASIC with the BORDER statement or if using MODE 0 (Color Stack), by setting the colors after the mode.

 

Depending on the style of the game, and the visual design, the border colour could be set the same as the play-field's background, making it invisible. In the case of Christmas Carol's title screen, the background colour varies depending on the screen area, so a single colour could not be used to hide the border. Therefore, I opted to make to not try to hide it, but use a colour that matched the rest of the art.

 

-dZ.

Link to comment
Share on other sites

That's the screen border. You can control it in IntyBASIC with the BORDER statement or if using MODE 0 (Color Stack), by setting the colors after the mode.

 

Depending on the style of the game, and the visual design, the border colour could be set the same as the play-field's background, making it invisible. In the case of Christmas Carol's title screen, the background colour varies depending on the screen area, so a single colour could not be used to hide the border. Therefore, I opted to make to not try to hide it, but use a colour that matched the rest of the art.

 

 

Yeah, and I think a lot of us just gave up on it. The original game designers generally used a much simpler palette and/or simpler graphics in general, so it was easier to color match. The current intro screen to Goatnom has no real color that would work, let alone the rest of the game, so black it is!

 

Then I just plain forgot about it. Now it looks like an emulator artifact more than anything (I realize that isn't)..

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