Jump to content


  • Content Count

  • Joined

  • Last visited

Community Reputation

39 Excellent

About JeffJetton

  • Rank
    Star Raider

Contact / Social Media

Profile Information

  • Gender
  • Location
    Nashville, TN
  • Interests
  • Currently Playing

Recent Profile Visitors

2,658 profile views
  1. Yup. 🙂 Just needed a refresher on which format number meant what.
  2. I had a quick question about DASM just now and Googled up the documentation. Holy moly! What a huge difference! The current documentation is AMAZING, especially compared to the charmingly scruffy, but not-so-up-to-date, text file of yore. Kudos to whomever has been doing what must be quite a bit of work. (Andrew, maybe?)
  3. Another vote for green. Maybe gray if you want to give a B&W choice. But having playing cards on a black background just seems... idiomatically incorrect for a VCS game. (Didn't Atari have a policy against black backgrounds for anything that wasn't a space game?)
  4. I'm going to suggest something a lot simpler for your shuffle routine: Don't shuffle the cards in the first place. 🙂 Just start out with all the possible card values in a block of memory somewhere, in whatever order you want to generate them. Maintain a pointer that refers, at any given moment, to one of the cards. Every frame, increment (or decrement) that pointer. When it gets to the top (or bottom), bump it down (or up) to wherever the other end currently is*. So it's as if the game is constantly cycling through every remaining card, one after the other, all the time. When the player starts the game with that first "fire", they get whatever card the pointer is currently pointing at. Remove that card from the "deck" and then remove the "memory hole" by copying values above it down one byte (or below it up one byte). Adjust references to the end of your memory block accordingly, or you could use a terminator value, such as zero, to signal the end (or beginning) of the block. When they place that card with the fire button, you then "deal" then next card that's at whatever position the constantly-cycling pointer is at that point. There's no way a human can possibly time where the pointer is, so it is essentially random. Repeat the process of shifting memory to remove the "hole", waiting for the next "fire" to figure out what the next card is, etc. This will appear, for all intents and purposes, as if you are dealing from the top of a randomly-shuffled deck. But really it's more like you're dealing a card from a randomly-selected place in an unshuffled deck each time, with the "randomness" supplied by the human player's own timing. The effect should be the same either way. I did something similar on an Apple 1 game I wrote recently, although with dice roll outcomes rather than cards (and without needing to remove values each time like you will). It's also 6502 assembly, so feel free to take a look: https://github.com/JeffJetton/apple1-shut-the-box * You might want to keep careful track of how many cycles the loop back to the bottom (or top) of the memory block takes when you reach the end, and then make sure that you take up the same number of cycles when you don't reach the end and instead just do the increment or decrement. This could be done by putting in one or more nop instructions or something like that. Otherwise, the card at the top (or bottom) will be slightly more likely to be dealt out, since the pointer will "linger" there slightly longer than on all the other cards.
  5. And, as an aside, some computers like the ZX80 and (when in "fast" mode) the ZX81 would routinely drop the video signal logic when it came time for any sort of intensive calculations. The Gigatron, a contemporary 8-bit computer without a microprocessor, finds a nice compromise by displaying black for a user-selected, alternating portion of the scan lines, depending on whether you want a slow program with a nice picture, or a faster program with a dimmer, striped/striated picture. Sort of similar to the "Venetian Blinds" trick used in Video Chess. Although Bob Whitehead used it there in order to display more objects, rather than to give the processor more time to think about game logic. (I don't think any carts ever used something like that to simply to provide more time for program logic, Gigatron-style, did they?) Another option is to simply reduce the number of scanlines used for the visual part of the game, rather than get rid of them all together. That would give you more time in the overscan and/or vertical blank for "thinking", at the expense of a more "letterbox" image. Didn't a lot of carts use that trick?
  6. Trying my code on Lillapojkenpåön's 88-row example yields the following. Hope it's correct! 😎 0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,224,0,0,0,0,0,0,0,0,0,0,224,0,0,0,0,0,0,0,0,0,0,224,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0 0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,136,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0 0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,136,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0 0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,136,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0 0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,132,0,0,0,0,0,0,0,0,0,0,132,0,0,0,0,0,0,0,0,0,0,132,0,0,0,0,0,0,0,0,0,0,132,0 0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,192,0,0,0,0,0,0,0,0,0,0 224,0,0,0,0,0,0,0,0,0,0,240,0,0,0,0,0,0,0,0,0,0,240,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,240,0,0,0,0,0,0 0,0,0,0,240,0,0,0,0,0,0,0,0,0,0,224,0,0,0,0,0,0,0,0,0,0,192,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0 0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,0,0,0,0,0,130,0,0 0,0,0,0,0,0,0,0,130,0,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128 0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,132,0,0,0,0,0,0,0,0,0 0,132,0,0,0,0,0,0,0,0,0,0,132,0,0,0,0,0,0,0,0,0,0,132,0,0,0,0,0,0,0,0,0,0,132,0,0,0,0,0,0,0,0,0,0,132,0,0,0,0,0,0,0,0,0,0,132,0,0,0,0,0,0,0 0,0,0,132,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0 0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0 0,0,0,0,0,0,0,240,0,0,0,0,0,0,0,0,0,0,240,0,0,0,0,0,0,0,0,0,0,240,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0 0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,136,0,0,0,0,0,0,0,0,0,0,132,0,0,0,0,0,0,0,0,0,0,132,0,0,0,0,0,0,0,0,0,0,132,0,0,0,0,0,0,0,0,0,0 132,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0 0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,192,0,0,0,0,0,0,0,0,0,0,224,0,0,0,0,0,0 0,0,0,0,240,0,0,0,0,0,0,0,0,0,0,248,0,0,0,0,0,0,0,0,0,0,252,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0 0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0 0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,128
  7. Not that anyone asked, but... here's a stab at the problem using Python: # Assumes each row has same number of columns INFILE = 'my_cool_level.txt' OUTFILE = 'leveldata.txt' BYTES_PER_OUTPUT_ROW = 64 EMPTY = '.' BYTE_SEPARATOR = ',' # Read in data, chopping off any newlines indata = [] with open(INFILE) as infile: for row in infile: indata.append(row.rstrip('\n')) # Build a list of output bytes outdata = [] for i in range(len(indata[0])): column = [] for j in range(len(indata)): if indata[j][i] == EMPTY: column.append('0') else: column.append('1') while len(column) > 0: if len(column) >= 8: byte = column[0:8] column = column[8:] else: byte = column + ['0'] * (8 - len(column)) column = [] byte = byte[::-1] byte = ''.join(byte) outdata.append(int(byte, 2)) # Write out the bytes with open(OUTFILE, 'w') as outfile: byte_counter = 0 for byte in outdata: outfile.write(str(byte)) byte_counter += 1 if byte_counter == BYTES_PER_OUTPUT_ROW: outfile.write('\n') byte_counter = 0 else: outfile.write(BYTE_SEPARATOR) print('Done!')
  8. Depends on the game. As DirtyHairy points out above, not all games store/track the entire game state in RAM. So looking at the RAM will not give you all the important information. (I think Combat might be one of those games... maybe some of Video Olympics too?) That is probably completely unlike just about every other computer system you might be familiar with. It certainly is for me. It's sort of a holdover from the old days of video arcade games, which did not use a microprocessor and had no RAM in the traditional sense. Game state was stored all over the place, in a variety of counters, shift registers, various flip flops, and other hardware components. The Atari 2600 wound up being a bit of a hybrid machine, with the TIA chip (essentially a single-chip version of one of those old-school, discrete-component circuit boards) handling a lot of things all by itself, and the 6507 microprocessor being more of a coworker than a boss.
  9. As an aside, I've been digging into the memory map lately and found it interesting that, internally, the 6507 is actually "looking" for the stack in page one (from $01FF down to $0100). That's baked into the design of the 6502 (and therefore the 6507 too) and cannot be changed. However address line A8 is not hooked up to the RIOT chip. So any attempt by the 6507 to read or write to anything in page one will have exactly the same effect as reading and writing to page zero (and the other way around). For example, when the 6507 tries to push a value onto the stack at $01FF (binary 0000 0001 1111 1111) the RIOT sees it as being no different from pushing it onto $00FF (binary 0000 0000 1111 1111), since the underlined bit is irrelevant. Lines A10 and A11 are ignored by the RIOT in the same way, incidentally. So the 6507 could also access that same stack location at $0DFF (binary 0000 1101 1111 1111) or $08FF (binary 0000 1000 1111 1111), and so on. And, of course, lines A13-A15 don't even come out of the chip in the first place, although the 6507 doesn't "know" that. So that same byte will also be accessible at, for example, $E5FF (binary 1110 0101 1111 1111), etc. That's 6 out of 16 bits that flat-out don't matter when you're accessing RIOT RAM!
  10. Using "Go" to write an "Atari" emulator? How appropriate! 😎
  11. Oh, just saw that you're putting in issues. Thanks, Andrew! I'll work on making those tweaks. I really appreciate it!
  12. Thanks! Yeah, sorry. That's supposed to link to the "documentation" for the code, which doesn't exist yet. 😞
  13. Hey MantaNZ, you might want to check out my beginning Atari programming notes that I've been (slowly) putting together. Actually, I'd really appreciate your feedback--I could use some guinea pigs! https://github.com/JeffJetton/atari-examples Still very much work-in-progress. I'm rethinking some of the later stuff, but I think the first section is pretty solid. It's coming from the same angle as your C beginner's course idea. It's at the super-noob level* and explains a lot of the things that puzzled me early on but seem to get glossed over in a lot of other tutorials. It goes very slowly. (I'm certainly not an Atari assembly programming master myself, which I think actually helps!) * Well, it does relate some things to higher-level programming concepts, and I don't really explain how binary and hex number systems work. But other than that, it's pretty noob-friendly!
  • Create New...