From 1c5f7cf293384f6354c1b40daaa7c55895fda169 Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Tue, 18 Dec 2012 21:50:01 -0500 Subject: [PATCH] Import tb_6502 vesion 1.1 --- tb_6502/Changelog | 134 + tb_6502/FAQ.tb_6502 | 233 ++ tb_6502/Makefile | 18 + tb_6502/README.tb_6502 | 130 + tb_6502/SINCOS | Bin 0 -> 146 bytes tb_6502/TODO | 3 + tb_6502/apple2_c00.inc | 12 + tb_6502/tb_6502.dsk | Bin 0 -> 143360 bytes tb_6502/tb_6502.s | 4291 +++++++++++++++++++++++++++++++ tb_6502/tools/rle_data.c | 173 ++ tb_6502/tools/string_to_apple.c | 26 + tb_6502/tools/test_random.c | 35 + tb_6502/tools/wait.c | 15 + 13 files changed, 5070 insertions(+) create mode 100644 tb_6502/Changelog create mode 100644 tb_6502/FAQ.tb_6502 create mode 100644 tb_6502/Makefile create mode 100644 tb_6502/README.tb_6502 create mode 100644 tb_6502/SINCOS create mode 100644 tb_6502/TODO create mode 100644 tb_6502/apple2_c00.inc create mode 100644 tb_6502/tb_6502.dsk create mode 100644 tb_6502/tb_6502.s create mode 100644 tb_6502/tools/rle_data.c create mode 100644 tb_6502/tools/string_to_apple.c create mode 100644 tb_6502/tools/test_random.c create mode 100644 tb_6502/tools/wait.c diff --git a/tb_6502/Changelog b/tb_6502/Changelog new file mode 100644 index 0000000..05bf55e --- /dev/null +++ b/tb_6502/Changelog @@ -0,0 +1,134 @@ +8 April 2003 ++ Got simple hello world to compile and run when entered in hex + by hand [ od -t x1 hello ] into apple emulator. ++ start work on add-file-to-disk-image program + +10 April 2003 ++ Add to disk program now lets you add arbitrary files to a disk image. ++ Hello World program now works from "BRUN TB_6502" + +11 April 2003 ++ Move from default Apple start addy of $800 to $c00 so we can + use low-res page flipping (page1 is from $800-$bff) ++ Got print_text_xy routine working ++ Got blit working! VMW opening screen now comes up! + +14 April 2003 ++ RLE compress the sprites ++ get title screen displaying after figuring out minor problem + [was > 256 bytes] + +15 April 2003 ++ Add support for in-line x and y on put_text_xy + +16 April 2003 ++ Worked on dos3.3 utils rather than any useful menu stuff + +9 May 2003 ++ Have menu partially working, plus the about and phobos sprites loading + +15 May 2003 ++ Have "ABOUT" running the way I like, and not as cluttered as it was. + +28 May 2003 ++ Fix up printxy to correctly wrap at 8-byte boundary ++ have the story output text set up correctly. ++ add a "clear_bottom_ function. + +1 June 2003 ++ Story works ++ Spent 3 hours figuring out why put_text_xy have sporadic problem. + Stupid 6502 and no-16-bit addition. So very tired... + +12 June 2003 ++ Add arrow key support ++ Faster clear-screen + +13 June 2003 ++ Fix arrow keys being backwards, add escape key support + +21 June 2003 ++ Get normal TB left/right support, and clipping. ++ Add missile support ++ Fix various minor bugs. ++ Set up page flipping. Make clear_screen, clear_bottom, and blit + handle this properly ++ Get preliminary shields/level/score indicator working ++ (yes my gf was out of town, how can you guess) + + +11 July 2003 ++ Got an enemy to appear in upper left + +14 July 2003 ++ Enemy moving back and forth, but major heisenbug. Why, why, why? + +15 July 2003 ++ Not heisenbug at all. Was running the move-enemy routine when + no enemy.out. Glad I didn't post on usenet asking why my code + was broken! + +16 July 2003 ++ Minimal y movement implemented + +17 July 2003 ++ Added random number generator + +18 July 2003 ++ Re structure enemy handling code to do a copy to zero page first, + thus streamlining things ++ Have missile <-> enemy collision detection working ++ Have minimal score keeping working ++ Have minimal enemy spawning working ++ (Yes gf was out on work related business, how did you guess) + +29 August 2003 ++ Long delay due to move to Ithaca ++ Annoying work getting 16-bit BCD printing to work. Harder than + it looks! + +30 August 2003 ++ Implement Proper Collision detection ++ Enemies can actually damage you ++ Explosions no longer move ++ Have "GAME OVER" print when you die + +7 September 2003 ++ Have it print "Level 1" at start of level + +27 September 2003 ++ HUGELY busy with grad school. Trying to get this + done for minigames competition + +28 September 2003 ++ Actual varied levels working. Trying to adjust speed for playability. ++ Added two more enemies, as having 8 is easier to do with mask instructions + ;) ++ Attempting to add Boss. ++ Added shield increment every 100 points ++ S now toggles sound ++ P now pauses ++ While waiting for keypress, random number gen seeded ++ Updated timinings. yae is too slow :( am trusting + xapple2 as it seems to play most other games properly. + Should fire up my _real_ IIe. + +11 July 2004 ++ Finally got around to uploading on my real IIe. + Subjective delay timing, seems to work. ++ Boss seems to act irregularly? + +13 July 2004 ++ Scrolling stars implemented. + +18 July 2004 ++ "Ending" for end of level 1 ported over. ++ Bonuses added ++ Hi-score (though not to disk) implemented ++ Final balancing on my Apple IIe Platinum ++ Fix some minor bugs ++ Fixed bug where unitialized memory was causing star scrolling to mess up ++ Bumped version number to 1.0 + +24 July 2004 ++ Added sort-of-working paddle/joystick code. diff --git a/tb_6502/FAQ.tb_6502 b/tb_6502/FAQ.tb_6502 new file mode 100644 index 0000000..e21f368 --- /dev/null +++ b/tb_6502/FAQ.tb_6502 @@ -0,0 +1,233 @@ +FAQ. Some questions shamelessly stolen from the tb_asm FAQ + + +Q. Why? + +A. My friend John got a Gameboy + Advance for Christmas. He suggested I port my game + Tom Bombem to it. + + In actuality the specs of the GBA are similar to the machine I + originally wrote TB1 on. It was on a 386-33 with 320x200x256 graphics + and constrained to 640kB of RAM. The game was written in 16-bit + PASCAL with some 32-bit assembly. + + I somehow got side-tracked into an 8k Linux x86 text-mode version first, + and then it seemed obvious to port it to the 6502. Finally the disks + full of poorly written way-to-slow BASIC space games I wrote when + I was in elementary school have been vindicated! + + +Q. The game runs too fast/too slow! It is unplayable! + +A. The game has been balanced and tested on an actual Apple IIe platinum. + If you are running on an emulator, your emulator probably isn't + emulating 100% accurately. + If you are on a real Apple IIe... well it's probably my fault. + If you're clever you can find the timing code in the source + and fix it yourself. + + + +Q. Why did it take you so long to finish? + +A. I originally rushed to get this game entered in the 2003 Minigames + Competition in the 4k game section. I had to cut down on the + features a lot to get it to fit in 4k. + + Despite all this work, I finished 53rd or so. Most of the + complaints were negative because there aren't that many good Apple ][ + emulators out there, but a highlight was the infamous "blocky graphics" + comment by the Atari 2600 programmer. + + Anyway this experience burned me out on the whole concept for a bit, + plus I started grad school which sucked up most of my time. + + But anyway I got a chance to finish it this summer. + + +Q. How did you do the graphics? + +A. With The Gimp. Used 16 color indexed + palette. Saved as xpm. Edited with text editor. + + + +Q. Why LOW-RES graphics mode? + +A. Because I like 16 colors. High-res on the Apple ][ really isn't all + that great and can only do 4 colors or so with weird placement rules. + + And all of you people with Atari 800s and Commodore's feel free to laugh. + But my code here will run in full 16 color mode even on the Original + Apple ][ released in 1977. + + In any case I like blocky graphics, probably dating to my time doing + ANSI graphics for BBS's in the early 90s. + + And don't think low-res mode was a cheating way out. The Apple ][ + framebuffer is _horribly_ convoluted and non-linear. Apparently + this saved some chips on the memory refresh... but man is it a pain + to program. + + +Q. Why is all the text in this game SHOUTING AT ME? + +A. For extra perversity, I want the game to work on all machines + back to the original 1977 Apple ][. Lower-case letters were an + optional add-on until the Apple //e came out much later. + + + +Q. What is the high score? + +A. A bit of a silly question as its impossible to prove. + + The highest _possible_ score is 9999 I am pretty sure, due + to the limitations of a 16 bit BCD number (which is how the + score is stored). + + +Q. Why does the ship have its engines constantly on, even though + it is moving at a constant velocity? + +A. Ummmm... friction. Yeah... space friction. + + + +Q. Why are the stars moving so quickly? Are you going faster than light? + +A. If you look closely you'll notice the stars repeat. Hence you + are really flying very fast in a big circle. Hey, maybe that's + why the engine is constantly firing! + + + +Q. Where in that tiny ship are all of those missiles stored? + +A. In the seventh dimension. + + +Q. Why the seventh dimension? + +A. The others were all full. + + +Q. Why is there a guinea pig in the game? + +A. A local guinea pig threatened me with violence if I did not include + a picture of her. + + +Q. What have you learned from all this assembly programming? + +A. I'm just reminded what Professor Bruce Jacob always said... + A computer is just a state machine. + + + +Q. Why are there only 6 enemies / 2 missiles / shields go up at 100/ etc? + +A. Game balance. Just trying to keep it challenging yet not overwhlmingly + so. [For the original tb1 it was "because my 386 can't keep up" but + that should be less of a problem these days]. + + If you _must_ have it some other way, feel free to mess with the constants + on the first page of the tb_6502.s file, but I cannot guarantee what + the consequences might be! + + +Q. Will there be a sequel? + +A. Yes, it will be released shortly before either the release of + "Duke Nukem Forever (tm)" or the heat death of the universe, + which ever happens first. + + +Q. Why can't Vince stay consitent between "HISCORE" and "HIGH SCORE" + including all possibly variations of "HI-SCORE" "HIGH_SCORE" usw? + +A. The world may never know. + + +Q. What does "usw" mean? + +A. Und So Weiter. + + +Q. That wasn't helpful. + +A. This isn't a question. + + +Q. What's the highest level you can get to? + +A. No matter how you try, once you get to level 7 it will + keep repeating. This is because I multiply the level + by 16 in various places for enemy movement, and it it goes + above 7 then the byte will be negative causing + Bad Things(tm) to happen. + + +Q. Well why don't you modify the code so it doesn't go haywire + after level 7? + +A. I am lazy. Also it should be too hard to get to level 7 anyway + + +Q. What are the enemies supposed to be? + +A. An envelope, a clip-board, a cigarette, a telephone, a dollar-bill, + and an un-identified yellow thing, possibly a banana. All things + malicious marketers might have in excess. + The apple II version has in addition a green toothbrush and a + purple toupe. Those wacky marketers! + +Q. How come the stars appear in straight bands insteas of scattered in the + sky? + +A. Because my pseudo-random number algorithm is at times more pseudo + than random. + + +Q. Why does vince use the stack so often, when it would make much more + sense to backup the Y register to the zero page? + +A. Too much intel x86 programming has warped my mind into thinking + stack usage is a good way of mitigating limited register count. + + Must remind myself the zero page is like a 256-byte register file. + + + +Q. Why is the 6502 instruction set so obtuse? + +A. I HAVE NO IDEA. In coding I keep stumbling across instructions + that I think would be _so_ useful. But they don't exist. But + apparently the instructions I pine for are fairly obvious... + an enhanced 65C02 was released with "bonus" opcodes. Sadly + I cannot use them because of the aforementioned want of Apple ][ + compatibility [the 65C02 wasn't around until the //e. + + ABS (IND), X indexing : would be great working with structs. + BRA -- Branch Always : a great opcode name, but also remove + the need for 16-bit absolute JMP's when + a short branch would do + DEA -- Decrement Accumulator : + That's right, there's no way to decrement + the accumulator. You have to CLC clear + carry then ADC $FF. Yet you can dec + X or Y with one-byte. Weird. + INA -- Incrememnt Accumlator: + See DEA. Yes, even more perverse. Taking + 3 bytes to do what should be a common task. + PHX/PLX + PHY/PLY -- Push/Pop X/Y : + These would be so useful. Otherwise + you can only push/pop the accumulator. + STZ -- Store Zero to Memory : + Would save a lot of LDA #$0 / STA pairs. + TRB/TSB -- Test and Set/Reset bit: + Wow, getting even more CISC here. Atomic + test/set bit instructions. We're ready + for SMP now. diff --git a/tb_6502/Makefile b/tb_6502/Makefile new file mode 100644 index 0000000..586d506 --- /dev/null +++ b/tb_6502/Makefile @@ -0,0 +1,18 @@ +all: TB_6502 + + +TB_6502: tb_6502 + make_b ./tb_6502 ./TB_6502 0xC00 + +tb_6502: tb_6502.o + ld65 -C ./apple2_c00.inc -o tb_6502 tb_6502.o + +tb_6502.o: tb_6502.s + ca65 -o tb_6502.o -l tb_6502.s + +disk: + dos33 tb_6502.dsk SAVE B TB_6502 + + +clean: + rm -f *.lst *.o tb_6502 *~ add_to_disk TB_6502 make_b a.out diff --git a/tb_6502/README.tb_6502 b/tb_6502/README.tb_6502 new file mode 100644 index 0000000..97a0a7e --- /dev/null +++ b/tb_6502/README.tb_6502 @@ -0,0 +1,130 @@ +TOM BOMBEM: Merciless Marauding Malicious Marketers + 6502 Apple IIe Edition +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +http://www.deater.net/weave/vmwprod/tb1/tb_6502.html + + by Vince Weaver + + version 1.1 -- 24 July 2004 + + +Quotes about tb_6502: +~~~~~~~~~~~~~~~~~~~~~ + + "The graphics are crude and blocky." + -- random Atari 2600 developer + + +System Requirements: +~~~~~~~~~~~~~~~~~~~~ + Apple ][ Computer + At least 32kB of RAM + Disk drive, or Super Serial Card to load game + + +Background: +~~~~~~~~~~~ + You are Tom Bombem, a shy new intern on Moonbase Alpha. + Somewhat against your will it has become your job to + defend Earth! See the "Story" option in the game + for the rest of the story. + + tb_6502 comes before "tb1: Invasion of the Inanimate Objects" + chronologically, for those who might care. + + +Keybindings: +~~~~~~~~~~~ + Use arrow keys, or i,j,k,m to manuever and navigate menus. + ' ' shoots and selects. + 'h' displays help. 's' toggles sound 'p' pauses + +Options/Hiscore File: +~~~~~~~~~~~~~~~~~~~~~ + + not implemented yet + +Game Play: +~~~~~~~~~~ + Manuever your ship avoiding the falling objects. Shoot them. + + Only 2 missiles can be in the air at the time [this is _not_ a bug. + it's a limit of your ship's missile guidance system]. + + Every 100 points your shields will increase. + + There are special bonuses you can earn at the end of each level. + + + No Shields Hit : going through an entire level without + having an enemy hit your ship + + All Enemies Destroyed : all enemies were destroyed before + scrolling off the screen. [Note, + ramming an enemy with your ship + _DOES_ count as destroying it. Just + don't let them get by you] + + Perfect Shot: Every missile fired hits an enemy. + + + At the end each level you fight the boss. Then the game starts over + with the enemies moving faster! + + +Compiling / Running: +~~~~~~~~~~~~~~~~~~~~ + + RUNNING: + Just obtain an apple emulator. Point it to the tb_6502.dsk image. + Upon booting it should run! + + Also, you can get a real Apple II computer and download the disk + image to a real floppy. That is a bit more complicated. + + COMPILING: + + The following compile instructions assume you are using Linux. + + * first you need the c65 package from: + http://www.cc65.org/ + + To install cc65 you need to unpack, and do a + "make -f make/gcc.mak" from the cc65/src directory. + + The utils we need are ca65 and ld65. Copy them somewhere in your + path (ie /usr/local/bin). + + * To make the disk image you will need the dos33fsprogs package + of mine, available from: + http://www.deater.net/weave/vmwprod/apple/dos33fs.html + Unpack and instal. "make; make install" + + * Now hopefully just type "make" in the tb_6502 directory and + the program should be assembled. "make disk" should copy + the new version to the disk image, assuming all the tools + are installed properly. + + + +About: +~~~~~~ + + When I was much younger, I would type in BASIC games on the Apple II. + I always wanted to write games myself, but the ones I wrote in BASIC + were too slow. I was just starting to learn assembly when we got + a 386 and I moved on to other things. + + But now, only 25 years too late, I finally wrote a playable game! + + The hope is maybe eventually using this as a stepping-board to + creating a Game Boy Advance TomBombem game. + + This game was originally written for the 4k mini-game competition. + It finished embarassingly low in the standings. I've added some + more features now so it is well over the 4k mark. + +Author: +~~~~~~~ + Vince Weaver + http://www.deater.net/weave/ + Special Thanks to KRG + 24 July 2004 + diff --git a/tb_6502/SINCOS b/tb_6502/SINCOS new file mode 100644 index 0000000000000000000000000000000000000000..c467de3ae57a01f5faf973aad090138bedf8cfcb GIT binary patch literal 146 zcmbQhz|O(N(7_$|?Lyn;_;)20JV@n2S4h@FL z3x)=#?rUg7oHjAgJY{q$z*CdKi$j-TfgwXAhY>?>gwAD+$P-2enhXgX<_rsr7%Dg{ ZA)4-?YHH`OLRQ_!VZ+cA!N9=41pvl_CtLsk literal 0 HcmV?d00001 diff --git a/tb_6502/TODO b/tb_6502/TODO new file mode 100644 index 0000000..9babbe0 --- /dev/null +++ b/tb_6502/TODO @@ -0,0 +1,3 @@ +Save high score to disk. + +OPTIMIZE! diff --git a/tb_6502/apple2_c00.inc b/tb_6502/apple2_c00.inc new file mode 100644 index 0000000..72588b0 --- /dev/null +++ b/tb_6502/apple2_c00.inc @@ -0,0 +1,12 @@ +MEMORY { + ZP: start = $00, size = $1A, type = rw; + RAM: start = $C00, size = $8E00, file = %O; +} + +SEGMENTS { +CODE: load = RAM, type = ro; +RODATA: load = RAM, type = ro; +DATA: load = RAM, type = rw; +BSS: load = RAM, type = bss, define = yes; +ZEROPAGE: load = ZP, type = zp; +} diff --git a/tb_6502/tb_6502.dsk b/tb_6502/tb_6502.dsk new file mode 100644 index 0000000000000000000000000000000000000000..d4fd059b22d9be879742203b6bfc07d476e42736 GIT binary patch literal 143360 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 literal 0 HcmV?d00001 diff --git a/tb_6502/tb_6502.s b/tb_6502/tb_6502.s new file mode 100644 index 0000000..14ea471 --- /dev/null +++ b/tb_6502/tb_6502.s @@ -0,0 +1,4291 @@ +.define EQU = + +; blt = bcc +; bge = bcs + +;; ZERO PAGE +CH EQU $24 +CV EQU $25 +BASL EQU $28 +BASH EQU $29 +H2 EQU $2C +COLOR EQU $30 +YSAV EQU $34 +YSAV1 EQU $35 +RANDOM_SEED EQU $43 + +;; Our Zero Page Allocations + +PADDLE_STATUS EQU $CA +HISCORE_1 EQU $CB +HISCORE_2 EQU $CC +HISCORE_3 EQU $CD +HISCORE_H EQU $CE +HISCORE_L EQU $CF + +BOSS_X EQU $D0 +BOSS_XADD EQU $D1 +BOSS_COUNT EQU $D2 +BOSS_SMOKE EQU $D3 +BOSS_EXPLODING EQU $D4 +BOSS_WAITING EQU $D5 +BOSS_HITS EQU $D6 +BOSS_SHOOTING EQU $D7 + +ENEMIES_SPAWNED EQU $D8 +ENEMY_TYPE EQU $D9 +ENEMY_WAVE EQU $DA +CURRENT_INIT_X EQU $DB +CURRENT_ENEMY_KIND EQU $DC +TOTAL_ENEMIES_OUT EQU $DD +SCROLL EQU $DE +SOUND_ON EQU $DF + +SHIPX EQU $E0 +SHIPXADD EQU $E1 +ENEMY_PL EQU $E2 +ENEMY_PH EQU $E3 +MISSILE_PL EQU $E4 +MISSILE_PH EQU $E5 +GR_PAGE EQU $E6 +LEVEL EQU $E7 +SHIELDS EQU $E8 +SCOREL EQU $E9 +SCOREH EQU $EA +BONUS_FLAGS EQU $EB + +BCD_BYTEH EQU $EC +BCD_BYTE EQU $ED + +COL_X1 EQU $EC +COL_X2 EQU $ED +COL_X3 EQU $EE +COL_X4 EQU $EF + +ENEMY_EXPLODING EQU $F0 +ENEMY_KIND EQU $F1 +ENEMY_X EQU $F2 +ENEMY_Y EQU $F3 +ENEMY_XADD EQU $F4 +ENEMY_YADD EQU $F5 +ENEMY_XMIN EQU $F6 +ENEMY_XMAX EQU $F7 + +BETWEEN_DELAY EQU $F8 +ENEMY_WAIT EQU $F9 + +STRINGL EQU $FA +STRINGH EQU $FB +PARAM2 EQU $FC +RESULT EQU $FD +LASTKEY EQU $FE +TEMP EQU $FF + +;; VECTORS +BASIC EQU $3D0 ;; VECTOR for return to Applesoft + +KEYPRESS EQU $C000 +KEYRESET EQU $C010 + +SPEAKER EQU $C030 + +;; SOFT SWITCHES +GR EQU $C050 +TEXT EQU $C051 +FULLGR EQU $C052 +TEXTGR EQU $C053 +PAGE0 EQU $C054 +PAGE1 EQU $C055 +LORES EQU $C056 +HIRES EQU $C057 + +PADDLE_BUTTON0 EQU $C061 +PADDL0 EQU $C064 +PTRIG EQU $C070 + +;; MONITOR ROUTINES +HLINE EQU $F819 ;; HLINE Y,$2C at A +VLINE EQU $F828 ;; VLINE A,$2D at Y +CLRSCR EQU $F832 ;; Clear low-res screen +CLRTOP EQU $F836 ;; clear only top of low-res screen +SETCOL EQU $F864 ;; COLOR=A +BASCALC EQU $FBC1 ;; +HOME EQU $FC58 ;; Clear the text screen +WAIT EQU $FCA8 ;; delay 1/2(26+27A+5A^2) us +SETINV EQU $FE80 ;; INVERSE +SETNORM EQU $FE84 ;; NORMAL +COUT1 EQU $FDF0 ;; output A to screen + + +;; GAME PARAMETERS +NUM_MISSILES EQU 2 +NUM_ENEMIES EQU 6 +UP_SHIELDS EQU 32 +WAVE_SIZE EQU 16 +WAVES_TILL_BOSS EQU 5 + +;; BONUS_FLAGS +PERFECT_SHIELDS EQU $80 +PERFECT_KILLS EQU $40 +PERFECT_AIM EQU $1 + + +;========================================================== +; MAIN() +;========================================================== + + + ;============================== + ; back up part of the zero page + ;============================== + + lda #>zero_page_save + sta BASH + lda #(score_string+31) + sta STRINGH + lda #<(score_string+31) + sta STRINGL + jsr print_high_score + + ;============= + ; put vmw logo + ;============= + + lda #$7 ; y=7 + sta CV + lda #$8 ; x=8 + sta CH + lda #>vmw_sprite + sta STRINGH + lda #vmw_string ; string = vmw_string + sta STRINGH + lda #opener_sprite + sta STRINGH + lda #opener_sprite_2 + sta STRINGH + lda #mercy_string ; string = MMMM + sta STRINGH + lda #help_string ; string = "H FOR HELP" + sta STRINGH + lda #zero_page_save + sta BASH + lda #new_game_string ; string starts at "NEW GAME" + sta STRINGH + lda #vince_sprite + sta STRINGH + lda #about_lines + sta STRINGH + lda #help_lines + sta STRINGH + lda #phobos_sprite + sta STRINGH + lda #story_lines + sta STRINGH + lda #evil_ship_sprite + sta STRINGH + lda #tom_sprite + sta STRINGH + lda #you_are_tom + sta STRINGH + lda #earth_sprite + sta STRINGH + lda #ending_lines + sta STRINGH + lda #susie_sprite + sta STRINGH + lda #susie_lines + sta STRINGH + lda #tom_head_sprite + sta STRINGH + lda #tom_sigh + sta STRINGH + lda #missile_0 ; clear the missile struct + sta MISSILE_PH ; should make this clear all BSS + lda #enemy_0 + sta ENEMY_PH + lda #(level_string+9) + sta STRINGH + lda #<(level_string+9) + sta STRINGL + + lda #0 + sta BCD_BYTEH + lda LEVEL + sta BCD_BYTE + jsr print_bcd_byte + + + ;====================== + ; Print level on screen + ;====================== + + lda #>(level_string_xy) + sta STRINGH + lda #<(level_string_xy) + sta STRINGL + + jsr print_text_xy + + ldx #20 + jsr wait_X_100msec ; pause for 3 seconds + bit KEYRESET ; clear keyboard + + ;================================== + ; Enter graphics mode, clear screen + ;================================== + + jsr set_page0_gr ; set graphics mode + jsr clear_screen ; clear screen + + +draw_stars: + + ;===================== + ; Setup star field + ;===================== + + lda #>(star_field) + sta STRINGH + lda #<(star_field) + sta STRINGL + + ldy #$0 +star_init: + jsr random_number + and #$9f + clc + adc #$4 + sta (STRINGL),Y + iny + lda #$0 + sta (STRINGL),Y + iny + bne star_init + + lda #$0 + sta SCROLL + + + ;/========================\ + ;+ + + ;+ MAIN GAME LOOP + + ;+ + + ;\========================/ + +main_game_loop: + jsr clear_screen ; clear screen + jsr show_stars + + + + + +done_scrolling: + + ; ================================ + ; put out new enemies (if needed) + ; ================================ + + inc BETWEEN_DELAY ; inc how long we've delayed + lda BETWEEN_DELAY ; load it in + cmp ENEMY_WAIT ; have we waited long enough? + beq reset_delay + + jmp move_enemies ; if not, go on to movement +reset_delay: + + ; delay==wait, so attempt to put out new enemy + + lda BETWEEN_DELAY + and #$1 + sta BETWEEN_DELAY ; reset delay + + ; special case for boss + + lda #$9 ; if boss, don't keep track of + cmp ENEMY_TYPE ; how many enemies were spawned + bne not_boss_dont_clear + + lda #$1 ; store 1 so we don't increment wave + sta ENEMIES_SPAWNED + +not_boss_dont_clear: + + ; see if we are at a new wave + ; basically, if 16 have been spawned, change + + lda ENEMIES_SPAWNED + and #$0f + bne same_enemy_type ; if not 16 gone by, move on + + ;======================= + ; change the enemy type + + inc ENEMIES_SPAWNED + + jsr random_number + and #$7 ; get a random number 0-7 + sta ENEMY_TYPE + + inc ENEMY_WAVE + + lda ENEMY_WAVE ; have we gone enough waves to reach boss? + cmp #WAVES_TILL_BOSS + bne not_boss_yet + + lda #$8 + sta ENEMY_TYPE + + + +not_boss_yet: + + ; set various constants + ; these may be overriden later + + + lda #20 + sec + sbc LEVEL + sta ENEMY_WAIT ; enemy_wait=20-level + + ; set kind and init x to be random by default + + lda #$ff + sta CURRENT_ENEMY_KIND + sta CURRENT_INIT_X + + + +same_enemy_type: + + ; find empty enemy slot + + ldy #$0 ; point to enemies[0] + tya + +find_empty_enemy: + pha + lda (ENEMY_PL),Y ; get enemy[y].out + beq add_enemy + + pla + clc + adc #$9 + tay + cpy #(NUM_ENEMIES*9) + bne find_empty_enemy + + + jmp move_enemies ; no empty, slots, move on + + +add_enemy: + pla + + ;============================================== + ; First see if we must wait for enemy to clear + ; types 2 and 8 + + lda ENEMY_TYPE + cmp #$2 + + bne check_type_8 + + lda TOTAL_ENEMIES_OUT + beq change_to_type_3 + jmp move_enemies +change_to_type_3: + lda #$3 + sta ENEMY_TYPE + + jsr random_number + and #$8 + sta CURRENT_ENEMY_KIND + + jsr random_number + and #$1F ; mask off so 0-31 + clc + adc #$2 + asl A + sta CURRENT_INIT_X + jmp setup_enemy_defaults + +check_type_8: + + cmp #$8 + beq before_boss_stuff + jmp check_type_9 + +before_boss_stuff: + + ;====================== + ; before boss stuff + + lda TOTAL_ENEMIES_OUT + beq prepare_for_boss + jmp move_enemies + +prepare_for_boss: + + ;=============== + ; HANDLE BONUSES + ;=============== + + ; Set text mode + + jsr set_page0_text + jsr HOME + + ; Print "BONUS POINTS" + + lda #>bonus_string + sta STRINGH + lda #bonus_shields + sta STRINGH + lda #bonus_kills + sta STRINGH + lda #bonus_aim + sta STRINGH + lda #no_bonus_string + sta STRINGH + lda #34 + + lda CURRENT_INIT_X + bpl store_init_x + + jsr random_number + and #$1f + clc + adc #$2 + asl + +store_init_x: + iny ; X + sta (ENEMY_PL),Y + + ; enemy_y is always 0 by default + + iny ; Y + lda #$0 + sta (ENEMY_PL),Y + + lda #$0 + iny + sta (ENEMY_PL),Y ; xadd + iny + sta (ENEMY_PL),Y ; yadd + lda #$2 + iny + sta (ENEMY_PL),Y ; xmin + iny + lda #$24 + sta (ENEMY_PL),Y ; ymin + + dey ; xmin + dey ; yadd + dey ; xadd + + + ;=========================================== + ; Enemy specific inits + + lda ENEMY_TYPE + beq enemy_type_0 + cmp #$1 + beq enemy_type_1 + jmp enemy_type_2 + +enemy_type_0: +enemy_type_1: + + ;================================ + ; ENEMY TYPE 0 and 1 + ; diagonal, no wait + ; movement proportional to level + + lda LEVEL ; xadd = level + sta (ENEMY_PL),Y + + iny + + lsr A + ora #$1 + sta (ENEMY_PL),Y ; yadd = level/2 + jmp move_enemies + +enemy_type_2: + ;===================== + ; Enemy Type 2 + ; just a place-holder + ; waits for enemies to die then moves on to 3 + + cmp #$2 + bne enemy_type_3 + jmp move_enemies + + +enemy_type_3: + + cmp #$3 + bne enemy_type_4 + + ;====================== + ; Enemy type 3 + + lda #$1 + sta (ENEMY_PL),Y ; xadd=1 + + iny + + lda LEVEL + sta (ENEMY_PL),Y ; yadd=level + + jmp move_enemies + +enemy_type_4: + + cmp #$4 + bne enemy_type_5 + + + ;========================= + ; Enemy Type 4 + ; Horizontal, then fall + + lda #$2 + sta (ENEMY_PL),Y ; xadd = 2 + + iny + + jsr random_number + ora #$80 ; set negative + sta (ENEMY_PL),y ; yadd = -(random%128) + ; this means bop back and forth a random + ; time, then drop + + jmp move_enemies + + +enemy_type_5: + cmp #$5 + bne enemy_type_6 + + ;======================== + ; Enemy Type 5 + ; "wiggle" + + lda #$1 + sta (ENEMY_PL),y ; xadd=1 + + iny + lda LEVEL + sta (ENEMY_PL),y ; yadd=2 + + iny + jsr random_number + and #$0f + clc + adc #$2 + sta (ENEMY_PL),y ; xmin=(rand%16)+2 + + + dey ; yadd + dey ; xadd + dey ; y + dey ;x + asl A + sta (ENEMY_PL),y + iny ;y + iny ; xadd + iny ; yadd + iny ; xmin + + jsr random_number + and #$0f + clc + adc (ENEMY_PL),Y + adc #$02 + iny + sta (ENEMY_PL),Y ; xmax = xmin+(rand%16)+2 + + jmp move_enemies + + +enemy_type_6: + cmp #$6 + beq enemy_type_7 + cmp #$7 + beq enemy_type_7 + jmp enemy_type_8 +enemy_type_7: + ;===================== + ; Enemy Types 6+7 + ; "Rain" + + + + jsr random_number + and #6 + bne no_use_own_x + + dey ; y + dey ; x + + lda SHIPX + cmp #$2 + bpl shipx_ok + lda #$2 ; stupid bug where gets stuck is < xmin + +shipx_ok: + + asl A + sta (ENEMY_PL),Y ; one-in-four chance we use shipx as X + + iny ; y + iny ; xadd + +no_use_own_x: + + lda #$0 + sta (ENEMY_PL),Y ; xadd=0 + iny + lda #$1 + sta (ENEMY_PL),Y ; yadd = 1 + + jmp move_enemies + +enemy_type_8: +enemy_type_9: + + ;====================== + ; Things flung by boss + + + dey ; y + dey ; x + + lda BOSS_X + clc + adc #$5 + asl A + sta (ENEMY_PL),Y ; enemy_x=boss_x+5 + + iny + lda #$3 + asl A + asl A + sta (ENEMY_PL),Y ; enemy_y=3 + + + iny + lda #$0 + sta (ENEMY_PL),Y ; xadd=0 + + iny + lda #$2 + sta (ENEMY_PL),Y ; yadd=2 + + + + + +move_enemies: + + ;============================================== + ; Move Enemies! (first thing, if no new added) + ;============================================== + + ldy #$0 ; point to enemies[0] +handle_enemies: + + tya + pha ; store y on stack + + lda (ENEMY_PL),Y ; get enemy[y].out + bne load_enemy_zero_page ; if enemy.out then we are good + + jmp skip_to_next_enemy ; enemy is not out, so skip to next + + + + ;========================================== + ; load this enemy stuff into zero page for + ; easier access + ;========================================== + +load_enemy_zero_page: + ldx #ENEMY_EXPLODING +load_to_zero_page: + iny ; point to exploding + lda (ENEMY_PL),Y + sta 0,X ; store to zero page + inx + cpx #(ENEMY_XMAX+1) ; see if reached end + bne load_to_zero_page ; if not keep copying + + ;================================ + ; skip all movement and collision + ; if exploding + ;================================ + + lda ENEMY_EXPLODING + beq move_enemy_x + jmp draw_enemy + + ;================================ + ; Start the enemy movement engine + ;================================ + + + ;======== + ; Move X + ;======== + +move_enemy_x: + clc + lda ENEMY_X ; X + adc ENEMY_XADD ; x+=xadd + sta ENEMY_X + + lsr A + + cmp ENEMY_XMIN ; are we less than xmin? + bmi switch_dir_enemy_x ; if so, switch direction + + cmp ENEMY_XMAX ; are we greater than xmax? + bpl switch_dir_enemy_x ; if so, switch direction + + jmp move_enemy_y + + +switch_dir_enemy_x: + + ; switch X direction + + lda #$0 ; load zero + sec + sbc ENEMY_XADD ; 0 - ENEMY_XADD + sta ENEMY_XADD ; store it back out, negated + jmp move_enemy_x ; re-add it in + + ;======== + ; Move Y + ;======== + +move_enemy_y: + + lda #$0 ; load in zero + cmp ENEMY_YADD ; compare to YADD + + bmi no_y_special_case ; if minus, we have special case + + inc ENEMY_YADD + bne done_enemy_y + + lda #$0 + sta ENEMY_XADD + lda #$2 + sta ENEMY_YADD + + ; increment y + ; is it > 0? + ; if not keep going + ; if so, yadd=level*2 + + jmp done_enemy_y + +no_y_special_case: + clc + lda ENEMY_Y ; get Y + adc ENEMY_YADD ; y+=yadd + sta ENEMY_Y ; store back out + + lsr A + lsr A + + cmp #$12 ; is y<=12? + bmi done_enemy_y ; if so no need to do anything + beq done_enemy_y + + ; off screen + + pla ; pop saved Y off stack + tay + pha ; push y back on stack + + lda #$0 + sta (ENEMY_PL),Y ; set enemy[i].out=0 + + dec TOTAL_ENEMIES_OUT + + lda BONUS_FLAGS + and #<(~PERFECT_KILLS) + sta BONUS_FLAGS + + jmp skip_to_next_enemy ; skip to next enemy + + +done_enemy_y: + + ;=============== + ; Done Movement + ;=============== + + + ;====================== + ; Check for Collisions + ;====================== + + + ;================================== + ; Check ENEMY <> MISSILE collision + ;================================== + +check_enemy_missile_collision: + + ldy #$0 + sty YSAV +check_missile_loop: + lda (MISSILE_PL),Y + beq missile_not_out + + iny ; point to missile.x + lda (MISSILE_PL),Y ; load missile.x + + sta COL_X1 + sta COL_X2 + + lda ENEMY_X + lsr A + sta COL_X3 + clc + adc #3 + sta COL_X4 + + jsr check_inside + + bcc missile_done + +x_in_range: + + iny + lda (MISSILE_PL),Y ; load missile.y + + sta COL_X3 + clc + adc #2 + sta COL_X4 + + lda ENEMY_Y + lsr A + lsr A + sta COL_X1 + clc + adc #1 + sta COL_X2 + + jsr check_inside + + bcc missile_done + + +horrible_explosion: + + ; clear missile + + ldy YSAV + lda #$0 + sta (MISSILE_PL),Y + + ; clear enemy + + lda #$1 + sta ENEMY_EXPLODING + lda #$40 + sta ENEMY_KIND + + jsr inc_score + + jmp draw_enemy + + +missile_done: +missile_not_out: + ldy YSAV + iny + iny + iny + sty YSAV + cpy #(NUM_MISSILES*3) + bne check_missile_loop + + ;================================= + ; Done missile <> enemy collision + ;================================= + + + ;==================================== + ; check for ship <-> enemy collision + ;==================================== + + lda SHIPX + sta COL_X3 + clc + adc #8 + sta COL_X4 ; big check is shipx - shipx+8 + + lda ENEMY_X + lsr A + sta COL_X1 + clc + adc #2 + sta COL_X2 ; small check enemy_x - enemy_x+2 + + jsr check_inside ; check if overlap + + bcc draw_enemy ; if not, move ahead + + lda #16 + sta COL_X3 + lda #18 + sta COL_X4 ; big check is 16 - 18 + + lda ENEMY_Y + lsr A + lsr A + sta COL_X1 + clc + adc #$1 + sta COL_X2 ; little check is enemy_y - enemy_y+1 + + jsr check_inside ; check if overlap + + bcc draw_enemy ; if not, move ahead + + ; make the enemy explode + + lda #$1 + sta ENEMY_EXPLODING + lda #$40 + sta ENEMY_KIND + + dec SHIELDS + jsr update_shields ; move shields down + + lda #<(~PERFECT_SHIELDS) ; (~PERFECT_SHIELDS) + and BONUS_FLAGS ; remove perfect shield bonus + sta BONUS_FLAGS + + + ;===================================== + ; Done ship <> enemy collision detect + ;===================================== + + +draw_enemy: + + ; See if the enemy is currently exploding + ; if so, do explosion stuff + +check_enemy_explode: + lda ENEMY_EXPLODING ; load enemy[i].exploding + beq not_exploding ; if 0 then not exploding + +handle_exploding: + + jsr click ; make some noise + + clc + lda ENEMY_KIND ; move to next step in explosion + adc #$4 + sta ENEMY_KIND + + cmp #$58 ; have we cycles through explosion? + bne draw_enemy_sprite ; if not, we are still exploding + + dec TOTAL_ENEMIES_OUT ; total_enemies_out-- + + pla + tay ; load y + pha + + lda #$0 ; enemy[i].out=0 + sta (ENEMY_PL),Y + + jmp skip_to_next_enemy + + + ; point to enemies_x + ; goto enemies_xy + + +not_exploding: + + + +draw_enemy_sprite: + + ; point to proper sprite + + lda #>enemy_sprite0 ; point to the missile sprite + sta STRINGH + lda #boss_sprite + sta STRINGH + lda #smoke_sprite0 ; point to the missile sprite + sta STRINGH + lda #laser_sprite0 ; point to the missile sprite + sta STRINGH + lda #smoke_sprite0 ; point to the missile sprite + sta STRINGH + lda #missile_sprite ; point to the missile sprite + sta STRINGH + lda #ship_sprite + sta STRINGH + lda #shields_string + sta STRINGH + lda #score_string + sta STRINGH + lda #level_string + sta STRINGH + lda #game_over_string + sta STRINGH + lda #(score_string+31) + sta STRINGH + lda #<(score_string+31) + sta STRINGL + jsr print_high_score + + jsr HOME + + ; print new high score message + + lda #>new_high_score_string + sta STRINGH + lda #high_score_string + sta STRINGH + lda #shields_string + sta STRINGH + lda #(score_string+7) + sta STRINGH + lda #<(score_string+7) + sta STRINGL + + tya + pha ; save Y on stack + + + ldy #$0 + + lda SCOREH + sta BCD_BYTEH + + lda SCOREL + sta BCD_BYTE + jsr print_bcd_word + + pla ; restore Y + tay + + rts + +;====================== +; print high_score +;====================== + ; location to output to in STRINGH/STRINGL + +print_high_score: + tya + pha ; save Y on stack + + ldy #$0 + + lda HISCORE_H + sta BCD_BYTEH + + lda HISCORE_L + sta BCD_BYTE + jsr print_bcd_word + + pla ; restore Y + tay + + rts + +;========================================================== +; print_bcd_word +;========================================================== + ; string to output in STRINGH/STRINGL + ; byte to output in BCD_BYTE + +print_bcd_word: + + + lda BCD_BYTEH + lsr A + lsr A + lsr A + lsr A + and #$f ; mask low nybble + bne to_ascii_thou + + lda #$A0 ; load a space + + jmp write_thousands +to_ascii_thou: + adc #$B0 ; covert to ascii + +write_thousands: + sta (STRINGL),Y ; store output + + iny + + lda BCD_BYTEH + + and #$f + bne to_ascii_hun + + cmp BCD_BYTEH + + bne to_ascii_hun + + lda #$A0 + jmp write_hundreds + +to_ascii_hun: + adc #$B0 +write_hundreds: + sta (STRINGL),Y + + iny + + +print_bcd_byte: + + lda BCD_BYTE + lsr A + lsr A + lsr A + lsr A + and #$f ; mask low nybble + bne to_ascii_tens ; if not zero, convert to ascii + + cmp BCD_BYTEH + + bne to_ascii_tens + + lda #$A0 + + jmp write_tens +to_ascii_tens: + adc #$B0 ; covert to ascii + +write_tens: + sta (STRINGL),Y ; store output + + iny ; point one lower + + + lda BCD_BYTE + clc + and #$f + adc #$B0 + + sta (STRINGL),Y + + + rts + +;========================================================== +; check inside +;========================================================== + ; Simple collision detection. Have small line x1<->x2 + ; Want to see if it overlaps long line x3<---------->x4 + ; so: + ; if ((x1>x3)&&(x1x3) && (x2 40? + bmi bottom_loop ; if not, loop + + lda #$80 ; go to next line [they are $80 apart] + clc + adc BASL ; increment base + sta BASL ; store it out + lda #$0 ; load 0 into A + adc BASH ; carry into top byte if need be + sta BASH ; and store out + + inx ; increment line count + cpx #$4 ; have we done 4 + bcc bottom_y ; if not, loop + + rts + + +;========================================================== +; print X strings +;========================================================== + ; + ; +print_x_strings: + stx TEMP + jsr print_text_xy + ldx TEMP + dex + bne print_x_strings + rts + + +;========================================================== +; Print text x,y +;========================================================== + ; x=ch y=cv + ; string=string_addr + +print_text_xy: + ldy #$0 ; clear IY + lda (STRINGL),Y ; load x from memory + sta CH ; store to CH + iny ; point to next value + + lda (STRINGL),Y ; load y from memory + sta CV ; store to CV + ; point to beginning of string + + clc + lda #$2 + adc STRINGL + sta STRINGL + lda #$0 + adc STRINGH + sta STRINGH + +print_text: + ldy #$0 + lda CV + jsr BASCALC ; get the address of y in BASH:BASL + clc ; clear the carry + lda BASL ; load BASL + adc CH ; add x + sta BASL ; store BASL back out + +output_loop: + lda (STRINGL),Y ; load char from string_addr+y + beq print_done ; if null terminated, done + sta (BASL),Y ; store to BASH:BASL + iny ; IY++ + jmp output_loop ; loop + +print_done: + iny + tya ; transfer y to accumulator + + + adc STRINGL ; add y and stringl + sta STRINGL ; and store it out + lda #$0 ; clear accumulator + adc STRINGH ; add with carry from prev stringh + sta STRINGH ; and save it + + + rts + + + + +;========================================================== +; clear_screen +;========================================================== + ; + +clear_screen: + + ldx #$0 +clear_0: + cpx #$0 + bne clear_1 + lda GR_PAGE + sta BASH + lda #$0 + sta BASL + ldy #$78 + jmp clear_it +clear_1: + cpx #$1 + bne clear_2 + lda #$80 + sta BASL + ldy #$78 + jmp clear_it +clear_2: + cpx #$2 + bne clear_3 + clc + lda #$1 + adc GR_PAGE + + sta BASH + ldy #$78 + jmp clear_it +clear_3: + cpx #$3 + bne clear_4 + lda #$0 + sta BASL + ldy #$78 + jmp clear_it +clear_4: + cpx #$4 + bne clear_5 + clc + lda #$2 + adc GR_PAGE + sta BASH + ldy #$50 + jmp clear_it +clear_5: + cpx #$5 + bne clear_6 + lda #$80 + sta BASL + ldy #$50 + jmp clear_it +clear_6: + cpx #$6 + bne clear_7 + clc + lda #$3 + adc GR_PAGE + sta BASH + ldy #$50 + jmp clear_it +clear_7: + cpx #$7 + bne clear_8 + lda #$0 + sta BASL + ldy #$50 + jmp clear_it +clear_8: + + rts + +clear_it: + lda #$00 +clear_loop: + dey + + sta (BASL),Y + + bne clear_loop + + inx + jmp clear_0 + +;========================================================== +; show_stars +;========================================================== +; + +show_stars: + + + lda #>star_field ; Load the star offsets + sta STRINGH ; array into + lda # +#include /* strncpy() */ +#include /* isdigit() */ +#include /* open() */ +#include /* close() */ + +char dos_color_to_apple[16]= +{0, /* 0 black */ + 2, /* 1 blue */ + 4, /* 2 green */ + 7, /* 3 cyan */ + 1, /* 4 red */ + 3, /* 5 purple */ + 8, /* 6 brown */ + 10,/* 7 l grey */ + 5, /* 8 d grey */ + 6, /* 9 l blue */ +12, /*10 l green */ +14, /*11 l cyan */ + 9, /*12 l red */ +11, /*13 pink */ +13, /*14 yellow */ +15, /* 15 white */ +} +; + +int get_number(char *string, int *pointer) { + + int temp_number; + + + if (string[*pointer]=='0') { + + /* Hexadecimal */ + if (string[*pointer+1]=='x') { + (*pointer)++; + + (*pointer)++; + temp_number=0; + while(isxdigit(string[*pointer])) { + if ((string[*pointer]>='a') && (string[*pointer]<='f')) + temp_number=16*temp_number+(10+(string[*pointer]-'a')); + if ((string[*pointer]>='A') && (string[*pointer]<='F')) + temp_number=16*temp_number+(10+(string[*pointer]-'A')); + if ((string[*pointer]>='0') && (string[*pointer]<='9')) + temp_number=16*temp_number+(string[*pointer]-'0'); + (*pointer)++; + } + } + else { + /* Octal */ + temp_number=0; + while(isdigit(string[*pointer])) { + temp_number=8*temp_number+(string[*pointer]-'0'); + (*pointer)++; + } + } + + } + else { + /* Decimal */ + temp_number=0; + while(isdigit(string[*pointer])) { + temp_number=10*temp_number+(string[*pointer]-'0'); + (*pointer)++; + } + } + + return temp_number; + +} + + +int main(int argc, char **argv) { + + FILE *input,*output; + + char input_filename[]="sprites"; + int pointer,temp_pointer; + char input_line[BUFSIZ]; + char temp_string[BUFSIZ]; + int color=0,oldcolor,run; + + input=fopen(input_filename,"r"); + if (input==NULL) goto file_error; + + + while(1) { + + if ( fgets(input_line,BUFSIZ,input) ==NULL) goto close_file; + + pointer=0; + + while(pointer14)) { + printf("$%X,",(run<<4)+dos_color_to_apple[oldcolor]); + run=0; + } + run++; + oldcolor=color; + + while(!isdigit(input_line[pointer])) pointer++; + } + if (color!=0) { + printf("$%X,",(run<<4)+dos_color_to_apple[color]); + } + + + printf("$00\n"); + goto done_with_string; + } + + else { + printf("Unknown directive!\n"); + goto close_file; + } + + } + /* end of label */ + if (input_line[pointer]==':') { + + temp_pointer=pointer; + while( (temp_pointer>0) && + (input_line[temp_pointer]!='\t') && + (input_line[temp_pointer]!=' ')) temp_pointer--; + + strncpy(temp_string,input_line+temp_pointer,pointer-temp_pointer); + temp_string[pointer]='\0'; + printf("\t.byte $00\n"); + printf("%s:\n",temp_string); + + } + + + + + pointer++; + } +done_with_string: ; + + + } + + + +close_file: + if (input!=NULL) fclose(input); + +file_error: + return 0; +} diff --git a/tb_6502/tools/string_to_apple.c b/tb_6502/tools/string_to_apple.c new file mode 100644 index 0000000..b6de2bb --- /dev/null +++ b/tb_6502/tools/string_to_apple.c @@ -0,0 +1,26 @@ +#include +#include + +int main(int argc, char **argv) { + + char string[BUFSIZ]; + int i; + + while(1) { + fgets(string,BUFSIZ,stdin); + if (feof(stdin)) goto done; + + printf(";# %s\n",string); + printf(".byte\t"); + + printf("$%X",string[0]+128); + + for (i=1;i + +int random_num(int seed) +{ + + static int our_seed; + + if (seed!=-1) our_seed=seed; + + if (our_seed==0) our_seed=13; + + our_seed<<=1; + if (our_seed & 0x100) our_seed^=0x87; + + our_seed&=0xff; + + return our_seed; + +} + +int main(int argc, char **argv) +{ +int i; + int frequency[256]; + for(i=0;i<256;i++) frequency[i]=0; + + for(i=0;i<4096;i++) + frequency[random_num(-1)]++; + + for(i=0;i<256;i++) + printf("%i : %i\n",i,frequency[i]); + + +} + diff --git a/tb_6502/tools/wait.c b/tb_6502/tools/wait.c new file mode 100644 index 0000000..a28a8f3 --- /dev/null +++ b/tb_6502/tools/wait.c @@ -0,0 +1,15 @@ +#include + +int main(int argc, char **argv) { + + int i; + + for(i=0;i<256;i++) { + printf("%i = %x = %i\n",i,i,(26+27*i+5*i*i)/2); + } + + return 0; + + + +}