Jump to content

SeaGtGruff

Members
  • Content Count

    5,587
  • Joined

  • Last visited

  • Days Won

    2

Posts posted by SeaGtGruff


  1. Well crap, I had a long bitchy post written about how we should all start writing our own bB custom kernels and other tricks instead of whining to batari to add stuff for us, and I lost my connection and the post got wiped out! :) I guess it's just as well.

     

    Anyway, I was basically trying to point out that a lot of really cool things can be done in bB right now, without any new commands or features having to be added by batari. For example, we can create custom kernels using only bB code (here's an example, the Atari rainbow); or defining the playfield with binary data sort of the way it's done in Adventure; or putting player data in a strip of ROM data and displaying the desired shape by pointing bB to it; or even creating modifiable player shapes by putting the player data in RAM!

     

    For the player example, push up to see a circle, push left to see a square, and push right to see a triangle.

     

    For the RAM player example, move the snake around. The positioning is buggy, the snake doesn't turn correctly, but it should work well enough to give an idea of what I was trying to accomplish.

     

    Michael Rideout

    playfield_example.bas

    playfield_example.bas.bin

    player_example.bas

    player_example.bas.bin

    ram_player_example.bas

    ram_player_example.bas.bin

    reverse_rainbow_2.bas

    reverse_rainbow_2.bas.bin


  2. I'm working at getting the multisprite kernel integrated into bB.

     

    So the problem right now is with RAM.  There's just not enough.  Initially it seemed like there was, but that was before I found that the new kernel stores graphics pointers and sprite heights in ROM, which is bad from a compilation standpoint if you want to allow any sprite to have any graphics and any height.  So this needs to be moved to RAM, but this requires 15 bytes that simply aren't there.

     

    So I'm needing to make a compromise.  I can do one of the above.

     

    I'm leaning toward #2, since this kernel uses a playfield that is only 16 pixels wide and symmetrical about the center, so it's not well-suited for plotting individual pixels and lines anyway.  You would define the entire playfield in one command.  You could change the playfield at will, but you'd have to change the whole thing at once.

     

     

    Let me know what you think.

    987031[/snapback]

     

    Could you provide both solutions using alternate kernels? Then the programmer could select which include file to use to get the kernel he or she wanted. Also, is the original kernel going to be retained as an alternate, so that any existing bB programs won't be broken by the new version? I know most everyone is eager to get the multi-sprite capability, but it seems to me that most games tend to have rather specific kernels anyway, as dictated by the needs of the game. I'd rather see a collection of different canned kernels which could be selected from. In fact, it might be nice to have a SET comand for specifying which kernel to compile into the game, like "set kernel=original" or "set kernel=multisprite".

     

    Michael Rideout


  3. i don't think you got my point, i have a rom and i want to see it's code - how do i do that? all i can do is run that kernel.bin and the game bins.

     

    anyone able to help me through msn? please

    986035[/snapback]

     

    The DASM program is used to assemble (compile) an assembly code file into a binary ROM image file. What you want to do is the reverse of that, take a binary ROM image file and disassemble it into an assembly code file. DASM can't do that, but a 6502 disassembler can. And to disassemble Atari 2600 ROM images, the best program to use is Distella.

     

    Go to http://www.atariage.com/2600/programming/index.html and scroll down until you see the link for Distella, and click on it. Oops, sorry, I just tried that and the link isn't working! Go to http://members.cox.net/rcolbert/distella.htm instead, and download version 3.0 for the latest and greatest.

     

    Michael Rideout


  4. OK, so my old desktop computer died, my boss gave me one of his old ones that he wasn't using any more, and this weekend I'm getting it set up, like installing bB on it, emulators, etc. So I created a folder called C:\Atari, and under it I created folders called 2600, 5200, 7800, and 800, like on my old computer. I downloaded and installed the various versions on bB in a folder called C:\bB, but then decided it would be better to move the bB folder inside the \Atari\2600 folder. But as I was about to do that, I had this crazy thought...

     

    bB is basically a high-level language to help create 6502 assembly source files that are then assembled into binary ROM images with DASM. Right now, bB is aimed at the 2600-- the header files, include files, and commands are specifically tailored for the 2600. But aside from the way the zero-page variables are defined, and the way the commands are currently tailored for the 2600 in particular, bB doesn't really know or care what machine the program is being written for. So wouldn't it be possible to create alternate header files, include files, and commands tailored for the other Atari machines? For example, maybe we could have a bB "machine" command, or "set machine=xxx" command, that would go at the beginning of a bB program, to specify which machine the program is being written for? Then, based on whatever that command is set to, the bB compiler could compile the source code using whichever header/footer/other include files are needed. After all, most of bB's commands (except the ones that are changed to assembly code by the bB compiler) are contained in routines located in the include files, so therefore any machine-specific routines (like drawing the playfield, the display kernel, etc.) could have their own separate include files. The resulting 6502 source code would then be assembled with DASM, and the final binary file could be run on the appropriate machine. In other words, we could use bB to write games for the 2600, or 7800, or 5200, or 800 et al.

     

    Now, admittedly this would take a lot of work to accomplish, there are already very powerful languages available for the 800 et al, and I think we should worry about further developments and improvements of bB for the 2600 before thinking about adding any support for other machines. And I'd personally prefer seeing support for the 7800 added before any support for the 5200 and 800 et al (simply because there's currently nothing for the 7800, and quite a few languages for the 800 et al-- with the 5200 essentially being like the 800 et al, so I presume that games for the 5200 can be developed using languages for the 800 et al?). But it strikes me that it would be very cool if some day (probably at least no sooner than a few years from now) we could use bB to create games for the 7800, 800, etc., in addition to games for the 2600!

     

    (I told you it was a crazy thought!)

     

    Michael Rideout


  5. Hey by the way do you know how many pixels tall a single scanline is ?, i have been looking all over this info and have not found it yet.

    983608[/snapback]

     

    Unless you use interlacing (very rare on the 2600), a scan line is the smallest unit of vertical resolution. Many Atari 2600 games draw the same thing on pairs of consecutive scan lines, though it's often possible to move things vertically in one-line increments.

    983637[/snapback]

     

    okay so like one PC style pixle tall than, i know the scanline is a group of pixels crammed together in a line from left to right, so i thought i might be 1 pixel tall from top to bottom. in any case thats answers that :).

     

    RA

    983645[/snapback]

     

    You asked the question backwards, it ought to be "A pixel is how many scan lines tall?" And the answer is that a pixel can be any number of scan lines tall, since the graphics features extend from the top of the screen to the bottom of the screen in the sense that once you set them on or off, they stay that way until you change them. So for example, if you set a particular playfield pixel on, it will create a line that extends from the top of the screen to the bottom of the screen, until you set that same playfield pixel off, hence you can make the playfield pixels be 1 scan line tall, or 2, or 3, or 4, etc., up to the height of the screen. At the same time, the player pixels can be left as is or changed, so they can also be any height. And the same holds true of the ball and the missiles. (I'm not referring to bB, which uses a canned kernel that updates the players every 2 scan lines, and updates the playfield every 16 scan lines-- with the exception of PF0 pixels, which stay on or off for the full height of the screen.)

     

    Or, to put it in terms of the way you asked the question, a scan line can be 1 pixel tall, or 1/2 pixel tall, or 1/3 pixel tall, or 1/4 pixel tall, etc., if you see what I mean.

     

    Michael Rideout


  6. Just to keep everyone updated on my bB tutorial-- I've been working on it, and had considered holding off until the next version of bB is released (since it sounds like it's going to be a major upgrade), but my computer died, so I can't access any of my work right now. The hard drive is OK, the power unit died, and I should be able to recover all of my work by either swapping my hard drive into another old computer (I know someone with an old one to sell), or fix it up to work as an extra external hard drive once I get my new computer. Right now I'm using "my" office laptop, and I've been needing a good excuse to buy a new computer anyway, so I guess I don't mind that my old 1998 clunker of a desktop finally bit the dust!

     

    Michael Rideout


  7. Out of curiosity, will the games that *don't* use the 8K, 16K, or 32K bankswitching (which I assume will be with Atari's method) still compile with everything in one place, or will they be split up into two areas as you'd mentioned doing to get the Atari bankswitching to work?

     

    Michael Rideout

    983577[/snapback]

    The games using no bankswitching will compile almost exactly as they did before. The only difference is that the graphics data are placed immediately after the bB code instead of being mixed in. This had to be done anyway because the multisprite kernel needs graphics to be placed stategically, but it also made bankswitching much easier.

    983590[/snapback]

     

    That sounds great! I was worried about how it might affect the customization I'd done for M-Network bankswitching, which I think works best if all of bB's code (included routines, as opposed to the programmer's code) can be compiled to occupy the fixed ROM area so it's available to all banks.

     

    Michael Rideout


  8. oh before i forget to ask, will bBatari Basic have a Poke and Peek function ?, like poke 65497,0 kinda command or Equivilent ?.

     

    RA

    983404[/snapback]

     

    bB already has this, at least sort of. LET (i.e., "=") is the equivalent of POKE, since it works with 1-byte variables, although the only thing you can "poke" into are the variables in RAM or the TIA registers (which don't keep their values). And IF or LET will sort of let you do a PEEK, in the sense that you can use IF to do something if a byte has a certain value, or you can LET a variable equal the value of any memory location. You can also use DIM to help you define the memory locations you're interested in.

     

    So for example, suppose you want to do something like "POKE 198, 7"-- you just say "variable = 7," where "variable" is a RAM variable that resides at location 198. Or "POKE COLUBK, 68" would just be "COLUBK = 68," since COLUBK is the name of a TIA register. You can't "poke" anything into ROM locations, but you can "poke" into registers or into RAM, including any extra RAM that's added by a particular bankswitching scheme (a few of which do add extra RAM).

     

    If you want to do something like "A = PEEK(65500)," you just start out saying something like "dim location=65500" near the beginning of your program (or it can actually go anywhere, even at the end), and then "a = location," which sets the variable a (or A, they are equivalent) to the value in address 65500.

     

    So, there's really no need for PEEK and POKE, they are pretty much necessary only in a BASIC that doesn't have 1-byte variables, whereas bB uses 1-byte variables by default.

     

    Michael Rideout


  9. my only concern is i do not think i can cram it in to 4K, i know about bankswitching but i am not sure how it would work or how to do it i should say.

    983314[/snapback]

    No need to worry about that in a few weeks - I've modified bB to create 8k, 16k, or even 32k binaries now. I think I've come up with a reasonable way to handle bankswitching, so most of it is transparent to the programmer. Still working on optimizations. But it will ne included in the next release regardless.

    983386[/snapback]

     

    Out of curiosity, will the games that *don't* use the 8K, 16K, or 32K bankswitching (which I assume will be with Atari's method) still compile with everything in one place, or will they be split up into two areas as you'd mentioned doing to get the Atari bankswitching to work?

     

    Michael Rideout


  10. I know that if i use the NUSIZ0 = $3 i can get three copies of the player0 and it's missile but how can i get them to be at Diffrent X and Y screen locations ?.

     

    I am slowly studying the tutorials at the Mini Dig and the ones here that Andrew Davies has provided as well as the one that Kirk Isreal has done. but i am a little slow at diegesting this kind of info. so is there a way to do it in bBasic or do i have to keep studying Asm to obtain that ?.

     

    RA

    981204[/snapback]

     

    You can't do it with the existing "canned" kernel, unless you use flickering-- e.g., to draw two independent player0 shapes, draw the first player0 shape on the odd frames, and draw the second player0 shape on the even frames.

     

    The ability to do that without flickering (well, except where the two shapes overlap on scan lines) is hoped for in the next version of bB, which may be released in January.

     

    However, I'm not sure how that's going to affect the RAM variables. Right now, 5 bytes are needed just for 1 copy of player0 (player0x = 1 byte, player0y = 1 byte, player0pointer = 2 bytes, and player0height = 1 byte), so for, say, 6 independent copies of player0, 30 bytes will be needed. That's 25 bytes more than currently, which means the 26 user variables (A through Z) would be toast-- and that's not even allowing for multiple copies of player1!

     

    Of course, you don't need to use the "canned" kernel. If you have very specific wants and needs (e.g., you won't be using the ball or missiles, just player0 and player1, and you aren't going to need an asymmetrical playfield), and if timing isn't a super-critical issue on each scan line, then you might be able to write your own game-specific kernel using all bB commands (i.e., for...next, if...then...else, goto, gosub, let). And if timing is an issue, you can always write your own kernel using inline assembly code.

     

    For example, the attached program is an all-bB custom kernel that I wrote last night to display the 2600's 128-color palette using only the background. Clearly, that kernel won't do you any good for multi-player graphics, but at least it shows that you can write all-bB custom kernels instead of calling drawscreen.

     

    Michael Rideout

     

    post-7456-1134447027_thumb.jpg

     

      rem * A simple NTSC display kernel written in bB.
      rem * "The Atari's 128-Color Palette" (:^p~
      rem =============================================
    
      rem * Initialize the 2600's audio and video.
      rem * (bB actually clears the 2600's registers for us,
      rem * but you need to do this sort of thing if you're
      rem * writing pure assembly programs outside of bB.)
      PF0 = 0 : rem * Turn off playfield 0.
      PF1 = 0 : rem * Turn off playfield 1.
      PF2 = 0 : rem * Turn off playfield 2.
      GRP0 = 0 : rem * Turn off graphics for player 0.
      GRP1 = 0 : rem * Turn off graphics for player 1.
      ENAM0 = 0 : rem * Turn off enable for missile 0.
      ENAM1 = 0 : rem * Turn off enable for missile 1.
      ENABL = 0 : rem * Turn off enable for ball.
      AUDV0 = 0 : rem * Turn off audio volume for sound 0.
      AUDV1 = 0 : rem * Turn off audio volume for sound 1.
    
    loop
    
      rem * Draw 30 blanked scan lines.
      VBLANK = 2 : rem * Turn on video blanking.
      for x = 1 to 30 : rem * Do next part 30 times.
         WSYNC = 0 : rem * Wait for next horizontal sync.
      next
    
      rem * Send vertical sync signal for 3 scan lines.
      VSYNC = 2 : rem * Turn on vertical sync.
      for x = 1 to 3 : rem * Do next part 3 times.
         WSYNC = 0 : rem * Wait for next horizontal sync.
      next
      VSYNC = 0 : rem * Turn off vertical sync.
    
      rem * Draw 36 more blanked scan lines.
      for x = 1 to 36 : rem * Do next part 36 times.
         WSYNC = 0 : rem * Wait for next horizontal sync.
      next
    
      rem * Turn video back on.
      VBLANK = 0 : rem * Turn off video blanking.
    
      rem * Draw hue 0 and its luminances for 11 scan lines.
      x = 0
    hue_0_loop
      WSYNC = 0 : rem * Wait for next horizontal sync.
      x = x + 1
      if x = 12 then goto hue_1
      COLUBK = $00
      COLUBK = $00
      COLUBK = $02
      COLUBK = $04
      COLUBK = $06
      COLUBK = $08
      COLUBK = $0A
      COLUBK = $0C
      COLUBK = $0E
      COLUBK = $00
      goto hue_0_loop
    
      rem * Draw hue 1 and its luminances for 11 scan lines.
    hue_1
      x = 0
    hue_1_loop
      WSYNC = 0 : rem * Wait for next horizontal sync.
      x = x + 1
      if x = 12 then goto hue_2
      COLUBK = $00
      COLUBK = $10
      COLUBK = $12
      COLUBK = $14
      COLUBK = $16
      COLUBK = $18
      COLUBK = $1A
      COLUBK = $1C
      COLUBK = $1E
      COLUBK = $00
      goto hue_1_loop
    
      rem * Draw hue 2 and its luminances for 11 scan lines.
    hue_2
      x = 0
    hue_2_loop
      WSYNC = 0 : rem * Wait for next horizontal sync.
      x = x + 1
      if x = 12 then goto hue_3
      COLUBK = $00
      COLUBK = $20
      COLUBK = $22
      COLUBK = $24
      COLUBK = $26
      COLUBK = $28
      COLUBK = $2A
      COLUBK = $2C
      COLUBK = $2E
      COLUBK = $00
      goto hue_2_loop
    
      rem * Draw hue 3 and its luminances for 11 scan lines.
    hue_3
      x = 0
    hue_3_loop
      WSYNC = 0 : rem * Wait for next horizontal sync.
      x = x + 1
      if x = 12 then goto hue_4
      COLUBK = $00
      COLUBK = $30
      COLUBK = $32
      COLUBK = $34
      COLUBK = $36
      COLUBK = $38
      COLUBK = $3A
      COLUBK = $3C
      COLUBK = $3E
      COLUBK = $00
      goto hue_3_loop
    
      rem * Draw hue 4 and its luminances for 11 scan lines.
    hue_4
      x = 0
    hue_4_loop
      WSYNC = 0 : rem * Wait for next horizontal sync.
      x = x + 1
      if x = 12 then goto hue_5
      COLUBK = $00
      COLUBK = $40
      COLUBK = $42
      COLUBK = $44
      COLUBK = $46
      COLUBK = $48
      COLUBK = $4A
      COLUBK = $4C
      COLUBK = $4E
      COLUBK = $00
      goto hue_4_loop
    
      rem * Draw hue 5 and its luminances for 11 scan lines.
    hue_5
      x = 0
    hue_5_loop
      WSYNC = 0 : rem * Wait for next horizontal sync.
      x = x + 1
      if x = 12 then goto hue_6
      COLUBK = $00
      COLUBK = $50
      COLUBK = $52
      COLUBK = $54
      COLUBK = $56
      COLUBK = $58
      COLUBK = $5A
      COLUBK = $5C
      COLUBK = $5E
      COLUBK = $00
      goto hue_5_loop
    
      rem * Draw hue 6 and its luminances for 11 scan lines.
    hue_6
      x = 0
    hue_6_loop
      WSYNC = 0 : rem * Wait for next horizontal sync.
      x = x + 1
      if x = 12 then goto hue_7
      COLUBK = $00
      COLUBK = $60
      COLUBK = $62
      COLUBK = $64
      COLUBK = $66
      COLUBK = $68
      COLUBK = $6A
      COLUBK = $6C
      COLUBK = $6E
      COLUBK = $00
      goto hue_6_loop
    
      rem * Draw hue 7 and its luminances for 11 scan lines.
    hue_7
      x = 0
    hue_7_loop
      WSYNC = 0 : rem * Wait for next horizontal sync.
      x = x + 1
      if x = 12 then goto hue_8
      COLUBK = $00
      COLUBK = $70
      COLUBK = $72
      COLUBK = $74
      COLUBK = $76
      COLUBK = $78
      COLUBK = $7A
      COLUBK = $7C
      COLUBK = $7E
      COLUBK = $00
      goto hue_7_loop
    
      rem * Draw hue 8 and its luminances for 11 scan lines.
    hue_8
      x = 0
    hue_8_loop
      WSYNC = 0 : rem * Wait for next horizontal sync.
      x = x + 1
      if x = 12 then goto hue_9
      COLUBK = $00
      COLUBK = $80
      COLUBK = $82
      COLUBK = $84
      COLUBK = $86
      COLUBK = $88
      COLUBK = $8A
      COLUBK = $8C
      COLUBK = $8E
      COLUBK = $00
      goto hue_8_loop
    
      rem * Draw hue 9 and its luminances for 11 scan lines.
    hue_9
      x = 0
    hue_9_loop
      WSYNC = 0 : rem * Wait for next horizontal sync.
      x = x + 1
      if x = 12 then goto hue_10
      COLUBK = $00
      COLUBK = $90
      COLUBK = $92
      COLUBK = $94
      COLUBK = $96
      COLUBK = $98
      COLUBK = $9A
      COLUBK = $9C
      COLUBK = $9E
      COLUBK = $00
      goto hue_9_loop
    
      rem * Draw hue 10 and its luminances for 11 scan lines.
    hue_10
      x = 0
    hue_10_loop
      WSYNC = 0 : rem * Wait for next horizontal sync.
      x = x + 1
      if x = 12 then goto hue_11
      COLUBK = $00
      COLUBK = $A0
      COLUBK = $A2
      COLUBK = $A4
      COLUBK = $A6
      COLUBK = $A8
      COLUBK = $AA
      COLUBK = $AC
      COLUBK = $AE
      COLUBK = $00
      goto hue_10_loop
    
      rem * Draw hue 11 and its luminances for 11 scan lines.
    hue_11
      x = 0
    hue_11_loop
      WSYNC = 0 : rem * Wait for next horizontal sync.
      x = x + 1
      if x = 12 then goto hue_12
      COLUBK = $00
      COLUBK = $B0
      COLUBK = $B2
      COLUBK = $B4
      COLUBK = $B6
      COLUBK = $B8
      COLUBK = $BA
      COLUBK = $BC
      COLUBK = $BE
      COLUBK = $00
      goto hue_11_loop
    
      rem * Draw hue 12 and its luminances for 11 scan lines.
    hue_12
      x = 0
    hue_12_loop
      WSYNC = 0 : rem * Wait for next horizontal sync.
      x = x + 1
      if x = 12 then goto hue_13
      COLUBK = $00
      COLUBK = $C0
      COLUBK = $C2
      COLUBK = $C4
      COLUBK = $C6
      COLUBK = $C8
      COLUBK = $CA
      COLUBK = $CC
      COLUBK = $CE
      COLUBK = $00
      goto hue_12_loop
    
      rem * Draw hue 13 and its luminances for 11 scan lines.
    hue_13
      x = 0
    hue_13_loop
      WSYNC = 0 : rem * Wait for next horizontal sync.
      x = x + 1
      if x = 12 then goto hue_14
      COLUBK = $00
      COLUBK = $D0
      COLUBK = $D2
      COLUBK = $D4
      COLUBK = $D6
      COLUBK = $D8
      COLUBK = $DA
      COLUBK = $DC
      COLUBK = $DE
      COLUBK = $00
      goto hue_13_loop
    
      rem * Draw hue 14 and its luminances for 11 scan lines.
    hue_14
      x = 0
    hue_14_loop
      WSYNC = 0 : rem * Wait for next horizontal sync.
      x = x + 1
      if x = 12 then goto hue_15
      COLUBK = $00
      COLUBK = $E0
      COLUBK = $E2
      COLUBK = $E4
      COLUBK = $E6
      COLUBK = $E8
      COLUBK = $EA
      COLUBK = $EC
      COLUBK = $EE
      COLUBK = $00
      goto hue_14_loop
    
      rem * Draw hue 15 and its luminances for 11 scan lines.
    hue_15
      x = 0
    hue_15_loop
      WSYNC = 0 : rem * Wait for next horizontal sync.
      x = x + 1
      if x = 12 then goto hue_15_end
      COLUBK = $00
      COLUBK = $F0
      COLUBK = $F2
      COLUBK = $F4
      COLUBK = $F6
      COLUBK = $F8
      COLUBK = $FA
      COLUBK = $FC
      COLUBK = $FE
      COLUBK = $00
      goto hue_15_loop
    
      rem * Draw one more scan line.
    hue_15_end
      WSYNC = 0 : rem * Wait for next horizontal sync.
      goto loop
    

    palette.zip


  11. UPDATE:

     

    I thought I would give y'all an update on the current status of this development.

     

    Basically the snake moves using the pfpixels.  I tried making a playing field with more pfpixels, but I guess since the snake is called using it - it will only display the playingfield and not the snake.

    976588[/snapback]

     

    What you'd need to do, if you want to use pfpixels for both the snake and the maze, is draw the maze first, before you get into the drawscreen loop, and then draw the snake inside the screen-drawing loop. For example, notice how in the following section of code you are gosubbing to draw the logo screen (by which I mean setting the bytes of the playfield equal to the desired values to create the logo text), before you actually get into the drawscreen loop:

     

    startme
      gosub clear : rem <----- this is where you're clearing the screen
      COLUPF = $44
      gosub logo : rem <------ and this is where you're "drawing" the title logo
      COLUP0 = $00
      COLUP1 = $00 : scorecolor = $00
    
    coloring
      g = g + 1
      COLUBK = g : COLUP0 = g : COLUP1 = g : COLUPF = $C4
      drawscreen : rem <----- but you don't actually draw the screen until here
      if joy0fire then goto programstart
      goto coloring
    

     

    If you clear the screen, draw the maze, draw the last four segments of the snake, and then get into the drawscreen loop, you shouldn't have any problems using the pfpixels for both the maze and the snake. Of course, when you position the snake for the start of the maze on each level, you want to be sure the snake isn't already colliding with a wall.

     

    I was then forced to use player sprites and missiles to coordinate the playing field for mazes.  But that in itself became a daunting task: lining up sprites where I have gaps with the invisible pfpixels so the snake can pass through them - and limited number of walls I'm allowed to create (2 players and 2 missiles).

     

    I think I'm gonna resort back to a stagnate snake using the player sprite (but make it turn directions it's goin in) until I can figure out a way to make the player sprite snake-like.

    976588[/snapback]

     

    I've been working on an example of drawing a snake with player0, but it's tricky. I started out thinking I would try to define all possible configurations for the player0 data, but that will take up a lot of ROM to define all the variations, plus the ifs for all the variations will require a lot of code. So now I'm working on a routine which defines the player0 data as an 8-byte array in RAM, and calculates what the data should be, based on the direction that each segment of the snake is moving in. As you can imagine, it's tricky, but I've almost got it working the way I want-- except there is a lot of screen flickering, so it appears that the routine is too long. I plan to try splitting it into two or four sections, split across two or four frames, to see if that helps.

     

    Also I'm slowly implementing levels.  I plan on using one of the missiles to make a key to unlock a door in the maze.  When the player collides with the key it opens a door, and when the player collides with the door it moves to the next level by adding +1 to the level variable.  I think that's the best way to move level to level.

     

    Currently you push space to begin the game and up to get out of the gameover sequence.  The score slowly declines (I'll probably make it slower in the future) because you're limited to how much time you have to get out of the maze.  If you push fire during the game it'll take you to a blank screen, just used it to test or not if I could make a second level (worked correctly).

     

    Few questions:

     

    How do I make it if say the head of the snake collides with a certain pixel (the pixel will be turned OFF) - which is the door to go to the next level?  I know how to make it go to the next level, but how do I set up the if - then statement?  If collides(player0, a certain pixel) then blah blah blah

    976588[/snapback]

     

    You can't test for collision between a player pixel and a playfield pixel if the pfpixel is turned off, so you'll need to use a different method of detecting when the snake has moved through the maze exit.

     

    One way you could do it is to check the snake's position. For example, if you know the exit is in column 0 of the playfield array, and in rows 4 and 5, then you could check to see if the snake's head is in column 0, row 4 or row 5.

     

    Another way you could do it is to leave the playfield alone (i.e., don't open the exit door by turning off any pfpixels), and instead use player1 or missile1 to draw the exit, positioning it on top of the pfpixels where the exit is, and check for a collision between player0 and player1, or between player0 and missile1. You could also use missile0, but if you use player1 or missile1, you can set COLUP1 to the same color as COLUBK, so it looks like the pfpixels for the exit have been erased even though they are still turned on. Of course, in your loop you'll probably be checking for a collision between player0 and player1 (or missile1) for something else, like to see if the snake is eating something or collecting the key, but you could use a flag to determine whether or not the exit has been revealed. If the collision occurs but the flag is off, then the snake is collecting something rather than touching the exit. But when the snake touches the key, then turn on the flag that says the exit is now available, draw the exit with player1 or missile1, and when another collision occurs go to the next level if the flag is on.

     

    Michael Rideout


  12. after rearranging things i found 2 papers i did not know i had. one says that there was only 8 contestants that guessed all 5 answers right in the earthworld challenge.

     

    if you guessed 1-2 right you were awarded the Brave Venturer Certificate

     

    if you guessed 3-4 right you were awarded the Wise Warrior Certificate

     

    if you guessed all 5 right you were awarded the Supreme Sage of Sorcery Certificate

     

    and the 5 correct clues were

    QUEST  IN  TOWER  TALISMAN  FOUND

     

    it also said that most people that missed one was the TALISMAN clue.

     

    Rick

    975885[/snapback]

     

    The number of contestants sounds about right. I got only 4 words right, and the one I missed was "TALISMAN," so that sounds right, too. The problem (for me) with that word clue was that it was hidden differently than the rest. The other 9 words were hidden within the panel drawings of the comic, like written in the grass or on the side of a building, etc. But "TALISMAN" was contained within a speech balloon, and was simply in big, bold letters like it was being stressed by the person speaking. I didn't find the clue number that pointed to that panel, so I didn't know a word was hidden there. :(

     

    Michael Rideout


  13. Fast multiplication

    (original article in Polish disk magazine "Syzygy" no. 6)

     

    The problem of multiplication on the 6502 is as old as this processor.

    The algorithms that can be found in various asm courses base on bit shifting

    and addition, and need about 100 cycles for calculating product of two

    8-bit numbers. Such algorithms are not fast at all.

     

    There is an effective solution to this problem: create 2-dimensional array

    (multiplication table) that contains all the possible results.

    Unfortunately not always one can afford 16 KB memory for this.

     

    What I suggest is an intermediate solution: implement multiplication

    using an addition and a function "calculated" using a lookup table.

     

    Consider the following formulas:

     

    (1) a*b = exp( log(a)+log(b) )

    (2) a*b = ( cos(x+y)+cos(x-y) )/2

    where: x = arc cos (a), y = arc cos (b)

    (3) a*b = ( (a+b)^2-a^2-b^2 )/2

    (4) a*b = ( (a+b)^2-(a-b)^2 )/4

     

    Which formula to choose? The best would be one:

    - simple to calculate,

    - true for any a and b,

    - that not requires high precision,

    - uses a lookup table easy to generate.

     

    These conditions are fulfilled best by the formula (4).

     

    The calculation is very simple:

        a*b = f(a+b)-f(a-b)

    where: f(x) = (x*x)/4

     

    At first glance, one thinks that you have to store

    the fractional part of (x*x)/4 in the lookup table

    in order to get an exact result. This is not the case,

    because:

    1) for even x, x = 2*k :

        f(2*k) = k*k

    - the result is an integer

    2) for odd x, x = 2*k+1

        f(2*k+1) = k*k+k+1/4

    - the result is an integer + 0.25.

    However, if a+b is odd, then a-b is odd too.

    The result of f(a+b)-f(a-b) would be therefore same,

    no matter if f() includes this 0.25 or not.

     

    Calculating successive squares is easy once you remember

    that:

     

    1*1 = 1 = 0+1

    2*2 = 4 = 0+1+3

    3*3 = 9 = 0+1+3+5

    ...

     

    That is, you only need to sum successive odd numbers.

     

    The algorithm is general enough to calculate products

    of signed numbers.

     

    There is no universal "fastest multiplication" routine,

    because universal routines are not fast and vice-versa.

     

    When implementing your own fast multiplication routine

    you should consider the following things:

    - how big are numbers which you want to multiplicate

    - are the numbers signed or not

    - where the factors are stored and where the result

      should be stored

    - what precision you want - for example, you may need

      just the high byte of the product and +-1 is acceptable

     

    But to not make this article too theoretical, I present

    two routines:

    - MULU8 - multiplicates unsigned numbers in A and X registers

    - MULS8 - multiplicates signed numbers in A and X

     

    A few words about the routines:

    - both routines calculate sums using 6502's indexed addressing mode.

      Unfortunately -A needs to calculated separately, which can be done

      with EOR #$ff and adding one. Instead of adding 1, we use a separate

      lookup table for (x+1)^2.

    - for MULU8 one lookup table contains squares of 0..510 and the other

      one -255..255

    - for MULS8 both tables contain squares of -255..255

    - for MULS8 $80 needs to be added to both input numbers, using EOR #$80.

      This eliminates the ambiguity that arises when adding signed numbers,

      for example:

        $60+$60=$c0

      -$40+0=$c0

      Instead, we have:

        $e0+$e0=$1c0 (positive $c0)

      $40+$80=$c0  (negative -$40)

      If the numbers are small (precisely: abs(A)+abs(X)<128), the EOR #$80

      are redundant, but you need to use different lookup tables.

     

    mulu8.asm:

     

    * Unsigned multiplication
    * A*X -> A:Y (A-high byte, Y-low)
    * b. Fox/Tqa
    
        opt 21
        org $480
    
    sq1l equ $a000
    sq1h equ $a200
    sq2l equ $a400
    sq2h equ $a600
    
        jsr init
    
        lda #123
        ldx #234
    
        sta l1+1
        sta h1+1
        eor #$ff
        sta l2+1
        sta h2+1
        sec
    l1   lda sq1l,x
    l2   sbc sq2l,x
        tay
    h1   lda sq1h,x
    h2   sbc sq2h,x
    
        brk
        brk
        brk
    
    init ldx #0
        stx sq1l
        stx sq1h
        stx sq2l+$ff
        stx sq2h+$ff
        ldy #$ff
    msq1 txa
        lsr @
        adc sq1l,x
        sta sq1l+1,x
        sta sq2l-1,y
        sta sq2l+$100,x
        lda #0
        adc sq1h,x
        sta sq1h+1,x
        sta sq2h-1,y
        sta sq2h+$100,x
        inx
        dey
        bne msq1
    msq2 tya
        sbc #0 -
        ror @
        adc sq1l+$ff,y
        sta sq1l+$100,y
        lda #0
        adc sq1h+$ff,y
        sta sq1h+$100,y
        iny
        bne msq2
        rts
    
        end
    

     

    muls8.asm:

    * Signed multiplication
    * A*X -> A:Y (A-high byte, Y-low)
    * b. Fox/Tqa
    
        opt 21
        org $480
    
    sq1l equ $a000
    sq1h equ $a200
    sq2l equ $a400
    sq2h equ $a600
    
        jsr init
    
        lda <123
        ldx <0-45
    
        eor #$80
        sta l1+1
        sta h1+1
        eor #$ff
        sta l2+1
        sta h2+1
        txa
        eor #$80
        tax
        sec
    l1   lda sq1l,x
    l2   sbc sq2l,x
        tay
    h1   lda sq1h,x
    h2   sbc sq2h,x
    
        brk
        brk
        brk
    
    
    init ldx #0
        stx sq1l+$100
        stx sq1h+$100
        stx sq2l+$ff
        stx sq2h+$ff
        ldy #$ff
    msqr txa
        lsr @
        adc sq1l+$100,x
        sta sq1l,y
        sta sq1l+$101,x
        sta sq2l-1,y
        sta sq2l+$100,x
        lda #0
        adc sq1h+$100,x
        sta sq1h,y
        sta sq1h+$101,x
        sta sq2h-1,y
        sta sq2h+$100,x
        inx
        dey
        bne msqr
        rts
    
        end
    

    975865[/snapback]

     

    Thank you, Fox, the article and routines will be very useful!

     

    Michael Rideout


  14. Ok, I figured out how to use Distella and DASM Thank you again for your help. I am slowly learning the fine art of hacking 2600 roms.  :)

    974773[/snapback]

     

    You're welcome! As for changing the title text color in "The Texas Chainsaw Massacre" (or stopping it from flashing), it looks like the code is here:

     

    L53FD: STA    WSYNC  ;3
          LDY    #$1A   ;2
          LDX    #$01   ;2
          STX    AUDC0  ;3
          DEX           ;2
          STX    COLUBK ;3
          STX    COLUPF ;3  ; <--- This initializes the playfield color I think
          LDA    $F0    ;3
          AND    #$7F   ;2
          CMP    #$20   ;2
          BCS    L541D  ;2
          LSR           ;2
          TAX           ;2
    L5414: AND    #$0F   ;2
          EOR    #$0F   ;2
          ORA    #$30   ;2
          STA    COLUPF ;3  ; <--- This is flashing the playfield color I think
          DEX           ;2
    L541D: STX    AUDF0  ;3
          STX    AUDV0  ;3
    L5421: STA    WSYNC  ;3
          DEY           ;2
    L5424: BNE    L5421  ;2
          LDX    #$0E   ;2
    L5428: LDA    #$04   ;2
          STA    $DF    ;3
    L542C: LDY    #$04   ;2
    L542E: STA    WSYNC  ;3
          LDA    L5B7E,X;4
          STA    PF0    ;3  ; <--- Here's where the text is being drawn
          LDA    L5B8D,X;4
          STA    PF1    ;3  ; <--- These are the left half of the playfield
          LDA    L5B9C,X;4
          STA    PF2    ;3  ; <--- Still left half of screen
          LDA    L5BAB,X;4
          STA    PF0    ;3  ; <--- Now begins the right half of the screen
          NOP           ;2
          LDA    L5BBA,X;4
          STA    PF1    ;3  ; <--- right half
          LDA    L5BC9,X;4
          DEY           ;2
          NOP           ;2
          STA    PF2    ;3  ; <--- right half
          BPL    L542E  ;2
          DEX           ;2
          DEC    $DF    ;5
          BPL    L542C  ;2
          STA    WSYNC  ;3
          INY           ;2
          STY    PF0    ;3  ; <--- Now we clear the playfield
          STY    PF1    ;3  ; <--- after the three lines of title text
          STY    PF2    ;3  ; <--- have been drawn
    

     

    Michael Rideout


  15. If you're going to use pfpixel to draw both the snake and the walls of the maze, then you'll have to "peek" ahead using the pfread function before you move the snake's head into a new location, like this:

     

    rem ** move snake's segments
     for z = 4 to 1 step 255
      y = z - 1
      snake_col[z] = snake_col[y]
      snake_row[z] = snake_col[y]
     next
     snake_col[0] = snake_col[0] + snake_e_w
     snake_row[0] = snake_row[0] + snake_n_s
    
    rem ** is there something there already?
    z = snake_col[0] : y = snake_row[0]
    if pfread(z,y) then goto gameover
    

    975241[/snapback]

     

    Sorry, I included the typo in that code. It should be:

     

    rem ** move snake's segments
     for z = 4 to 1 step 255
      y = z - 1
      snake_col[z] = snake_col[y]
      snake_row[z] = snake_row[y] : rem ** typo was in this line
     next
     snake_col[0] = snake_col[0] + snake_e_w
     snake_row[0] = snake_row[0] + snake_n_s
    
    rem ** is there something there already?
    z = snake_col[0] : y = snake_row[0]
    if pfread(z,y) then goto gameover
    

     

    Michael Rideout


  16. And as you see I used the player0 method of constructing the character - I didn't know if there was a way to make a snake with this that would act like the snake you gave in the example above.

    975110[/snapback]

     

    I couldn't think of a decent way to use a player for the snake, since I figured you'd want the snake to move around and change shape/directions kind of like the way it does in my second example. To do something similar with a player, you'll need to redefine the player shape a whole bunch-- which is doable, but could be very tedious to program because of all the possible shapes. Using a player does offer the advantage that the pixels can be smaller, though.

     

    I'll see if I can put together an example that uses a player for the snake, but I can't do it tonight.

     

    Also the snake can't go offscreen:

    if joy0up && player0y > 10 then player0y = player0y - 1
    if joy0down && player0y < 89 then player0y = player0y + 1
    if joy0left && player0x > 15 then player0x = player0x - 1
    if joy0right && player0x <167 then player0x = player0x + 1
    

     

    But I admit, I do like the way you showed above where the snake just wraps, could make for some harder levels if I don't put borders in places.

    975110[/snapback]

     

    Well, I expected that you wouldn't want to use wraparound; I just used it in my example because I didn't have any borders/walls, and I was really trying to show how you can program a shape to keep moving in a particular direction until you use the joystick (or cursor control keys in an emulator) to steer it in a different direction.

     

    Now, I'll post the code with you suggestions and show you the errors I get, and maybe you can point me in the right direction if I don't figure it out again.

     

     goto startme
    
    programstart
     gosub clear
     x = 0
     y = 0
    
     score = 10000
    
     rem ** this moves a snake made up of 5 playfield pixels
    
     dim snake_n_s = a
     dim snake_e_w = b
    
     dim snake_row = c
     rem ** snake_row is 5 bytes -- c, d, e, f, g
    
     dim snake_col = h
     rem ** snake_col is 5 bytes -- h, i, j, k, l
    
     dim frame = m
     dim speed = n
    
     snake_n_s = 0 : snake_e_w = 255 : speed = 15
    
     snake_row[0] = 5 : snake_col[0] = 16
     snake_row[1] = 5 : snake_col[1] = 17
     snake_row[2] = 5 : snake_col[2] = 18
     snake_row[3] = 5 : snake_col[3] = 19
     snake_row[4] = 5 : snake_col[4] = 20
    
     COLUBK = $00
     COLUPF = $C4
    
     rem ** plot the snake's position
     for z = 1 to 4
      pfpixel snake_col[z] snake_row[z] on
     next
     rem ** don't need to draw all segments each frame
    end
    
    gameloop
     rem ** snake's head
     pfpixel snake_col[0] snake_row[0] on
    
     rem ** draw the screen
     frame = 0
    
    wait
     drawscreen
    
     if joy0left then snake_e_w = 255 : snake_n_s = 0
     if joy0right then snake_e_w = 1 : snake_n_s = 0
     if joy0up then snake_n_s = 255 : snake_e_w = 0
     if joy0down then snake_n_s = 1 : snake_e_w = 0
    
     rem ** slowing things down
     frame = frame + 1
     if frame < speed then goto wait
     rem ** set spped to a lower number to speed up the snake
     rem ** useful for harder levels in the future
    
     rem ** now wee need to erase the snake's last segment
     pfpixel snake_col[4] snake_row[4] off
    
    rem ** move snake's segments
     for z = 4 to 1 step 255
      y = z - 1
      snake_col[z] = snake_col[y]
      snake_row[z] = snake_col[y]
     next
     snake_col[0] = snake_col[0] + snake_e_w
     snake_row[0] = snake_row[0] + snake_n_s
    
     rem ** snake wrap
     if snake_col[0] = 255 then snake_col[0] = 31
     if snake_col[0] = 32 then snake_col[0] = 0
     if snake_row[0] = 255 then snake_row[0] = 10
     if snake_row[0] = 11 then snake_row[0] = 0
    
     goto gameloop
    
    startme
     gosub clear
     COLUPF = $44
     gosub logo
     COLUP0 = $00
     COLUP1 = $00 : scorecolor = $00
    
    coloring
     g = g + 1
     COLUBK = g : COLUP0 = g : COLUP1 = g : COLUPF = $C4
     drawscreen
     if joy0fire then goto programstart
     goto coloring
    
    logo
     data logo_data
     %00000000,%00000000,%00000000,%00000000
     %00000000,%00000000,%00000000,%00000000
     %01111101,%00010111,%11011111,%01111100
     %01000101,%10010100,%01000001,%01000100
     %01000001,%01010100,%01000010,%01000000
     %01111101,%01010111,%11000100,%01110000
     %00000101,%01010100,%01001000,%01000100
     %00000101,%00110100,%01010000,%01000100
     %01111101,%00010100,%01011111,%01111100
     %00000000,%00000000,%00000000,%00000000
     %00000000,%00000000,%00000000,%00000000
    end
     for r = 0 to 10
      for c = 0 to 3
       b = 4 * r
       b = b + c
       temp1 = logo_data[b]
       if c = 1 then gosub flip_it
       if c = 3 then gosub flip_it
       playfield[b] = temp1
      next
     next
     return
    
     rem ** clears the screen
    clear
     for b = 0 to 47
      playfield[b] = 0
     next
     return
    
    flip_it
     temp2 = 0
     if temp1{0} then temp2{7} = 1
     if temp1{1} then temp2{6} = 1
     if temp1{2} then temp2{5} = 1
     if temp1{3} then temp2{4} = 1
     if temp1{4} then temp2{3} = 1
     if temp1{5} then temp2{2} = 1
     if temp1{6} then temp2{1} = 1
     if temp1{7} then temp2{0} = 1
     temp1 = temp2
     return
    

     

    The program works fine, until you use the snake for a little bit.  The snake continues to grow and after a few seconds the screen just freaks out (I guess it's because the snake continues to grow).  The last segment isn't turning off, although it is instructed to through the pfpixel off command.

    975110[/snapback]

     

    I see a number of problems right away.

     

    First, I can't get it to compile as is because you need to include the div_mul.asm file. Add this line at the very beginning of your code:

     

      include div_mul.asm
    

     

    (If you got it to compile, then you may have simply omitted that line when you were copying the code into your post.)

     

    Next, you have a typo right here:

     

      rem ** move snake's segments
      for z = 4 to 1 step 255
         y = z - 1
         snake_col[z] = snake_col[y]
         snake_row[z] = snake_col[y]
      next
    

     

    In the line that says "snake_row[z] = snake_col[y]", the second "col" should be "row," like this:

     

      rem ** move snake's segments
      for z = 4 to 1 step 255
         y = z - 1
         snake_col[z] = snake_col[y]
         snake_row[z] = snake_row[y]
      next
    

     

    That's the reason it's freaking out, since snake_col can go up to 31, but snake_row should go up to only 10, so setting snake_row[z] equal to snake_col[y] puts the wrong value in snake_row[z], and that value can be much too large. Fix that line, and the snake will move around correctly.

     

    Also, I see that you're using b, c, and g in your code, but in the sample code that I'd posted, those variables are being used for other things. It turns out that this is okay, because you aren't using them for different things at the same time. But in general, you should try not to reuse variables like that unless you're sure there won't be any conflicts. In other words, don't use b, c, and g during the actual game play if you're using them for storing other values (e.g., b is used for snake_e_w, c is used for snake_row[0], and g is used for snake_row[4]). This is my fault for not picking other letters to use in my examples, letters that you weren't already using, or that weren't used for other things in my logo screen example. As I said, in this case it's okay, but just be careful when you reuse variables for multiple purposes in the same program.

     

    I was also wondering if it was possible to make this snake without the pfpixel, to make it 'skinnier' as with a sprite or something.

    975110[/snapback]

     

    Yes, but it will be trickier and more tedious to do. As I said, I'll try to put together an example, tomorrow night at the earliest.

     

    I had no idea how to use the collision detection with this if I'm using pfpixel - it was simpler with the method in my first code.  Because of this, I didn't implement my gameover sequence.

    975110[/snapback]

     

    If you're going to use pfpixel to draw both the snake and the walls of the maze, then you'll have to "peek" ahead using the pfread function before you move the snake's head into a new location, like this:

     

    rem ** move snake's segments
     for z = 4 to 1 step 255
      y = z - 1
      snake_col[z] = snake_col[y]
      snake_row[z] = snake_col[y]
     next
     snake_col[0] = snake_col[0] + snake_e_w
     snake_row[0] = snake_row[0] + snake_n_s
    
    rem ** is there something there already?
    z = snake_col[0] : y = snake_row[0]
    if pfread(z,y) then goto gameover
    

     

    Note that this check is being done after the new position of the snake's head has been calculated, but before the snake's head has actually been drawn at the new position, so if the pfpixel at the new position is already on, then it means the snake is about to collide either with itself or with a wall.

     

    Oh, and I do like the color changing thing in the beginning ;)

     

    What is the generally accepted or best method for moving level to level?  Say my snake's head hits a certain pixel (the end of the maze) then move to the next level - all the while implementing different speeds as the level gets harder.

    975110[/snapback]

     

    Yes, I like the flashing colors, too!

     

    As for moving from one level to the next, that's up to how you want the game to work, as well as what the goal is. For example, if the primary goal is to navigate the maze without the snake hitting a wall or crossing over itself, then you probably need a secondary goal, too. For example, you mentioned reaching and touching a particular wall or section of wall, which (if you do that) you might want to draw with a player or missile, so it can be a different color than the rest of the maze. Or, you could have an opening in the maze wall, and the snake has to get through the maze and go through the opening to enter the next "room." Or, if you're going to draw both the snake and the maze with pfpixels, then you might use the players and missiles to draw objects that are scattered around the maze, and the snake is supposed to collect (or collide with and "eat") all of the objects without hitting a wall (or itself) in order to "clear" the current maze and advance to the next maze.

     

    To go from one level to the next, you could just clear the screen once the current maze has been completed successfully, and draw the next maze, repositioning the snake to the "starting" location for the new level. Also, besides speeding up the game from one level to the next, you might want to keep the same speed for a few levels before speeding up, and have some other kind of difficulty increase, such as starting with a short snake, and adding another segment every level or so to make the snake longer so it's harder to keep it from crossing over itself.

     

    Michael Rideout


  17. Wow - thanks for the help.  Haha, it's funny because after this post I sat down for hours and learned this language as best I could.  I made code for moving the snake and had collision testing that works for a gameover sequence.

     

    Thanks so much SeaGT for the help - now I have to go back through the code and clean it haha because I left in the pfpixel (well I coded all this before coming back to my thread).

     

    But as you mentioned - I think the rom will be an issue with this game.

    974256[/snapback]

     

    Drawing a playfield the way I demonstrated can definitely help save ROM in many cases, as well as a whole lot of machine cycles. If you're drawing a title screen, the machine cycles might not matter much, if you're setting the playfield pixels just once and then using drawscreen in a loop without setting the playfield pixels over again during each pass through the loop. But if you need to reset/regenerate the screen each time the loop executes, the pf drawing routines can use up a lot of valuable machine cycles, leaving less time for you to do other things.

     

    Can I have unlimited included files and what format do they need to be in?

    974256[/snapback]

     

    I'm not certain what you mean, but include files don't do any good after a game has been compiled and is running, because you can't "swap out" sections of the ROM by using different include files. It sounds like you really mean bankswitching, not include files. And no, bankswitching isn't unlimited. There are various schemes for implementing bankswitching. A month or two ago I posted a verion of bB 0.35 which allows the use of M-Network's bankswitching method, which can use about 16K of ROM and 2K of extra RAM. You might want to push your game as far as it will go in 4K of ROM to start out with, and then check out bankswitching if 4K isn't big enough to do what you want.

     

    Basically I need a way to make all my levels of mazes without running out of rom space.  So can I have a bunch of included files which created my different levels of mazes?  Is there an easier way to do this?

    974256[/snapback]

     

    Keep in mind that the method I showed you for drawing a playfield requires only 44 bytes per screen (assuming you aren't putting anything in row 11, which is invisible anyway since it's "behind" the score bar), so you ought to be able to squeeze in several screens or mazes by storing them as data that way.

     

    And I think working on my trailing snake will be the last thing I do/implement as it will probably give me some trouble.  I'll post my code when I go through and update it with all your helps.

     

     

    EDIT: I don't want the snake to grow - but I do want it to have a trailing tail like the original nibbles game.  I just want it a fixed length.  I don't want it to eat apples and grow, it's not the point of this game.  I'm gonna make mazes that you have to get through with your snake, maybe even a key that when it collides with the key it opens the door to the next level.

    974256[/snapback]

     

    I was thinking about this last night after I posted. If the snake has a fixed length, then you can define an array to store the position of each block or segment of the snake, and use a routine to advance each block to the position occupied by the block in front of it, sort of like this:

     

      rem * this moves a snake made up of 5 playfield pixels
    
      dim snake_n_s = a
      dim snake_e_w = b
    
      dim snake_row = c
      rem * snake_row is 5 bytes-- c, d, e, f, g
    
      dim snake_col = h
      rem * snake_col is 5 bytes-- h, i, j, k, l
    
      dim frame = m
      dim speed = n
    
      snake_n_s = 0 : snake_e_w = 255 : speed = 15
    
      snake_row[0] = 5 : snake_col[0] = 16
      snake_row[1] = 5 : snake_col[1] = 17
      snake_row[2] = 5 : snake_col[2] = 18
      snake_row[3] = 5 : snake_col[3] = 19
      snake_row[4] = 5 : snake_col[4] = 20
    
      COLUBK = $00
      COLUPF = $C4
    
      rem * plot the snake's position (last 4 segments only)
      for z = 1 to 4
         pfpixel snake_col[z] snake_row[z] on
      next
      rem * don't need to draw all 5 segments each frame
    
    loop
    
      rem * plot the snake's head
      pfpixel snake_col[0] snake_row[0] on
    
      rem * draw the screen
      frame = 0
    
    wait
    
      drawscreen
    
      rem * update the snake's direction from the joystick
      if joy0left then snake_e_w = 255 : snake_n_s = 0
      if joy0right then snake_e_w = 1 : snake_n_s = 0
      if joy0up then snake_n_s = 255 : snake_e_w = 0
      if joy0down then snake_n_s = 1 : snake_e_w = 0
    
      rem * wait a bit to slow things down
      frame = frame + 1
      if frame < speed then goto wait
      rem * set speed to a lower number to speed up the snake
    
      rem * erase the snake's last segment
      pfpixel snake_col[4] snake_row[4] off
    
      rem * move the snake's segments forward
      for z = 4 to 1 step 255
         y = z - 1
         snake_col[z] = snake_col[y]
         snake_row[z] = snake_row[y]
      next
      snake_col[0] = snake_col[0] + snake_e_w
      snake_row[0] = snake_row[0] + snake_n_s
    
      rem * if snake moved "offscreen," then wrap around
      if snake_col[0] = 255 then snake_col[0] = 31
      if snake_col[0] = 32 then snake_col[0] = 0
      if snake_row[0] = 255 then snake_row[0] = 10
      if snake_row[0] = 11 then snake_row[0] = 0
    
      rem * keep repeating
      goto loop
    

     

    Note that if you make the snake double back on itself (e.g., let it move left, then press the right arrow so it moves right), the drawing routine above will mess up, since it erases the last segment and draws the new position of the head segment, but doesn't redraw all 5 segments each frame. However, you already said you don't want the snake to be able to double back or cross over itself, so that won't be a problem with the above routine, although you would need to check the pixel for the new position of the head before you actually draw the head there, to be sure it isn't on already (which would mean that either the snake is about to run into a wall, or is about to cross over itself).

     

    Michael Rideout


  18. Okay, I got row logic to work, and it only cost me 100-150 bytes. Inefficient, but it'd only run once per hit, so any rolling wouldn't show up for more than one frame.

    974592[/snapback]

     

    That's great! By the way, I was a little off on my row values. If bally is 31, then the ball is straddling rows 3 and 4 (but since row 3 is just "air," the ball is hitting row 4). Any value equal to 31 and a multiple of 8 (i.e., 39, 47, 55, 63, etc.) is straddling two rows. But when bally is 63, the ball is straddling row 7 and row 8 (and row 8 is just "air," so the ball is hitting row 7). So if the ball has collided with the playfield, then:

     

    if bally <= 30, the ball hit a wall;

    if bally >= 31 and bally <= 38, the ball may have hit a brick in row 4;

    if bally = 39, the ball may have hit a brick in row 4 or row 5;

    if bally >= 40 and bally <= 46, the ball may have hit a brick in row 5;

    if bally = 47, the ball may have hit a brick in row 5 or row 6;

    if bally >= 48 and bally <= 54, the ball may have hit a brick in row 6;

    if bally = 55, the ball may have hit a brick in row 6 or row 7;

    if bally >= 56 and bally <= 63, the ball may have hit a brick in row 7;

    if bally >= 64, the ball hit a wall.

     

    If bally < 1, then the ball has moved off the top of the screen, so player 1 (or the top paddle) has missed the ball, and you can set ball_moving to 0. If bally > 89, then the ball has moved off the bottom of the screen, so player 0 (or the bottom paddle) has missed the ball, and you can set ball_moving to 0.

     

    Michael Rideout


  19. Basically I'm creating a game (duh! wouldn't be in here no would I?), I created a logo screen by looking at other people's coding.  Basically you see the logo screen of my game then you can push space to continue to the game.  I have that part down so far and it compiles.

     

    The problem is, I need some help with my game.  I just need help getting started, then I can complete it.  I need to make a player that is controllable by the arrow keys, and the player is constantly moving.  Basically it's gonna be like a snake from the game nibbles, but not really.  All I need is some example code of how to get it started (since there aren't any tutorials out there) of a moving character (non-stop moving) that is controlled by the keys and the game ends when he hits a wall or himself.

     

    Any suggestions?  Starting points?  Here's my code of the logo screen so far:

     

    COLUBK = 112
    
    COLUPF = 68
    
    COLUP0 = 196
    
    programstart
    gosub clear
    
    x = 0
    y = 0
    end
    
    startme
    gosub clear
    COLUPF = 68
    gosub logo
    COLUP0 = 0
    COLUP1 = 0 : scorecolor = 0
    500
    g = g + 1
    COLUBK = g : COLUP0 = g : COLUP1 = g : COLUPF = 196
    drawscreen
    if joy0fire then goto programstart
    goto500
    
    logo
    pfpixel 1 2 on : pfpixel 2 2 on : pfpixel 3 2 on : pfpixel 4 2 on 
    pfpixel 5 2 on : pfpixel 7 2 on : pfpixel 11 2 on : pfpixel 13 2 on 
    pfpixel 14 2 on : pfpixel 15 2 on : pfpixel 16 2 on : pfpixel 17 2 on 
    pfpixel 19 2 on : pfpixel 20 2 on : pfpixel 21 2 on : pfpixel 22 2 on 
    pfpixel 23 2 on : pfpixel 25 2 on : pfpixel 26 2 on : pfpixel 27 2 on 
    pfpixel 28 2 on : pfpixel 29 2 on : pfpixel 1 3 on : pfpixel 5 3 on 
    pfpixel 7 3 on : pfpixel 8 3 on : pfpixel 11 3 on : pfpixel 13 3 on 
    pfpixel 17 3 on : pfpixel 23 3 on : pfpixel 25 3 on : pfpixel 29 3 on 
    pfpixel 1 4 on : pfpixel 7 4 on : pfpixel 9 4 on : pfpixel 11 4 on 
    pfpixel 13 4 on : pfpixel 17 4 on : pfpixel 22 4 on : pfpixel 25 4 on 
    pfpixel 1 5 on : pfpixel 2 5 on : pfpixel 3 5 on : pfpixel 4 5 on 
    pfpixel 5 5 on : pfpixel 7 5 on : pfpixel 9 5 on : pfpixel 11 5 on 
    pfpixel 13 5 on : pfpixel 14 5 on : pfpixel 15 5 on : pfpixel 16 5 on 
    pfpixel 17 5 on : pfpixel 21 5 on : pfpixel 25 5 on : pfpixel 26 5 on 
    pfpixel 27 5 on : pfpixel 5 6 on : pfpixel 7 6 on : pfpixel 9 6 on 
    pfpixel 11 6 on : pfpixel 13 6 on : pfpixel 17 6 on : pfpixel 20 6 on 
    pfpixel 25 6 on : pfpixel 1 7 on : pfpixel 5 7 on : pfpixel 7 7 on 
    pfpixel 10 7 on : pfpixel 11 7 on : pfpixel 13 7 on : pfpixel 17 7 on 
    pfpixel 19 7 on : pfpixel 25 7 on : pfpixel 29 7 on : pfpixel 1 8 on 
    pfpixel 2 8 on : pfpixel 3 8 on : pfpixel 4 8 on : pfpixel 5 8 on 
    pfpixel 7 8 on : pfpixel 11 8 on : pfpixel 13 8 on : pfpixel 17 8 on 
    pfpixel 19 8 on : pfpixel 20 8 on : pfpixel 21 8 on : pfpixel 22 8 on 
    pfpixel 23 8 on : pfpixel 25 8 on : pfpixel 26 8 on : pfpixel 27 8 on 
    pfpixel 28 8 on : pfpixel 29 8 on
    return
    
    clear
    
    r29 asm
    ldx #47
    lda #0
    clearpf
    sta playfield, x
    dex
    bpl clearpf
    end
    return
    

    973889[/snapback]

     

    First of all, I like your logo or title screen! However, judging by all the pfpixel commands, it looks like you used the playfield drawing tool to draw your logo and then generate the necessary pfpixel statements. You should be aware that the pf drawing routines take up a lot of machine cycles, and using a lot of pfpixel statements to draw a screen also takes up a lot of ROM. It's almost always much quicker to "poke" the desired playfield data directly into the playfield array, and it can also save a lot of ROM in some cases. Here's another version of your code, which I've modified by removing the pfpixel commands and replacing them with the necessary data and routines to draw the playfield directly. I also replaced your in-line assembly routine to clear the playfield with the equivalent bB code, to show you how you can do that in bB.

     

      include div_mul.asm
    
      COLUBK = $70
      COLUPF = $44
      COLUP0 = $C4
    
    programstart
      gosub clear
      x = 0
      y = 0
    end
    
    startme
      gosub clear
      COLUPF = $44
      gosub logo
      COLUP0 = $00
      COLUP1 = $00 : scorecolor = $00
    
    500
      g = g + 1
      COLUBK = g : COLUP0 = g : COLUP1 = g : COLUPF = $C4
      drawscreen
      if joy0fire then goto programstart
      goto 500
    
    logo
      data logo_data
      %00000000,%00000000,%00000000,%00000000
      %00000000,%00000000,%00000000,%00000000
      %01111101,%00010111,%11011111,%01111100
      %01000101,%10010100,%01000001,%01000100
      %01000001,%01010100,%01000010,%01000000
      %01111101,%01010111,%11000100,%01110000
      %00000101,%01010100,%01001000,%01000000
      %01000101,%00110100,%01010000,%01000100
      %01111101,%00010100,%01011111,%01111100
      %00000000,%00000000,%00000000,%00000000
      %00000000,%00000000,%00000000,%00000000
    end
      for r = 0 to 10
         for c = 0 to 3
            b = 4 * r
            b = b + c
            temp1 = logo_data[b]
            if c = 1 then gosub flip_it
            if c = 3 then gosub flip_it
            playfield[b] = temp1
         next
      next
      return
    
    clear
      for b = 0 to 47
         playfield[b] = 0
      next
      return
    
    flip_it
      temp2 = 0
      if temp1{0} then temp2{7} = 1
      if temp1{1} then temp2{6} = 1
      if temp1{2} then temp2{5} = 1
      if temp1{3} then temp2{4} = 1
      if temp1{4} then temp2{3} = 1
      if temp1{5} then temp2{2} = 1
      if temp1{6} then temp2{1} = 1
      if temp1{7} then temp2{0} = 1
      temp1 = temp2
      return
    

     

    When your original code is compiled, there are 2002 bytes of ROM free (but you're probably getting a little more than that, because I've added some code to read joystick 1 to one of bB's include files, hence I get less ROM free than you do.) On the other hand, when the modified code is compiled, there are 2587 bytes of ROM free, so using the data statement to define the playfield pixels, and "poking" the data directly into the playfield array using two nested for..next loops, saves 585 bytes of ROM. And I think it's easier to draw the playfield using data statements, because you can more easily see what's being drawn (i.e., by imagining the 0s as blanks and the 1s as playfield pixels that are "on"). However, if you do this, you must flip the second and fourth playfield bytes, since the 2600 reads those bytes "backwards" as it's drawing the playfield, hence I'm calling flip_it to reverse the second and fourth bytes. (The alternative is to store those bytes backwards in the data statements, but that's more difficult to do, so I prefer to store the data in the way that looks natural to the reader's eye, and then use the flip_it routine to reverse the necessary bytes.)

     

    As for moving the "snaze" around the screen, you first need to decide what you're going to draw it with-- playfield pixels or player/missile graphics. Assuming that the snaze can be very long, you'll probably want to draw it with playfield pixels, but that's up to you. If you draw the snaze with playfield pixels, then you can use the players and missiles for walls, or for other objects (e.g., "food" that the snaze eats, which makes it grow longer).

     

    Either way, you'll want to define one or two variables to indicate and control the directions the snaze is moving in. For example, you could have one variable that can have four or eight different values, corresponding to N, S, E, and W movement (and maybe NE, SE, SW, and NW movement as well, if you want to allow the snaze to move diagonally). You would keep the movement value the same, so the snaze keeps moving in the same direction, and then change the movement value when the joystick or cursor keys are pressed. If you want to use two variables instead of one for the movement, then one variable could control the left/right direction value, and the other variable could control the up/down direction value.

     

    Here is a simple example that moves a playfield pixel around:

     

      dim snaze_row = a
      dim snaze_col = b
      dim snaze_n_s = c
      dim snaze_e_w = d
      dim frame = e
    
      snaze_row = 5
      snaze_col = 16
      snaze_n_s = 0
      snaze_e_w = 255
    
      COLUBK = $04
      COLUPF = $1A
    
    loop
    
      rem * plot the snaze's position (1 playfield pixel)
      pfpixel snaze_col snaze_row on
    
      rem * draw the screen
      frame = 0
    
    wait
    
      drawscreen
    
      rem * update the snaze's direction from the joystick
      if joy0left then snaze_e_w = 255 : snaze_n_s = 0
      if joy0right then snaze_e_w = 1 : snaze_n_s = 0
      if joy0up then snaze_n_s = 255 : snaze_e_w = 0
      if joy0down then snaze_n_s = 1 : snaze_e_w = 0
    
      rem * wait a bit to slow things down
      frame = frame + 1
      if frame < 10 then goto wait
    
      rem * erase the snaze's last position
      pfpixel snaze_col snaze_row off
    
      rem * update the snaze's new position
      snaze_col = snaze_col + snaze_e_w
      snaze_row = snaze_row + snaze_n_s
    
      rem * if it moved "offscreen," then wrap around
      if snaze_col = 255 then snaze_col = 31
      if snaze_col = 32 then snaze_col = 0
      if snaze_row = 255 then snaze_row = 10
      if snaze_row = 11 then snaze_row = 0
    
      rem * keep repeating
      goto loop
    

     

    This example assumes that there will be no diagonal movement, so moving up or down will set the left/right (e/w) movement value to 0, and moving left or right will set the up/down (n/s) movement value to 0. A movement value of 1 will add to the row or column position, moving the snaze down or right. A movement value of 255 will subtract 1 from the row or column position (because 255 is the same as -1), moving the snaze up or left.

     

    Of course, this example just moves one playfield pixel around. If the snaze is more than one pixel long, things will be more tricky, because you'll need to leave a "trail" as the snaze moves around, and erase the last pixel, hence you'll need to have variables for remembering the position of the last pixel of the snaze.

     

    Also, this example allows the playfield pixel to wraparound from one side of the screen to the other, but presumably you won't want to allow that in your game. Still, I hope this example helps you to see how an object such as a playfield pixel can be moved continuously in a given direction, with the joystick (or cursor keys in an emulator program) being used to steer the object around.

     

    Michael Rideout


  20. Hello All,

     

    ok maybe I am missing a step but using Distella a created a .asm file, how do I convert this into a .bas file for BATARI to create a working .bin file?

     

    Thanks, Tim

    973851[/snapback]

     

    Sorry, it doesn't work that way. batari BASIC programs are written in batari BASIC, and assembly programs are written in assembly. Although you can include assembly code in a batari BASIC program, you can't compile a pure assembly program with batari BASIC-- at least, not really. You *could* write an all-assembly program in batari BASIC and compile it with batari BASIC, but the compiled code will contain all of batari BASIC's included routines, which will take up ROM space. So if you disassemble a .bin file into an .asm file, you don't want to compile it with batari BASIC. Instead, you want to compile it with DASM. batari BASIC does use DASM to compile .asm files into .bin files, but first batari BASIC compiles .bas files into .asm files, and that's the step you'll want to avoid if you're working with a disassembled .asm file.

     

    I suggest working directly with the .asm file, using the 6502 assembly language, and then compiling it with DASM once you're done hacking it. However, be aware that disassembled .asm files can be a bit wacky, if Distella tried to disassemble data into assembly commands. (Some parts of an assembly program are data, such as the bytes which define the playfield text display for "The Texas Chainsaw Massacre" title screen, and those data bytes should not be disassembled into assembly commands, since they aren't intended to be assembly commands, and will look extremely wacky if Distella tries to convert them into assembly commands.)

     

    The best thing to do, if you're trying to hack a game like TTCM, is check to see if someone else has already disassembled that game. If not, then you will need to figure out which portions of the code are assembly commands, and which portions are data. Then you can create a custom config file for that game, to tell Distella which sections of code are data and should be left as is, and disassemble the game using the custom config file. Then Distella will create an .asm file which has assembly commands where appropriate, and un-disassembled data where appropriate. Once you have such an .asm file, you can try hacking it, and then compile the altered .asm file using DASM.

     

    Michael Rideout


  21. Thank you very much, I actually was able to get on the screen the letters I wanted after hours of work

    973440[/snapback]

     

    Glad to hear it! Working with playfield text can be tricky.

     

    however with your help I will now be able to line up the letters a little better. Thanks for your help. One last question about this screen....is it possible to stop it from flashing?

    973440[/snapback]

     

    To stop the letters from flashing, you're going to have to find out where the code is that's doing it, and figure out how to change it without messing up anything. When I get home later I'll take a look at it.

     

    Also I finally found Hack-o-matic II and it's way better than ShowGfx!!!!

    973440[/snapback]

     

    I'm not familiar with ShowGfx, so I can't really compare them, but I know from experience with other types of programs that one program can be better than another in certain ways, and vice versa. In other words, each program may have its own strengths and weaknesses. ShowGfx may be superior to Hack-O-Matic II in some ways, and inferior in other ways. Likewise, Hack-O-Matic II may be inferior to other programs in some ways. Sometimes I like to "collect" different programs so I can jump from one to another and use the one that's best for the job. But I've never tried to hack games, so I haven't ever collected different hacking utilities, and the only reason I have Hack-O-Matic II is because someone had asked about hacking colors and I was trying to answer them, so I downloaded Hack-O-Matic II to help me better relate to what they were up against.

     

    Michael Rideout


  22. Okay, here is what the title screen looks like:

     

     

     

    And here's the start of the relevant section of code in Hack-O-Matic II:

     

     

    That's weird, I can't see the first two pictures, so I'll repost them. This is what they were supposed to look like:

     

    post-7456-1133242491_thumb.jpg

     

    post-7456-1133242541_thumb.jpg

     

    (Hope they show up this time.)

     

    Michael Rideout


  23. Hello Everyone I  need some help, has anyone ever changed the opening Title graphics the read "THE TEXAS CHAINSAW MASSACRE"? I am currently using SHOWGFX and can not figure out where the Words appear or how to change them. Is there a better graphics tool for this? Thanks Tim

    972571[/snapback]

    They're drawn with the playfield. Using Hack-O-Matic II, it looks like they start at around 0b88.

     

    Michael Rideout

    972589[/snapback]

     

    Thanks, now that I know where they are any advice on changing the lettering? Every time I make a few changes the whole program stops workin.

     

    Thanks, Tim

    972925[/snapback]

    Hmm, that shouldn't happen, so you must be changing more than just the bytes for the title letters? I don't have SHOWGFX and am not familiar with it, but I have Hack-O-Matic II. If you change just the bytes for the title letters, the game should still work, just with a different-looking title screen.

     

    But the thing is, playfield graphics can be difficult to use for text displays, because (1) the letters tend to look big and blocky-- although you can still attain reasonably decent results if you try to make the letters a bit rounded (see below)-- but more importantly, (2) you have to understand how the bytes are being used. Once you understand that, you are closer to successfully hacking the playfield text to say something different.

     

    Okay, here is what the title screen looks like:

     

     

     

    And here's the start of the relevant section of code in Hack-O-Matic II:

     

     

     

    (By the way, I was wrong before-- it actually starts at 0b7e, not 0b88.) There are a number of important points that you need to understand about how the bytes are being used for the playfield:

     

    (1) The bytes-- or the data for the letters-- are stored "upside down," not just for each letter, but for the three rows of letters. In other words, the data for the third row of letters begin at 0b7e, with the byte for the last scan line of row three given first, then the byte for the next-to-last scan line of row three, etc.

     

    (2) The data for each row of letters must be divided up into several sections, due to the way the playfield works. The playfield has only two-and-a-half bytes(!), so the programmer must move the data into those two-and-a-half bytes twice for each scan line-- first for the left half of the screen, and then for the right half of the screen. There are two ways the playfield can be drawn-- normally, where the right side is an exact duplicate of the left side; or reflected, where the right side is a mirror image of the left side. In this game, the title is drawn using the normal method, so the data looks like this: half a byte, one whole byte, one whole byte, half a byte, one whole byte, one whole byte. Of course, since the programmer is changing the bytes before the right half of the screen is drawn, the right half is different than the left half (which is an "asymmetrical" playfield, although it's still drawn using the normal playfield mode). So because of the way the playfield is being drawn,

    -- the data for the first four columns of playfield pixels are 0b7e through 0b8c;

    -- the data for the next eight columns of playfield pixels are 0b8d through 0b9b;

    -- the data for the next eight columns of playfield pixels are 0b9c through 0baa;

    -- the data for the next four columns of playfield pixels are 0bab through 0bb9;

    -- the data for the next eight columns of playfield pixels are 0bba through 0bc8;

    -- the data for the last eight columns of playfield pixels are 0bc9 through 0bd7.

     

    (3) However, we can't store half a byte-- unless we store two halves of a byte in one whole byte and then shift the data as needed to get the desired half, which the programmer(s) didn't do-- so the data at 0b7e through 0b8c, and 0bab through 0bb9, are stored as whole bytes, even though only half of each of those bytes are actually being used. As you can see from the picture above, the left half (or high nibble) of each byte is used, and the right half (or low nibble) is left blank.

     

    (4) Due to the way the 2600 reads the bytes as it draws the playfield, some of the bytes have to be reversed-- that is, the 2600 reads them from right-to-left instead or from left-to-right, as follows:

    -- the byte for the first four pixels is read right-to-left (backwards);

    -- the byte for the next eight pixels is read left-to-right (normally);

    -- the byte for the next eight pixels is read right-to-left (backwards);

    -- the byte for the next four pixels is read right-to-left (backwards);

    -- the byte for the next eight pixels is read left-to-right (normally);

    -- the byte for the next eight pixels is read right-to-left (backwards).

     

    (5) To save ROM, the programmer(s) didn't try to map the entire playfield, just the three rows where the letters of the title are being drawn. In fact, the blank spaces or scan lines between the three rows of text aren't even being stored. This means you can redefine the shapes of the letters by hacking the corresponding bytes, but the new text is limited to three rows of letters (or other shapes) that are five lines tall, and you can't extend the new letters into the blank scan lines that are above, between, and below those three rows of text.

     

    I realize that this is all a bit much to absorb, so I've chopped out the blank lines of the title screen with a paint program, and changed the background and foreground colors to emphasize the way the screen is divided up into six vertical strips:

     

    post-7456-1133236752_thumb.jpg

     

    The colors make it kind of hard to read the text, but I hope you can see how there are six areas going from left to right. I've drawn arrows under each of these six areas, pointing either right-to-left or left-to-right to indicate the direction in which the Atari is reading the bytes. To make things even clearer, let's look at how each area corresponds to the bytes in the program code:

     

    post-7456-1133237728.gif post-7456-1133237800_thumb.jpg

     

    post-7456-1133238570.gif post-7456-1133238625_thumb.jpg

     

    post-7456-1133239166.gif post-7456-1133239199_thumb.jpg

     

    post-7456-1133239707.gif post-7456-1133239748_thumb.jpg

     

    post-7456-1133240409.gif post-7456-1133240470_thumb.jpg

     

    post-7456-1133241163.gif post-7456-1133241214_thumb.jpg

     

    I used a paint program to color the Hack-O-Matic II screens, and colored the text in the screenshots to match, to try to help you see how the data in the program code corresponds to the text in the screen display. As you can see, the data is stored upside-down, the data is stored backwards for some bytes, and the data for some bytes uses only the left (high) half of the byte. So if you want to hack the title text to say something else, you're going to have to be careful about which bytes you change, do everything upside-down, do most of it backwards, etc. You might want to use a piece of graph paper, and divide it up into sections to match the way it's divided up in memory, then create the new text on the graph paper and use it to help you hack the bytes accordingly.

     

    As I mentioned above, you can create better-looking text with playfield pixels if you try to round the letters. Unfortunately, you can't do that in this game, due to the way it stores the data, because each byte is actually used to draw several scan lines (to help save ROM space). Anyway, the screenshot below shows a title screen that I made for a game I started to write (but then put aside), and you can see how the letters look a little better because of the way I made the letters a little more rounded.

     

    post-7456-1133242175_thumb.jpg

     

    Good luck in your hacking, and I hope this post has helped you understand how "The Texas Chainsaw Massacre" title screen is stored.

     

    Michael Rideout


  24. ballx = 35 means the ball is hitting bricks 0 and 1 simultaneously.

    972579[/snapback]

     

    It might be, if there are in fact bricks in both of those spots.

     

    What I would suggest doing would be to determine the existence of brick/wall in the four corners of the ball; depending upon the position of the ball, this may require looking at one, two, or four bricks. If the number of bricks present in the top two corners exceeds that in the bottom, move the ball downward. If the number of bricks present in the bottom two exceeds that in the top, move the ball upward. If the number of bricks present in the left two exceeds that in the right, move the ball rightward. If the number of bricks present in the right two exceeds that in the left, move the ball leftward. If all four corners are occupied by "brick", set X direction toward the center of the screen and set Y direction to "down" (shouldn't happen, but that's probably the best course of action).

     

    Doing things this way will allow for effective handling of all cases where the ball hits bricks; if it hits the left side of a brick while going diagonally upward, it will bounce off but continue its upward path.

    972609[/snapback]

    Yes, that's a good point about hitting the side of a brick and continuing up (or down). I'd thought about that as well last night, but forgot to mention it. As for checking the four corners of the ball, that's only necessary if it's potentially hitting three bricks at once. Most of the time it will be hitting only one or two bricks. I'd started working on some routines to handle these cases, but wasn't happy with the way they were going (I wanted to find a way to consolidate or simplify them), and I removed the code before I posted it because I wasn't sure how Luigi301 wanted the ball and bricks to behave. After all, my vision of how the game "should" work may be very different from what he has in mind. :) But I'll keep working on it and post my solutions if he wants, and anyone else can optimize the code for ROM space and/or machine cycles.

     

    Michael Rideout

×
×
  • Create New...