diff --git a/tb_asm/Changelog.tb_asm b/tb_asm/Changelog.tb_asm
new file mode 100644
index 0000000..5d0b947
--- /dev/null
+++ b/tb_asm/Changelog.tb_asm
@@ -0,0 +1,86 @@
+25 December 2002
++ Get idea from friend
++ Start implementing in C
+
+?? January 2003
++ Finish title, about, story options
+
+?? January 2003
++ Add "quit, are you sure" display
+
+?? February 2003
++ Port all of C version at time to assembler
+
+?? February 2003
++ Add help screen to C version
++ Add help screen to asm version
+
+?? February 2003
++ Add ansi-code sound effects to C version
+
+?? February 2003
++ Finish varied enemies and boss on C version
+
+?? February 2003
++ Add save game support to C version
+
+4 March 2003
++ Started adding actual game support to assembler
++ Frame limiter and pause/sound/help work
+
+6 March 2003
++ Added pseudo-random number generator
++ Added scrolling star background
++ Added missiles
+
+10 March 2003
++ Added int->ascii routine
++ Added bottom status bar
+
+11 March 2003
++ Simple enemy movement.
+
+12 March 2003
++ Added collision detection.
+
+17 March 2003
++ Added enemy behavior
+
+18 March 2003
++ Added sound
++ Added hi-score support
++ Added level announce
+
+19 March 2003
++ Added boss
++ Polished a bit
++ Put rep / stosb on separate lines so works with as 2.9.1
+
+20 March 2003
++ Added "restore colors" at exit time
++ Removed extra spaces from strings... saves 100 bytes
++ Lots of infrastructute to compress data segment... saves 2k
++ Change all the cool "bt/btr/bts/btc" op-codes to equivelant
+ or/and/xor. The former was cool, but slightly longer. Sad, sad.
++ Found if I remove ".data" the text+data segments are merged saving
+ 3k. Cool, especially as I don't write to the data segment at all anymore.
++ Use sstrip. There are random file lengths that either "strip" or
+ "sstrip" don't handle well. May have to pad things out in the end
+
+21 March 2003
++ convert "get_char" and "get_a_char" to return status in the carry flag.
++ Much optimization. See "optimization" file.
++ Now under 8k ;)
+
+23 March 2003
++ Extensive play-testing to make sure optimization didn't break game.
++ Fix "sstrip" program so it puts the bss on the proper boundry.
+ Hope this isn't "as" version specific.
++ Game balancing. Moved up to 6 enemies. Slight shifts in
+ game engine constants.
++ Fix problem where enemies get stuck at level 4. As a result
+ level 7 never ends, as we do tricks where we use level*16 and
+ over 7 that overflows to negative.
++ Play tested. Seems ok. Release 0.32!
+
+
diff --git a/tb_asm/FAQ.tb_asm b/tb_asm/FAQ.tb_asm
new file mode 100644
index 0000000..94e4913
--- /dev/null
+++ b/tb_asm/FAQ.tb_asm
@@ -0,0 +1,168 @@
+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 thought I should attempt a x86 assembly version before I go and learn
+ ARM assembly.
+
+
+
+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 text mode?
+
+A. Because doing graphics in Linux is a pain. And I didn't feel like
+ messing with the framebuffer. This was a proof-of-concept, not a
+ designed-for-release game.
+
+
+
+Q. Why 40x20 resolution?
+
+A. Because I'd like to port it to Apple IIe low-res graphics mode.
+
+
+
+Q. Why not a DOS version?
+
+A. Should be technically possible, although it's been a while and gas
+ isn't the best assembler for it. Also doing things like reading
+ the keyboard/getting timestamps/speaker noise are more complicated.
+
+ More interesting would be a version using Windows console syscalls.
+
+
+
+Q. What is the high score?
+
+A. A bit of a silly question as anyone can edit a text file and lie. The
+ highest score I've gotten is 14170 on level 4.
+ But this isn't saying much, I tend to be debugging more than playing.
+
+ The highest _possible_ score is 2^31 or about 2 billion. Actually
+ it might be 4 billion, I am not sure how my int->ascii code handles
+ signed numbers.
+
+
+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 Jacob always said...
+ A computer is just a state machine.
+
+
+Q. What do you hate most about the GNU Assembler "gas"?
+
+A. It doesn't warn you when a "loop" instruction overflows
+ 128 thus causing your program to go off into la-la land.
+ It also doesn't do type checking causing you headaches if
+ you forget the "b" on cmpb.
+
+ But you can't really blame it, it's used to dealing with
+ gcc which is a very good and proper assembler-producer,
+ unlike the author.
+
+
+Q. Why are there only 6 enemies / 2 missiles / shields go up at 320/ 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_asm.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.
+
+
+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.
diff --git a/tb_asm/Makefile b/tb_asm/Makefile
new file mode 100644
index 0000000..0e81412
--- /dev/null
+++ b/tb_asm/Makefile
@@ -0,0 +1,47 @@
+CC=gcc
+CFLAGS = -Wall -O2
+LFLAGS =
+
+all: tb_asm configure compress_data
+
+./sstrip/sstrip:
+ cd sstrip && make
+
+compress_data: compress_data.o lzss.o
+ $(CC) $(LFLAGS) -o compress_data compress_data.o lzss.o
+
+compress_data.o: compress_data.c
+ $(CC) $(CFLAGS) -c compress_data.c
+
+
+lzss.o: lzss.c
+ gcc -O2 -Wall -c lzss.c
+
+lzss_new.o: lzss_new.c
+ gcc -O2 -Wall -c lzss_new.c
+
+
+tb_asm: tb_asm.o ./sstrip/sstrip
+ ld -o tb_asm tb_asm.o
+ ./sstrip/sstrip tb_asm
+
+tb_asm.o: tb_asm.s data.lzss data.labels
+ as -o tb_asm.o tb_asm.s
+
+tb_asm.s: configure
+ ./configure
+
+data.labels: compress_data
+ ./compress_data
+
+data.lzss: compress_data data.inc
+ ./compress_data
+
+
+
+configure: configure.c
+ gcc -O2 -Wall -o configure configure.c
+
+clean:
+ rm -f *~ *.o tb_asm tb_asm.s core configure compress_data data.lzss data.header data.raw data.labels
+ cd sstrip && $(MAKE) clean
diff --git a/tb_asm/README.tb_asm b/tb_asm/README.tb_asm
new file mode 100644
index 0000000..519adfe
--- /dev/null
+++ b/tb_asm/README.tb_asm
@@ -0,0 +1,99 @@
+TOM BOMBEM: Merciless Marauding Malicious Marketers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+http://www.deater.net/weave/vmwprod/tb1/tb_asm.html
+
+ by Vince Weaver
+
+ version 0.24 -- 19 March 2003
+
+
+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_asm comes before "tb1: Invasion of the Inanimate Objects"
+chronologically, for those who might care.
+
+
+Compiling / Running:
+~~~~~~~~~~~~~~~~~~~~
+ Just run "make". If you have a supported architecture "tb_asm"
+ will be created.
+
+ If you don't have an ix86 or ppc computer, you can try in the
+ "c" subdirectory and do "make" there to run a "C" version of the game
+ that should run on and architecture. The "C" version is not
+ as feature-complete.
+
+ After compiling just run "./tb_asm"
+
+ tb_asm will run _ONLY_ on Linux. A DOS/w32 port could be possible
+ but I really don't have the time or desire to mess with it.
+
+ tb_asm should be run at the text_console [if in X press CTRL-ALT-F1].
+ It will run to some extent in an x-term, but w/o sound.
+
+
+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:
+~~~~~~~~~~~~~~~~~~~~~
+ tb_asm will create the file "/tmp/tb_asm.hsc" to store the hiscore.
+
+ tb_asm will only write the file if it's not there, or if there
+ is a file there that is at least 12 bytes long and starts
+ with "tb".
+
+ Besides the hiscore tb_asm also stores the "sound on/sound off"
+ state in this file.
+
+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 320 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!
+
+
+About:
+~~~~~~
+ (see also the FAQ.asm file)
+
+ This was done as an exercise to see if I could make a Tom-Bombem
+ class game entirely in assembly language. I've optimized for
+ size rather than speed. And most likely it's not _completely_
+ optimized for size yet.
+
+ The hope is maybe eventually using this as a stepping-board to
+ creating a Game Boy Advance TomBombem game.
+
+Author:
+~~~~~~~
+ Vince Weaver
+ http://www.deater.net/weave/
+ Special Thanks to KRG
+ 19 March 2003
+
diff --git a/tb_asm/TODO b/tb_asm/TODO
new file mode 100644
index 0000000..4211866
--- /dev/null
+++ b/tb_asm/TODO
@@ -0,0 +1,2 @@
+have the boss go away before final explosion
+"demo" mode of self playing
diff --git a/tb_asm/arch.h b/tb_asm/arch.h
new file mode 100644
index 0000000..9e91ad7
--- /dev/null
+++ b/tb_asm/arch.h
@@ -0,0 +1,32 @@
+#define ARCH_UNKNOWN 0
+#define ARCH_ALPHA 1
+#define ARCH_ARM 2
+#define ARCH_CRIS 3
+#define ARCH_IA64 4
+#define ARCH_IX86 5
+#define ARCH_M68K 6
+#define ARCH_MIPS 7
+#define ARCH_PARISC 8
+#define ARCH_PPC 9
+#define ARCH_S390 10
+#define ARCH_SH3 11
+#define ARCH_SPARC 12
+#define ARCH_VAX 13
+
+
+char *arch_names[]={
+ "Unknown",
+ "alpha",
+ "arm",
+ "cris",
+ "ia64",
+ "ix86",
+ "m68k",
+ "mips",
+ "parisc",
+ "ppc",
+ "s390",
+ "sh3",
+ "sparc",
+ "vax"
+};
diff --git a/tb_asm/c/Makefile b/tb_asm/c/Makefile
new file mode 100644
index 0000000..1c89736
--- /dev/null
+++ b/tb_asm/c/Makefile
@@ -0,0 +1,12 @@
+C_FLAGS=-Wall -O2 -g
+
+all: tb_asm
+
+tb_asm: tb_asm.o
+ gcc $(L_FLAGS) -o tb_asm tb_asm.o
+
+tb_asm.o: tb_asm.c game_sprites.h
+ gcc $(C_FLAGS) -c tb_asm.c
+
+clean:
+ rm -f *~ *.o tb_asm core
diff --git a/tb_asm/c/boss.h b/tb_asm/c/boss.h
new file mode 100644
index 0000000..2062f67
--- /dev/null
+++ b/tb_asm/c/boss.h
@@ -0,0 +1,34 @@
+/* XPM */
+/* Boss */
+
+/* 3x2 */
+char smoke_sprites[3][6]={
+{0x0,0x8,0x0,
+ 0x0,0x0,0x0,
+},
+{0x8,0x7,0x8,
+ 0x8,0x8,0x8,
+},
+{0x7,0x4,0x7,
+ 0x7,0x7,0x7,
+},
+
+};
+
+/* 13x3 */
+char boss_sprite[]={
+0xf,0x7,0x4,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0x4,0x7,0xf,
+0xf,0x8,0x7,0x4,0x4,0x3,0xb,0x3,0x4,0x4,0x7,0x8,0xf,
+0xf,0x0,0x8,0x7,0x3,0xb,0xe,0xb,0x3,0x7,0x8,0x0,0xf,
+};
+
+/* 1x2 */
+char laser_sprite[2][2]={
+{0xd,
+0x5,
+},
+{0x5,
+0xd,
+}
+};
+
diff --git a/tb_asm/c/dump_to_ansi.c b/tb_asm/c/dump_to_ansi.c
new file mode 100644
index 0000000..87f00cc
--- /dev/null
+++ b/tb_asm/c/dump_to_ansi.c
@@ -0,0 +1,33 @@
+#include
+
+int main(int argc, char **argv) {
+
+ int ch,vt102mode=0,inAnsi=0;
+
+ while(!feof(stdin)) {
+
+ ch=getchar();
+
+ if (ch<0) break;
+
+ if (ch==27) inAnsi=1;
+ if ((inAnsi) && (ch=='m')) inAnsi=0;
+ if ((inAnsi) && (ch=='H')) inAnsi=0;
+
+ if (ch==14) {
+ vt102mode=1;
+ goto skip_print;
+ }
+
+ if (ch==15) {
+ vt102mode=0;
+ goto skip_print;
+ }
+
+ if ((vt102mode)&&(ch=='0')&&(!inAnsi)) putchar('\333');
+ else putchar(ch);
+
+skip_print:
+ }
+
+}
diff --git a/tb_asm/c/ending.h b/tb_asm/c/ending.h
new file mode 100644
index 0000000..78c4456
--- /dev/null
+++ b/tb_asm/c/ending.h
@@ -0,0 +1,34 @@
+/* Ending */
+
+/* 7x7*/
+char tom_head_sprite[]={
+0x0,0x1,0x1,0x1,0x9,0x9,0x0,
+0x0,0x1,0x0,0x0,0x8,0x9,0x0,
+0x0,0x1,0x0,0x0,0x8,0x9,0x0,
+0x0,0x1,0x0,0x0,0x8,0x9,0x0,
+0x0,0x1,0x0,0x0,0x8,0x9,0x0,
+0x0,0x0,0x1,0x1,0x9,0x0,0x0,
+0x1,0x1,0x1,0x1,0x9,0x9,0x9,
+};
+
+/* 5x6 */
+char earth_sprite[]={
+0x0,0x7,0xf,0xf,0x0,
+0x2,0xA,0xA,0x9,0x9,
+0x1,0xA,0x9,0x9,0x9,
+0x1,0x9,0xA,0xA,0x9,
+0x1,0x9,0xA,0x9,0x9,
+0x0,0x7,0xf,0xf,0x0,
+};
+
+/* 19x7 */
+char susie_sprite[]={
+/*0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,*/
+0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x8,0x0,0xf,0xf,0x0,0x7,0x7,0x7,
+0x7,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x8,0x0,0x0,0x7,0x7,
+0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,
+0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,
+0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x7,0x7,
+0x7,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x7,0x7,0x7,0x7,
+0x7,0x7,0x7,0x7,0x8,0x8,0x8,0x7,0x7,0x7,0x7,0x7,0x8,0x8,0x8,0x7,0x7,0x7,0x7,
+};
diff --git a/tb_asm/c/game_sprites.h b/tb_asm/c/game_sprites.h
new file mode 100644
index 0000000..aa20343
--- /dev/null
+++ b/tb_asm/c/game_sprites.h
@@ -0,0 +1,57 @@
+ /* 8x4 */
+char ship_sprite[]=
+{
+0x0,0x0,0x9,0x9,0x9,0x0,0x0,0x0,
+0x0,0x7,0xf,0xf,0xf,0x7,0x0,0x0,
+0x7,0x7,0xf,0x7,0xf,0x7,0x7,0x0,
+0x0,0x0,0x0,0xe,0x0,0x0,0x0,0x0
+};
+
+/* 1x3 */
+char missile_sprite[]={
+0x7,
+0x7,
+0xe,
+};
+
+ /* 3x2 */
+char enemy_sprites[6][6]={
+ {0xf,0xf,0x4,
+ 0xf,0xf,0xf,
+ }
+ ,
+ {0x9,0x0,0x9,
+ 0x0,0x9,0x0,
+ }
+ ,
+ {0x2,0xa,0x2,
+ 0x2,0xa,0x2,
+ }
+ ,
+ {0x3,0x6,0x6,
+ 0x3,0x6,0x6,
+ }
+ ,
+ {0x0,0xe,0x0,
+ 0xe,0x0,0xe,
+ }
+ ,
+ {0xc,0xf,0xf,
+ 0xc,0x7,0x7
+ }
+ ,
+};
+
+char explosion_sprites[3][6]={
+ { 0xe,0xe,0xc,
+ 0xc,0xe,0x8,
+ },
+ { 0x7,0x7,0x4,
+ 0x4,0x7,0x0,
+ },
+
+ { 0x8,0x8,0x0,
+ 0x0,0x8,0x8,
+ },
+};
+
diff --git a/tb_asm/c/guess.c b/tb_asm/c/guess.c
new file mode 100644
index 0000000..7ae1a9c
--- /dev/null
+++ b/tb_asm/c/guess.c
@@ -0,0 +1,41 @@
+
+#include
+#include
+#include
+
+int main(int argc, char **argv) {
+ int result,guess,secret,tries;
+
+ srand(time(NULL));
+
+new_game:
+ secret=rand()%65536;
+ tries=0;
+ printf("Guess a number between 0 and 65536!\n");
+ printf(" Or -1 to quit\n");
+guess_again:
+ result=scanf("%d",&guess);
+ if (result<1) {
+ scanf("%*s");
+ goto guess_again;
+ }
+ if (guess==-1) goto end;
+ tries++;
+ if (guesssecret) {
+ printf("%i is too high! Try again!\n",guess);
+ goto guess_again;
+ }
+
+ if (guess==secret) {
+ printf("Correct! It took you %i tries!\n",tries);
+ goto new_game;
+ }
+
+end:
+ printf("Thanks for playing!\n\n");
+ return 0;
+}
diff --git a/tb_asm/c/int_random.c b/tb_asm/c/int_random.c
new file mode 100644
index 0000000..85a59f1
--- /dev/null
+++ b/tb_asm/c/int_random.c
@@ -0,0 +1,56 @@
+#include
+#include
+
+/* default beep is 750Hz/125ms */
+
+
+/* The following algorithm from the Hewlett Packard HP-20S */
+/* Scientific Calculator manual, September 1998, p75-76 */
+
+/* The algorithm r = FractionalPart (997r ) */
+/* i+1 i */
+/* */
+/* Where r0 is a starting value between 0 and 1. */
+/* The generator passes the chi-square frequency test for */
+/* uniformity, and serial and run tests for randomness. */
+/* The more significant digits are more random than the */
+/* less significant. If r0 * 10e7 is not divisible */
+/* by 2 or 5 you get 500,000 numbers w/o repeating. */
+
+/* modified to be fixed-point integer only by Vince Weaver */
+
+int int_random(int seed) {
+
+ static int ri;
+
+ /* Be sure doesn't end in multiple of 2, 5 and is ~<=7 digits */
+ if (seed!=0) {
+ ri=seed;
+ while ((ri%2==0) || (ri%5==0)) ri++;
+ ri=ri&0xffffff;
+ return ri;
+ }
+
+ ri*=997;
+ ri&=0xffffff;
+
+ return ri;
+}
+
+int random_word() {
+ int i;
+
+ i=(int_random(0)>>8)&0xffff;
+ return i;
+}
+
+int main(int argc,char **argv) {
+
+ int i;
+
+ int_random(time(NULL));
+
+ for(i=0;i<1000;i++) printf("%i\n",random_word()%1000);
+
+ return 0;
+}
diff --git a/tb_asm/c/open_test.c b/tb_asm/c/open_test.c
new file mode 100644
index 0000000..80186d4
--- /dev/null
+++ b/tb_asm/c/open_test.c
@@ -0,0 +1,12 @@
+#include
+
+int main(int argc, char **argv) {
+ FILE *fff;
+
+ fff=fopen("bob","w");
+ if (fff!=NULL) {
+ fprintf(fff,"HELLO\n");
+ fclose(fff);
+ }
+ return 0;
+}
diff --git a/tb_asm/c/opener.h b/tb_asm/c/opener.h
new file mode 100644
index 0000000..20da632
--- /dev/null
+++ b/tb_asm/c/opener.h
@@ -0,0 +1,28 @@
+/* opener.h */
+/* 40x20 */
+
+/* 0,5 Merciless Marauding Malicious Marketers */
+
+char opener_sprite[]=
+{
+0x9,0x9,0x9,0x0,0x9,0x9,0x9,0x0,0x9,0x0,0x0,0x0,0x9,0x0,0xC,0xC,0x0,0x0,0xC,0xC,0xC,0x0,0xC,0x0,0x0,0x0,0xC,0x0,0xC,0xC,0x0,0x0,0xC,0xC,0x0,0xC,0x0,0x0,0x0,0xC,
+0x0,0x9,0x0,0x0,0x9,0x0,0x9,0x0,0x9,0x9,0x0,0x9,0x9,0x0,0xC,0x0,0xC,0x0,0xC,0x0,0xC,0x0,0xC,0xC,0x0,0xC,0xC,0x0,0xC,0x0,0xC,0x0,0xC,0x0,0x0,0xC,0xC,0x0,0xC,0xC,
+0x0,0x9,0x0,0x0,0x9,0x0,0x9,0x0,0x9,0x0,0x9,0x0,0x9,0x0,0xC,0xC,0x0,0x0,0xC,0x0,0xC,0x0,0xC,0x0,0xC,0x0,0xC,0x0,0xC,0xC,0x0,0x0,0xC,0xC,0x0,0xC,0x0,0xC,0x0,0xC,
+0x0,0x9,0x0,0x0,0x9,0x0,0x9,0x0,0x9,0x0,0x0,0x0,0x9,0x0,0xC,0x0,0xC,0x0,0xC,0x0,0xC,0x0,0xC,0x0,0x0,0x0,0xC,0x0,0xC,0x0,0xC,0x0,0xC,0x0,0x0,0xC,0x0,0x0,0x0,0xC,
+0x0,0x9,0x0,0x0,0x9,0x9,0x9,0x0,0x9,0x0,0x0,0x0,0x9,0x0,0xC,0xC,0x0,0x0,0xC,0xC,0xC,0x0,0xC,0x0,0x0,0x0,0xC,0x0,0xC,0xC,0x0,0x0,0xC,0xC,0x0,0xC,0x0,0x0,0x0,0xC,
+0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,
+0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xF,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xF,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+0x0,0x0,0x0,0x0,0x0,0x7,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xB,0x0,0x0,0x0,
+0x0,0xE,0x0,0x0,0x0,0x7,0x7,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xB,0x4,0x4,
+0x0,0xE,0xE,0xE,0x9,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0x9,0x9,0x9,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xB,0xC,0xC,
+0xE,0xE,0x4,0xC,0x9,0xF,0x4,0x2,0x9,0x2,0x9,0xF,0xF,0x9,0x9,0x9,0x9,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xB,0x0,0xC,0xC,
+0x0,0xE,0xE,0xC,0x9,0xF,0x4,0x2,0x9,0x2,0x9,0xF,0xF,0x9,0x9,0x9,0x9,0x9,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xC,0xC,
+0x0,0x0,0x0,0xE,0x9,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0xF,0xF,0xF,0xF,0xF,0xF,0x0,0x0,0x0,0x0,0xE,0x7,0x7,0x7,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xC,0xC,
+0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xF,0x0,0x0,0x0,0x0,0x4,0x4,
+0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+0x0,0xF,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xF,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,
+};
diff --git a/tb_asm/c/organ.c b/tb_asm/c/organ.c
new file mode 100644
index 0000000..3eed833
--- /dev/null
+++ b/tb_asm/c/organ.c
@@ -0,0 +1,71 @@
+#include
+#include /* pow */
+#include /* fcntl */
+#include
+
+
+
+int main(int argc, char **argv) {
+
+ int frequency[127],i,ch,note=60;
+
+ static struct termios new_tty,old_tty;
+
+
+ /* setup non-blocking non-echo mode */
+
+ tcgetattr(0,&old_tty);
+
+ new_tty=old_tty;
+ new_tty.c_lflag&=~ICANON;
+ new_tty.c_cc[VMIN]=1;
+ new_tty.c_lflag&=~ECHO;
+ tcsetattr(0,TCSANOW,&new_tty);
+
+ fcntl(0,F_SETFL,fcntl(0,F_GETFL) | O_NONBLOCK);
+
+
+
+ for (i=0;i<127;i++) frequency[i]=(440.0/32.0)*(pow(2.0,(i-9.0)/12.0));
+
+ for(i=0;i<127;i++) printf("%i\n",frequency[i]);
+
+ while ((ch=getchar())!='q') {
+ if (ch==-1) goto loop;
+ switch(ch)
+ {
+
+ case 'a': note=60; break;
+ case 'w': note=61; break;
+ case 's': note=62; break;
+ case 'e': note=63; break;
+ case 'd': note=64; break;
+ case 'f': note=65; break;
+ case 't': note=66; break;
+ case 'g': note=67; break;
+ case 'y': note=68; break;
+ case 'h': note=69; break;
+ case 'u': note=70; break;
+ case 'j': note=71; break;
+ case 'k': note=72; break;
+
+ }
+
+
+
+ printf("%c[10;%i]\n",27,frequency[note]);
+// write(1, "\33[11;200]", 9) length = 200
+ printf("%c",ch);
+ printf("\a");
+ usleep(150000);
+ loop:
+
+
+ }
+
+ tcsetattr(0,TCSANOW,&old_tty);
+
+
+
+
+}
diff --git a/tb_asm/c/phobos.h b/tb_asm/c/phobos.h
new file mode 100644
index 0000000..a996919
--- /dev/null
+++ b/tb_asm/c/phobos.h
@@ -0,0 +1,26 @@
+
+ /* 40x16 */
+
+char phobos_sprite[]={
+0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf,0x0,0x0,0x0,
+0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+0x0,0x0,0x0,0x0,0x0,0x7,0xf,0xf,0xf,0xf,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+0x0,0x0,0x0,0x0,0x4,0xc,0xc,0xc,0xc,0xc,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+0x0,0x0,0x0,0x4,0xc,0xc,0xc,0xc,0xc,0x4,0xc,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+0x0,0x0,0x0,0x4,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+0x0,0x0,0x0,0x4,0xc,0xc,0xc,0x4,0xc,0xc,0xc,0xc,0x0,0x0,0x0,0x0,0x0,0x8,0x6,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+0x0,0x0,0x0,0x4,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+0x0,0x0,0x0,0x4,0xc,0xc,0xc,0xc,0xc,0x4,0xc,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+0x0,0x0,0x0,0x0,0x4,0xc,0xc,0xc,0xc,0xc,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+0x0,0x0,0x0,0x0,0x0,0x7,0xf,0xf,0xf,0xf,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+0x0,0x0,0x0,0xf,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+};
+
+ /* 3x1 */
+char evil_ship_sprite[]={
+0x3,0xb,0x3,
+};
diff --git a/tb_asm/c/tb_asm.c b/tb_asm/c/tb_asm.c
new file mode 100644
index 0000000..6ef0a91
--- /dev/null
+++ b/tb_asm/c/tb_asm.c
@@ -0,0 +1,1278 @@
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#define SCREEN_WIDTH 40
+#define SCREEN_HEIGHT 24
+#define BYTES_PER_PIXEL 2
+#include "vmwsoft.h"
+#include "opener.h"
+#include "vince.h"
+#include "tom.h"
+#include "phobos.h"
+#include "game_sprites.h"
+#include "boss.h"
+#include "ending.h"
+
+int play_sound=0;
+char hi_player[4]="KRG";
+int hiscore=100;
+int dump_screen=0;
+
+void load_hi_score() {
+ FILE *hi_score;
+
+ hi_score=fopen("/tmp/tb_asm.hsc","r");
+ if (hi_score!=NULL) {
+ fscanf(hi_score,"%i\n",&hiscore);
+ fgets(hi_player,4,hi_score);
+ fclose(hi_score);
+ }
+}
+
+
+
+int clear_framebuffer(char *buffer,char color,char value) {
+
+ int i=0;
+
+ while(i=xsize) {
+ offset+=((SCREEN_WIDTH-xsize)*BYTES_PER_PIXEL);
+ xx=0;
+ yy++;
+ }
+ }
+
+ return 0;
+}
+
+int put_text_xy(char *text,int x,int y,int color, char *framebuffer) {
+
+ int offset,i;
+
+ offset=(y*SCREEN_WIDTH+x)*BYTES_PER_PIXEL;
+
+ i=0;
+
+ while(i7,colors[color&7]);
+ old_color=color;
+ }
+ temp_string[0]=framebuffer[((i+j*SCREEN_WIDTH)*BYTES_PER_PIXEL)+1];
+ if (temp_string[0]==219) {
+ if (!block_mode){
+ block_mode=1;
+ size+=to_buffer(out_buffer,"\016");
+ }
+ temp_string[0]='0';
+ }
+ else {
+ if (block_mode) {
+ block_mode=0;
+ size+=to_buffer(out_buffer,"\017");
+
+ }
+ }
+
+ size+=to_buffer(out_buffer,temp_string);
+ }
+ size+=to_buffer(out_buffer,"\n");
+ }
+
+ if (size>40*44*10) {
+
+ printf("\a\a\a\n");
+ exit(10);
+ }
+
+
+ write(1,out_buffer,size);
+ if (dump_screen) {
+ int fd;
+ fd=creat("screen",0x666);
+ write(fd,out_buffer,size);
+ close(fd);
+ dump_screen=0;
+ }
+
+// fdatasync(1);
+
+ return 0;
+}
+
+int get_timer() {
+
+ static int initialized=0;
+ static int startseconds,startusecs;
+
+ struct timeval our_time;
+
+ int temp_time;
+
+ if (!initialized) {
+ gettimeofday(&our_time,NULL);
+
+ startseconds=time(NULL);
+ startusecs=our_time.tv_usec;
+
+ initialized=1;
+ }
+ gettimeofday(&our_time,NULL);
+ temp_time=(time(NULL)-startseconds)*1000;
+ temp_time+=(our_time.tv_usec/1000);
+
+ return temp_time;
+
+}
+
+
+void clear_keyboard_buffer()
+{
+ int ch;
+
+ while(read(0,&ch,1)==1);
+}
+
+
+void pause_a_while(int msecs) {
+
+ int ch,our_time;
+
+ our_time=get_timer();
+
+ while ( read(0,&ch,1)!=1) {
+ usleep(1);
+
+ if ( (get_timer()-our_time) > msecs ) break;
+ }
+ clear_keyboard_buffer();
+
+}
+
+int get_char() {
+
+ char ch;
+ int result;
+
+ result=read(0,&ch,1);
+
+ if (result<1) return 0;
+ else return ch;
+}
+
+
+int get_a_char() {
+
+ char ch,ch1,ch2,ch3;
+
+ ch=get_char();
+
+ if (ch==27) {
+ ch1=get_char();
+ ch2=get_char();
+ ch3=get_char();
+
+ if ((ch1==0) && (ch2==0)) return 'q';
+ if ((ch1==91) && (ch2==66)) return 'm';
+ if ((ch1==91) && (ch2==65)) return 'i';
+ if ((ch1==91) && (ch2==67)) return 'k';
+ if ((ch1==91) && (ch2==68)) return 'j';
+ if ((ch1==91) && (ch2==91)) {
+ if (ch3==65) return 'h';
+ }
+ {
+ FILE *fff;
+ fff=fopen("bob","w");
+ fprintf(fff,"%i %i %i\n",ch1,ch2,ch3);
+ fclose(fff);
+ }
+// }
+ }
+ return ch;
+}
+
+
+
+
+void null()
+{
+}
+
+
+void put_attention_block(char *framebuffer,int color) {
+
+ int i,j;
+
+ for(i=5;i<12;i++)
+ for(j=0;j<40;j++)
+ put_text_xy("*",j,i,color,framebuffer);
+
+}
+
+
+int verify_quit(char *framebuffer) {
+
+ int quit_bar=0;
+ char ch;
+
+ put_attention_block(framebuffer,14);
+ put_text_xy(" QUIT? Are you sure? ",9,7,12,framebuffer);
+ put_text_xy(" NO!",9,8,12,framebuffer);
+ put_text_xy(" YES!",9,9,12,framebuffer);
+ quit_loop:
+
+ if (quit_bar==0) {
+ put_text_xy(" --> NO! ",9,8,13,framebuffer);
+ put_text_xy(" YES ",9,9,5,framebuffer);
+ }
+ else {
+ put_text_xy(" NO ",9,8,5,framebuffer);
+ put_text_xy(" --> YES! ",9,9,13,framebuffer);
+ }
+
+ dump_to_screen(framebuffer);
+ while ((ch=get_a_char())==0) usleep(5000);
+
+ if ((ch=='i') || (ch=='j') || (ch=='k') || (ch=='m')) quit_bar=!quit_bar;
+
+ if (ch=='y') quit_bar=1;
+ if (ch=='n') quit_bar=0;
+
+ if (ch=='\n') {
+ return quit_bar;
+ }
+
+ goto quit_loop;
+
+ return 0;
+
+}
+
+int ending(char *framebuffer) {
+
+ sleep(3);
+
+ clear_keyboard_buffer();
+
+ clear_framebuffer(framebuffer,0,' ');
+
+ blit(earth_sprite,framebuffer,219,32,0,5,6);
+ put_text_xy("INCOMING MESSAGE FROM",0,0,15,framebuffer);
+ put_text_xy(" ** EARTH **",0,1,15,framebuffer);
+
+ put_text_xy("Congratulations Tom!",0,3,14,framebuffer);
+ put_text_xy("You've destroyed the",0,4,14,framebuffer);
+ put_text_xy(" Marketing Menace!!",0,5,14,framebuffer);
+
+ put_text_xy("But wait...",0,7,14,framebuffer);
+ put_text_xy("Our sensors detect another batch of",0,8,14,framebuffer);
+ put_text_xy(" enemies, moving even faster!",0,9,14,framebuffer);
+ put_text_xy("Feel free to quit at any time, but",0,11,14,framebuffer);
+ put_text_xy(" remember no paycheck bonus unless",0,12,14,framebuffer);
+ put_text_xy(" all are destroyed.",0,13,14,framebuffer);
+ put_text_xy("PS Your pet guinea",0,15,14,framebuffer);
+ put_text_xy(" pig is doing",0,16,14,framebuffer);
+ put_text_xy(" well. -->",0,17,14,framebuffer);
+ blit(susie_sprite,framebuffer,219,20,15,19,7);
+ put_text_xy("** END TRANSMISSION **",0,22,15,framebuffer);
+
+ dump_to_screen(framebuffer);
+
+ while(get_char()==0) usleep(30);
+
+ clear_framebuffer(framebuffer,0,' ');
+
+ blit(tom_head_sprite,framebuffer,219,0,0,7,7);
+ put_text_xy("Tom: *Sigh*",10,0,9,framebuffer);
+
+ put_text_xy("Press Any Key to Resume Fighting",0,10,15,framebuffer);
+
+ dump_to_screen(framebuffer);
+
+ while(get_char()==0) usleep(30);
+
+ return 0;
+}
+
+int help(char *framebuffer) {
+
+ clear_framebuffer(framebuffer,0,' ');
+
+ put_text_xy("TOM BOMBEM",10,0,15,framebuffer);
+
+ put_text_xy("by",14,1,7,framebuffer);
+ put_text_xy("Vince Weaver",9,2,15,framebuffer);
+
+ put_text_xy("Key Bindings:",0,4,15,framebuffer);
+ put_text_xy("UP or 'i' : Move menu up",2,6,7,framebuffer);
+ put_text_xy("DOWN or 'm' : Move menu down",2,7,7,framebuffer);
+ put_text_xy("ENTER : Selects current option",2,8,7,framebuffer);
+
+ put_text_xy("RIGHT or 'k' : Move ship right",2,10,7,framebuffer);
+ put_text_xy("LEFT or 'j' : Move ship left",2,11,7,framebuffer);
+ put_text_xy("SPACEBAR : Shoots",2,12,7,framebuffer);
+
+ put_text_xy("F1 or 'h' : Displays help",2,14,7,framebuffer);
+ put_text_xy("ESC or 'q' : Quits",2,15,7,framebuffer);
+ put_text_xy("'p' : Pauses",2,16,7,framebuffer);
+ put_text_xy("'s' : Toggles sound",2,17,7,framebuffer);
+
+ dump_to_screen(framebuffer);
+
+ while(get_char()==0) usleep(30);
+
+ return 0;
+}
+
+
+
+int hi_score(char *framebuffer) {
+
+ char temp_string[BUFSIZ];
+
+ load_hi_score();
+
+ put_attention_block(framebuffer,12);
+ put_text_xy("HIGH SCORE",15,7,14,framebuffer);
+
+ sprintf(temp_string," %s %i ",hi_player,hiscore);
+ put_text_xy(temp_string,(40-strlen(temp_string))/2,9,15,framebuffer);
+
+ dump_to_screen(framebuffer);
+
+
+
+ return 0;
+}
+
+int new_hi_score(char *framebuffer) {
+
+ FILE *hi_score;
+ char temp_name[4]="AAA";
+ int char_num=0,ch;
+
+ put_attention_block(framebuffer,9);
+ put_text_xy("NEW HIGH SCORE",13,5,13,framebuffer);
+ put_text_xy("Use the arrows to pick your initials",2,7,14,framebuffer);
+ put_text_xy("Press ENTER when you are done",5,8,14,framebuffer);
+
+ hi_score_loop:
+ put_text_xy(" ",17,10,15,framebuffer);
+ put_text_xy(" ",18,11,15,framebuffer);
+
+ put_text_xy(temp_name,18,10,15,framebuffer);
+ put_text_xy("^",18+char_num,11,15,framebuffer);
+
+ dump_to_screen(framebuffer);
+
+ while ((ch=get_a_char())==0) usleep(5000);
+
+ if (ch=='k') {
+ char_num++;
+ if (char_num>2) char_num=0;
+ }
+ if (ch=='j') {
+ char_num--;
+ if (char_num<0) char_num=2;
+ }
+
+ if (ch=='i') {
+ temp_name[char_num]--;
+ if (temp_name[char_num]<64) temp_name[char_num]=126;
+ }
+
+ if (ch=='m') {
+ temp_name[char_num]++;
+ if (temp_name[char_num]>126) temp_name[char_num]=64;
+ }
+
+ if (ch!='\n') goto hi_score_loop;
+
+ strncpy(hi_player,temp_name,3);
+
+ hi_score=fopen("/tmp/tb_asm.hsc","w");
+ if (hi_score!=NULL) {
+ fprintf(hi_score,"%i\n",hiscore);
+ fprintf(hi_score,"%s\n",hi_player);
+ fclose(hi_score);
+ }
+
+ return 0;
+}
+
+
+
+
+void set_sound(int freq,int duration) {
+ printf("%c[10;%i]%c[11;%i]\n",27,freq,27,duration);
+ play_sound=1;
+}
+
+
+
+#define UP_SHIELDS 200
+
+int new_game(char *framebuffer) {
+
+
+ int i,j,xadd=0,scroll=0,quit=0,x=20,bigx=20<<8,y=16;
+ int sound=1,shields=8,score=0;
+ int game_paused=0,current_enemy_type=0 /*0*/,current_enemy_kind=-1,current_init_x=-1,
+ total_enemies_out=0,level=1,enemies_spawned=1,enemy_wave=0;
+
+ char temp_string[BUFSIZ];
+
+ int done_waiting;
+ struct timeval timing_info;
+ int time_spent,oldusec=0,oldsec=0;
+
+ struct boss_type {
+ int x,xadd,count;
+ int waiting,hits,smoke,exploding;
+ int shooting;
+ } boss;
+
+ struct missile_type {
+ int out,x,y;
+ } missile[2];
+
+ struct enemy_type {
+ int x,y,out,kind;
+ int xadd,yadd,xmin,xmax;
+ int hitsneeded;
+ int exploding;
+ } enemies[5];
+
+ int enemy_wait=30,enemy_count=0;
+
+
+ char ch;
+
+ char *background;
+
+ FILE *debug;
+
+ debug=fopen("debug","w");
+
+
+ load_hi_score();
+
+ clear_keyboard_buffer();
+ clear_framebuffer(framebuffer,0x0,' ');
+
+ background=calloc(1600,sizeof(char));
+
+ missile[0].out=0;
+ missile[1].out=0;
+
+ for(i=0;i<5;i++) enemies[i].out=0;
+
+
+ /* RANDOMIZE TIMER */
+ srand(time(NULL));
+
+ /* Draw the Stars */
+ for(i=0;i<50;i++) {
+ *(background+(rand()%40)*40+rand()%40)=7;
+ *(background+(rand()%40)*40+rand()%40)=8;
+ }
+
+
+ while(!quit) {
+
+
+ clear_framebuffer(framebuffer,0x0,' ');
+
+ /* Scrolling Stars */
+ scroll-=1;
+ if (scroll<0) scroll=78;
+
+ if (scroll/2<20) {
+ blit(background+(scroll/2*40),framebuffer,'.',0,0,40,20);
+ }
+ else {
+ blit(background+(scroll/2*40),framebuffer,'.',0,0,40,40-scroll/2);
+ blit(background,framebuffer,'.',0,40-scroll/2,40,scroll/2-20);
+ }
+
+
+ /* Put out new enemies */
+
+ /* Type 0: "Diagonal No Wait" x_init=rand, xadd=1, yadd=1
+ * Type 1: "horiz then fall" xadd=1. After random, xadd=0 yadd=1
+ * Type 2: "diagonal, wait" wait(all_free) then 0 with same type
+ * Type 4: "Wiggle" x=rand()
+ * Type 5: "Rain" x=rand() xadd=0 yadd=1
+ * Type 6: Wait for Boss
+ * Type 7: BOSS
+ *
+ *
+ * After enemies_destroyed>20 switch types
+ * After enemies_destroyed>500? Wait till all destroyed then BOSS
+ * After boss keep going, knocking up speed each 100
+ */
+
+ /* Keep a level indicator? */
+
+ /* Keep a count of how close to place enemies */
+ /* Don't want all to appear at once */
+
+
+ enemy_count++;
+ if (enemy_count==enemy_wait) {
+ enemy_count=0;
+
+ if (current_enemy_type==7) enemies_spawned=1;
+
+ /* make length random? */
+ if (enemies_spawned%15==0) {
+
+ enemies_spawned++; /* hack to keep from getting stuck */
+ current_enemy_type=rand()%6;
+
+ enemy_wave++;
+ if (enemy_wave==15) current_enemy_type=6;
+
+
+ if ((current_enemy_type==0) || (current_enemy_type==1))
+ enemy_wait=30;
+ else enemy_wait=10;
+ current_enemy_kind=-1;
+ current_init_x=-1;
+
+ }
+
+
+ i=0;
+ while (i<5) {
+ if (!enemies[i].out) break;
+ i++;
+ }
+
+ if (current_enemy_type==2) {
+ if (total_enemies_out>0) goto move_enemies;
+ current_enemy_type=3;
+ current_enemy_kind=rand()%6;
+ current_init_x=rand()%300;
+ enemy_wait=10;
+ }
+
+ if (current_enemy_type==6) {
+ if (total_enemies_out>0) goto move_enemies;
+ boss.x=13;
+ boss.xadd=1;
+ boss.count=10+rand()%40;
+ boss.waiting=1;
+ boss.hits=20+(5*level);
+ boss.smoke=0;
+ boss.exploding=0;
+ current_enemy_type=7;
+ enemy_wait=10;
+ }
+
+ if ((current_enemy_type==7) && (boss.waiting)) goto move_enemies;
+
+ if (i<5) {
+ enemies_spawned++;
+ enemies[i].out=1;
+ enemies[i].exploding=0;
+ total_enemies_out++;
+ enemies[i].y=0;
+ enemies[i].hitsneeded=0;
+ enemies[i].xmin=0;
+ enemies[i].xmax=37;
+
+ if (current_enemy_kind<0) enemies[i].kind=rand()%6;
+ else enemies[i].kind=current_enemy_kind;
+
+ if (current_init_x<0) enemies[i].x=rand()%300;
+ else enemies[i].x=current_init_x;
+
+ switch(current_enemy_type) {
+ case 0: enemies[i].xadd=level;
+ enemies[i].yadd=level;
+ break;
+ case 1: enemies[i].xadd=5;
+ enemies[i].yadd=-(rand()%100);
+ break;
+ case 3: enemies[i].xadd=3;
+ enemies[i].yadd=level;
+ break;
+ case 4: enemies[i].xadd=4;
+ enemies[i].yadd=level;
+ enemies[i].xmin=2+rand()%34;
+ enemies[i].xmax=enemies[i].xmin+(rand()%20);
+ if (enemies[i].xmax>35) enemies[i].xmax=35;
+ enemies[i].x=enemies[i].xmin*8;
+// fprintf(debug,"%i %i\n",enemies[i].xmin,enemies[i].xmax)
+ break;
+ case 5: enemies[i].xadd=0; enemies[i].yadd=2;
+ if (rand()%3==0) enemies[i].x=x;
+ break;
+ case 7: enemies[i].xadd=0; enemies[i].yadd=2;
+ enemies[i].x=(boss.x+5)*8;
+ enemies[i].y=3*8;
+ break;
+ }
+
+ }
+
+ }
+
+move_enemies:
+
+
+ /* Move the enemies */
+ for(i=0;i<5;i++) {
+ if (enemies[i].out) {
+
+ /* Move on x */
+ if (enemies[i].xadd!=0) {
+ enemies[i].x+=enemies[i].xadd;
+
+ if ((enemies[i].x/8>37) || (enemies[i].x/8<0)) {
+ enemies[i].xadd=-enemies[i].xadd;
+ enemies[i].x+=enemies[i].xadd;
+ }
+
+ if (current_enemy_type==4) {
+ if ((enemies[i].x/8>enemies[i].xmax) || (enemies[i].x/80) {
+ enemies[i].y+=enemies[i].yadd;
+ if (enemies[i].y/8>18) {
+ enemies[i].out=0;
+ total_enemies_out--;
+ }
+
+ }
+
+
+ /* Ship <-> Enemies Collision Detection */
+ if (!enemies[i].exploding) {
+ if ( ( (enemies[i].x/8+2 >= x) && (enemies[i].x/8+2 <= x +6) )
+ || ( (enemies[i].x/8 >=x) && (enemies[i].x/8 <= x+6))) {
+
+ if ( ((enemies[i].y/8 >= y) && (enemies[i].y/8 <=y+2))
+ || ( (enemies[i].y/8+1 >=y) && (enemies[i].y/8+1 <=y+2)) ) {
+
+ enemies[i].exploding=1;
+ shields--;
+ set_sound(120,50);
+
+ }
+
+ }
+
+
+ }
+
+
+
+ }
+ }
+
+
+
+
+
+
+ /* Draw the enemies */
+ for(i=0;i<5;i++) {
+ if (enemies[i].out) {
+ if (enemies[i].exploding) {
+ blit(explosion_sprites[enemies[i].exploding/2-1],framebuffer,219,enemies[i].x/8,enemies[i].y/8,3,2);
+ enemies[i].exploding++;
+ if (enemies[i].exploding>7) {
+ enemies[i].out=0;
+ total_enemies_out--;
+ }
+
+
+ }
+ else {
+ blit(enemy_sprites[enemies[i].kind],framebuffer,219,enemies[i].x/8,enemies[i].y/8,3,2);
+ }
+ }
+
+ }
+
+
+ /* Draw the Boss */
+ if (current_enemy_type==7) {
+ if (boss.exploding!=1) blit(boss_sprite,framebuffer,219,boss.x,0,13,3);
+ if (boss.smoke) {
+ blit(smoke_sprites[boss.smoke/4],framebuffer,219,boss.x+5,3,3,1);
+ blit(smoke_sprites[boss.smoke/4],framebuffer,219,boss.x+5-boss.xadd,4,3,1);
+ boss.smoke--;
+ }
+
+ if (boss.shooting) {
+ boss.shooting--;
+ for(i=0;i<8;i++) {
+ blit(laser_sprite[boss.shooting%2],framebuffer,219,boss.x,3+(i*2),1,2);
+ blit(laser_sprite[boss.shooting%2],framebuffer,219,boss.x+12,3+(i*2),1,2);
+ set_sound(200+boss.shooting,20);
+ }
+ }
+
+ if (boss.exploding) {
+ boss.waiting=1;
+ for(i=0;i<30;i++) {
+ blit(smoke_sprites[boss.exploding/8],framebuffer,219,boss.x+rand()%11,rand()%4,3,1);
+ }
+ set_sound(120,20);
+ boss.exploding--;
+ if (boss.exploding==0) {
+ level++;
+ boss.shooting=0;
+ for(i=0;i<5;i++) enemies[i].exploding=2;
+ ending(framebuffer);
+ current_enemy_type=2;
+ enemy_wave=0;
+ }
+ }
+
+ else {
+
+ boss.count--;
+ if (boss.count<0) {
+ if (boss.waiting) {
+ boss.waiting=0;
+ boss.count=40+rand()%320;
+ }
+
+ else {
+ boss.waiting=1;
+ boss.count=30+rand()%40;
+ boss.shooting=30;
+
+ }
+
+ }
+ }
+
+
+ if (!boss.waiting) {
+ boss.x+=boss.xadd;
+ if ((boss.x>26) || (boss.x<0)) {
+ boss.xadd=-boss.xadd;
+ boss.x+=boss.xadd;
+ }
+
+ }
+
+ /* Collision detection for lasers */
+ if (boss.shooting) {
+ if (((boss.x < x+6) && (boss.x>=x)) ||
+ ((boss.x+12=x))) {
+ if (boss.shooting%7==0) shields--;
+
+ }
+ }
+ }
+
+
+
+
+ /* Move the missiles */
+ for(i=0;i<2;i++) {
+ if (missile[i].out) {
+ missile[i].y--;
+ if (missile[i].y<0) missile[i].out=0;
+
+ /* Missile Collision Detection */
+ for(j=0;j<5;j++) {
+
+ /* Missile <-> Enemy Collision Detection */
+ if ((enemies[j].out)&&(!enemies[j].exploding)) {
+ if ((missile[i].x >=enemies[j].x/8) && (missile[i].x < enemies[j].x/8+3)) {
+ if ((missile[i].y >= enemies[j].y/8) && (missile[i].y <=enemies[j].y/8+1) ) {
+ missile[i].out=0;
+ enemies[j].exploding=2;
+ set_sound(150,40);
+ score+=10;
+ if (score%UP_SHIELDS==0) {
+ shields++;
+ set_sound(220,50);
+ if (shields>9) shields=9;
+ }
+
+ }
+ }
+ }
+ }
+
+ /* Missile <-> Boss Collision Detection */
+ if ((current_enemy_type==7) && (!boss.exploding)) {
+ if ((missile[i].x >= boss.x) && (missile[i].x < boss.x+13)) {
+ if ((missile[i].y>= 0) && (missile[i].y <=2)) {
+ missile[i].out=0;
+ boss.smoke=11;
+ set_sound(150,50);
+ boss.hits--;
+
+ if (boss.hits<0) boss.exploding=23;
+ }
+ }
+ }
+ }
+ }
+
+ /* Draw the missiles */
+ for(i=0;i<2;i++) {
+ if (missile[i].out) blit(missile_sprite,framebuffer,219,missile[i].x,missile[i].y,1,3);
+ }
+
+
+
+
+ ch=0;
+
+ while( (ch=get_a_char()) ) {
+
+ switch(ch) {
+ case 'd': dump_screen=1; break;
+ case 'q': case 'Q':
+ if (verify_quit(framebuffer)) {
+ quit=1;
+ }
+ else {
+ game_paused=1;
+ }
+ break;
+ case 'j': if (xadd<=0) xadd-=128; else xadd=0; break;
+ case 'k': if (xadd>=0) xadd+=128; else xadd=0; break;
+ case 'p':
+ put_attention_block(framebuffer,14);
+ put_text_xy(" GAME PAUSED! ",13,8,12,framebuffer);
+ dump_to_screen(framebuffer);
+
+ while (get_char()==0) usleep(5000);
+ game_paused=1;
+ break;
+ case 's': sound=!sound; /*level++;*/ break;
+ case 'h': help(framebuffer); /*game_paused=1;*/ break;
+ case ' ': if (!missile[0].out) {
+ missile[0].out=1;
+ missile[0].x=x+3;
+ missile[0].y=y;
+ set_sound(110,30);
+ } else if (!missile[1].out) {
+ missile[1].out=1;
+ missile[1].x=x+3;
+ missile[1].y=y;
+ set_sound(110,30);
+
+ }
+ break;
+ }
+ }
+
+ bigx+=xadd;
+ if (bigx<0) {
+ bigx=0;
+ xadd=0;
+ }
+
+ if (bigx>(32<<8)) {
+ bigx=32<<8;
+ xadd=0;
+ }
+
+ x=bigx>>8;
+
+
+ blit(ship_sprite,framebuffer,219,x,y,8,4);
+
+ put_text_xy("SHIELDS: ",0,21,shields?12:14,framebuffer);
+
+ for(i=0;i<10;i++) {
+ if (ihiscore) {
+ hiscore=score;
+ fprintf(debug,"score=%i hiscore=%i\n",score,hiscore);
+ new_hi_score(framebuffer);
+ }
+ hi_score(framebuffer);
+
+ pause_a_while(5000);
+
+ return 0;
+}
+
+int about(char *framebuffer) {
+
+ clear_framebuffer(framebuffer,0,' ');
+
+ blit(vince_sprite,framebuffer,219,24,0,16,20);
+ put_text_xy("TOM BOMBEM",7,0,13,framebuffer);
+
+ put_text_xy("by",11,1,14,framebuffer);
+ put_text_xy("Vince Weaver",6,2,9,framebuffer);
+ put_text_xy("author if you squint ->",0,3,12,framebuffer);
+
+ put_text_xy("* Testing my asm skills",0,5,11,framebuffer);
+
+ put_text_xy("* Based on Tom Bombem: ",0,7,10,framebuffer);
+ put_text_xy(" Invasion of Inanimate",0,8,10,framebuffer);
+ put_text_xy(" Objects, a game I ",0,9,10,framebuffer);
+ put_text_xy(" started 10 years ago ",0,10,10,framebuffer);
+ put_text_xy(" in Pascal/asm and is ",0,11,10,framebuffer);
+ put_text_xy(" still languishing ",0,12,10,framebuffer);
+ put_text_xy(" uncompleted in C/SDL.",0,13,10,framebuffer);
+
+ put_text_xy("Contact Vince:",0,17,5,framebuffer);
+ put_text_xy("vince@deater.net",0,18,9,framebuffer);
+ put_text_xy("http://www.deater.net/weave/",0,19,9,framebuffer);
+
+ dump_to_screen(framebuffer);
+
+ while(get_char()==0) usleep(30);
+
+ return 0;
+}
+
+
+int story(char *framebuffer) {
+
+ int x;
+
+ clear_framebuffer(framebuffer,0,' ');
+ blit(phobos_sprite,framebuffer,219,0,0,40,16);
+ /* 0 5 0 5 0 5 0 5 0 */
+ put_text_xy("It is the year 2025. All telemarketers",0,17,15,framebuffer);
+ put_text_xy("and unsolicited bulk e-mailers have ",0,18,15,framebuffer);
+ put_text_xy("been exiled to Phobos.",0,19,15,framebuffer);
+
+ dump_to_screen(framebuffer);
+ pause_a_while(7000);
+
+ put_text_xy("Right before being trapped forever they",0,17,10,framebuffer);
+ put_text_xy("manage to launch one last marketing ",0,18,10,framebuffer);
+ put_text_xy("droid. ",0,19,10,framebuffer);
+
+ dump_to_screen(framebuffer);
+ pause_a_while(4000);
+
+ x=19;
+ while(x<37) {
+ blit(evil_ship_sprite,framebuffer,219,x,9,3,1);
+ dump_to_screen(framebuffer);
+ pause_a_while(250);
+ put_text_xy(" ",x,9,0,framebuffer);
+ x++;
+
+ }
+ pause_a_while(2000);
+
+ clear_framebuffer(framebuffer,0,' ');
+ blit(tom_sprite,framebuffer,219,24,1,16,18);
+
+ /*0 5 0 5 0 */
+ put_text_xy("You are Tom Bombem.",0,0,9,framebuffer);
+
+ put_text_xy("You drew the short straw.",0,2,9,framebuffer);
+
+ put_text_xy("So it is up to you to",0,4,9,framebuffer);
+ put_text_xy(" fight through the ads",0,5,9,framebuffer);
+ put_text_xy(" and destroy the evil ",0,6,9,framebuffer);
+ put_text_xy(" marketing robot, thus",0,7,9,framebuffer);
+ put_text_xy(" restoring harmony to ",0,8,9,framebuffer);
+ put_text_xy(" the space lanes.",0,9,9,framebuffer);
+
+ put_text_xy(" GOOD LUCK!",0,12,11,framebuffer);
+
+ dump_to_screen(framebuffer);
+ pause_a_while(20000);
+
+ return 0;
+}
+
+
+int main(int argc, char **argv) {
+
+ static struct termios new_tty,old_tty;
+
+ char *framebuffer;
+
+
+ int i,menu_item;
+ char ch;
+
+ framebuffer=calloc(SCREEN_WIDTH*SCREEN_HEIGHT*BYTES_PER_PIXEL,sizeof(char));
+
+ /* setup non-blocking non-echo mode */
+
+ tcgetattr(0,&old_tty);
+
+ new_tty=old_tty;
+ new_tty.c_lflag&=~ICANON;
+ new_tty.c_cc[VMIN]=1;
+ new_tty.c_lflag&=~ECHO;
+ tcsetattr(0,TCSANOW,&new_tty);
+
+ fcntl(0,F_SETFL,fcntl(0,F_GETFL) | O_NONBLOCK);
+
+
+ /* clear screen */
+ printf("\033[2J\n");
+
+ clear_framebuffer(framebuffer,0,' ');
+
+ blit(vmw_sprite,framebuffer,219,8,6,23,8);
+ put_text_xy("A VMW Software Production",7,15,15,framebuffer);
+ dump_to_screen(framebuffer);
+ pause_a_while(3000);
+
+
+ opening_screen:
+
+ clear_framebuffer(framebuffer,0,' ');
+ blit(opener_sprite,framebuffer,219,0,0,40,20);
+ put_text_xy("Merciless Marauding Malicious Marketers",0,5,14,framebuffer);
+
+ dump_to_screen(framebuffer);
+
+ pause_a_while(10000);
+
+
+ menu_item=0;
+
+ put_attention_block(framebuffer,0);
+
+ while(1) {
+ put_text_xy("New Game",15,6,(menu_item==0)?13:5,framebuffer);
+ put_text_xy("About",15,7,(menu_item==1)?13:5,framebuffer);
+ put_text_xy("Story",15,8,(menu_item==2)?13:5,framebuffer);
+ put_text_xy("Hi Score",15,9,(menu_item==3)?13:5,framebuffer);
+ put_text_xy("Quit",15,10,(menu_item==4)?13:5,framebuffer);
+ put_text_xy("F1 or 'h' for HELP",0,20,7,framebuffer);
+
+ for(i=0;i<5;i++)
+ if (i==menu_item) put_text_xy("-->",12,6+menu_item,14,framebuffer);
+ else put_text_xy(" ",12,6+i,0,framebuffer);
+ dump_to_screen(framebuffer);
+
+ while( !(ch=get_a_char()) ) usleep(30);
+
+ switch(ch) {
+ case 'q': case 'Q': menu_item=4; ch='\n'; break;
+
+ case 'i': case 'j': menu_item--;
+ if (menu_item<0) menu_item=4;
+ break;
+ case 'm': case 'k': menu_item++;
+ if (menu_item>4) menu_item=0; break;
+ case 'h': menu_item=5; ch='\n'; break;
+
+
+ case 10: case 13: case 32: break;
+
+
+
+ }
+
+ if ((ch==10) || (ch==13) || (ch==32)) {
+ switch(menu_item) {
+ case 0: new_game(framebuffer); break;
+ case 1: about(framebuffer); break;
+ case 2: story(framebuffer); break;
+ case 3: hi_score(framebuffer);
+ while(get_char()==0) usleep(30);
+ break;
+ case 4: if (verify_quit(framebuffer)) goto done_the_game; break;
+ case 5: help(framebuffer); break;
+ }
+ goto opening_screen;
+ }
+
+ }
+
+
+
+
+
+ done_the_game:
+ printf("%c\n",15);
+ set_sound(750,125); /* The default. No way I know of to save/restore */
+ tcsetattr(0,TCSANOW,&old_tty);
+
+ return 0;
+}
diff --git a/tb_asm/c/tom.h b/tb_asm/c/tom.h
new file mode 100644
index 0000000..f4388f3
--- /dev/null
+++ b/tb_asm/c/tom.h
@@ -0,0 +1,23 @@
+/* 16x18 */
+
+char tom_sprite[]=
+{
+0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x9,0x9,0x9,0x9,0x0,0x0,0x0,0x0,
+0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0,0x8,0x8,0x9,0x9,0x0,0x0,0x0,0x0,
+0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0,0x8,0x8,0x9,0x9,0x0,0x0,0x0,0x0,
+0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0,0x8,0x8,0x9,0x9,0x0,0x0,0x0,0x0,
+0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0,0x8,0x8,0x9,0x9,0x0,0x0,0x0,0x0,
+0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x9,0x9,0x0,0x0,0x0,0x0,0x0,0x0,
+0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x9,0x9,0x9,0x9,0x9,0x9,0x9,0x9,
+0x1,0x1,0x9,0x9,0x1,0x1,0x1,0x1,0x9,0x9,0xc,0xc,0x1,0x1,0x9,0x9,
+0x1,0x1,0x9,0x9,0x1,0x1,0x1,0x1,0x9,0x9,0x9,0x9,0x1,0x1,0x9,0x9,
+0x1,0x1,0x9,0x9,0x1,0x1,0x1,0x1,0x9,0x9,0x9,0x9,0x1,0x1,0x9,0x9,
+0x1,0x1,0x9,0x9,0x1,0x1,0x1,0x1,0x9,0x9,0x9,0x9,0x1,0x1,0x9,0x9,
+0x1,0x1,0x9,0x9,0x1,0x1,0x1,0x1,0x9,0x9,0x9,0x9,0x1,0x1,0x9,0x9,
+0x3,0x3,0xb,0xb,0x1,0x1,0x9,0x9,0x1,0x1,0x9,0x9,0x3,0x3,0xb,0xb,
+0x0,0x0,0x0,0x0,0x1,0x1,0x9,0x9,0x1,0x1,0x9,0x9,0x0,0x0,0x0,0x0,
+0x0,0x0,0x0,0x0,0x1,0x1,0x9,0x9,0x1,0x1,0x9,0x9,0x0,0x0,0x0,0x0,
+0x0,0x0,0x0,0x0,0x1,0x1,0x9,0x9,0x1,0x1,0x9,0x9,0x0,0x0,0x0,0x0,
+0x0,0x0,0x0,0x0,0x3,0x3,0xb,0xb,0x3,0x3,0xb,0xb,0x0,0x0,0x0,0x0,
+0x0,0x0,0x0,0x0,0x8,0x8,0x7,0x7,0x8,0x8,0x7,0x7,0x0,0x0,0x0,0x0,
+};
diff --git a/tb_asm/c/vince.h b/tb_asm/c/vince.h
new file mode 100644
index 0000000..fb48836
--- /dev/null
+++ b/tb_asm/c/vince.h
@@ -0,0 +1,26 @@
+/* Vince */
+
+/* 16x20 */
+
+char vince_sprite[]={
+0x0,0x0,0x8,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0x8,0x0,0x0,0x0,0x0,
+0x0,0x8,0x7,0xf,0xf,0xf,0xf,0x7,0xf,0xf,0xf,0xf,0x7,0x7,0x0,0x0,
+0x8,0x7,0x7,0x7,0x7,0x7,0x8,0x7,0xf,0x7,0x7,0xf,0xf,0xf,0x7,0x0,
+0x7,0x8,0x0,0x8,0x7,0x7,0x7,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0x8,
+0x7,0x0,0x8,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0x7,
+0x8,0x0,0x7,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0x7,0xf,0x7,0x7,0x8,0x8,
+0x8,0x8,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0x8,0x8,0x0,0x8,0x7,
+0x8,0x7,0xf,0xf,0xf,0xf,0x7,0xf,0xf,0xf,0x7,0x0,0x8,0x0,0x8,0x7,
+0x7,0x8,0x8,0x7,0xf,0x8,0x0,0x8,0x7,0xf,0x7,0x0,0x0,0x0,0x0,0x8,
+0x0,0x7,0x0,0x8,0xf,0x0,0x0,0x8,0x0,0x8,0xf,0x8,0x0,0x0,0x0,0x8,
+0x0,0x7,0x8,0x7,0xf,0x8,0x0,0x0,0x7,0xf,0xf,0x7,0x0,0x0,0x0,0x7,
+0x0,0xf,0x8,0xf,0xf,0xf,0x7,0x7,0xf,0xf,0xf,0xf,0x0,0x0,0x0,0x7,
+0x0,0xf,0x7,0x8,0x8,0x7,0xf,0xf,0xf,0xf,0xf,0x8,0x8,0x8,0x7,0x7,
+0x0,0xf,0xf,0x8,0x0,0x7,0xf,0xf,0xf,0xf,0x7,0x0,0x7,0x7,0x7,0x0,
+0x0,0xf,0xf,0x7,0x8,0x7,0x7,0xf,0xf,0xf,0x7,0x0,0x7,0x7,0x8,0x0,
+0x0,0x7,0x7,0x0,0x8,0x0,0x0,0x7,0x7,0x0,0x0,0xf,0x8,0x7,0x0,0x0,
+0x0,0x8,0xf,0xf,0x8,0xf,0xf,0x7,0x0,0x0,0x8,0x7,0x7,0x8,0x0,0x0,
+0x0,0x0,0xf,0x7,0x7,0x7,0xf,0x7,0x7,0x8,0x8,0xf,0x7,0x0,0x0,0x0,
+0x0,0x0,0x7,0xf,0xf,0xf,0xf,0x8,0x8,0x0,0x8,0xf,0x8,0x0,0x0,0x0,
+0x0,0x0,0x0,0x8,0x8,0x0,0x0,0x0,0x0,0x0,0x7,0xf,0x8,0x0,0x0,0x0,
+};
diff --git a/tb_asm/c/vmwsoft.h b/tb_asm/c/vmwsoft.h
new file mode 100644
index 0000000..bb555b1
--- /dev/null
+++ b/tb_asm/c/vmwsoft.h
@@ -0,0 +1,14 @@
+/*vmw @ 8,6
+"A VMW Software Production" @ 7,15
+*/
+
+char vmw_sprite[]={
+0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x2,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x2,0x1,0x1,0x1,0x1,0x1,0x1,0x1,
+0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x2,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x2,0x1,0x1,0x1,0x1,0x1,0x1,0x1,
+0x0,0x4,0x4,0x4,0x4,0x4,0x2,0x2,0x2,0x1,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x1,0x1,0x1,0x1,0x1,0x0,
+0x0,0x4,0x4,0x4,0x4,0x4,0x2,0x2,0x2,0x1,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x1,0x1,0x1,0x1,0x1,0x0,
+0x0,0x0,0x4,0x4,0x4,0x2,0x2,0x2,0x2,0x2,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x1,0x1,0x1,0x0,0x0,
+0x0,0x0,0x4,0x4,0x4,0x2,0x2,0x2,0x2,0x2,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x1,0x1,0x1,0x0,0x0,
+0x0,0x0,0x0,0x4,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x1,0x0,0x0,0x0,
+0x0,0x0,0x0,0x4,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x1,0x0,0x0,0x0,
+};
diff --git a/tb_asm/compress_data.c b/tb_asm/compress_data.c
new file mode 100644
index 0000000..0a6486a
--- /dev/null
+++ b/tb_asm/compress_data.c
@@ -0,0 +1,274 @@
+/* The following code is UGLY. Read at your own risk. --vmw */
+
+#include
+#include /* strncpy() */
+#include /* isdigit() */
+#include /* open() */
+#include /* close() */
+
+#include "lzss.h"
+
+int write_ascii(char *string,int output_fd) {
+
+ int pointer=0,count=0,octal=0;
+ unsigned char byte;
+
+ while(string[pointer]!='\"') pointer++;
+ pointer++;
+
+ while(string[pointer]!='\"') {
+ if (string[pointer]=='\\') {
+ pointer++;
+
+ if (isdigit(string[pointer])) {
+ octal=0;
+ while(isdigit(string[pointer])) {
+ octal=8*octal+(string[pointer]-'0');
+ pointer++;
+ }
+ if (octal>255) {
+ fprintf(stderr,"BYTE OUT OF RANGE\n");
+ }
+ else {
+ byte=octal;
+ }
+ pointer--;
+ }
+
+ else {
+ switch(string[pointer]) {
+ case 'n': byte='\n'; break;
+ case 't': byte='\t'; break;
+ case '\\': byte='\\'; break;
+ case '\"': byte='\"'; break;
+ }
+ }
+ }
+
+ else byte=string[pointer];
+
+ write(output_fd,&byte,1);
+
+ pointer++;
+ count++;
+ }
+
+ return count;
+
+}
+
+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 write_bytes(char *string, int output_fd) {
+
+ int pointer=0,count=0,number=0;
+ unsigned char temp_byte;
+
+ while(1) {
+
+ while(!isdigit(string[pointer])) {
+ if (string[pointer]=='\n') goto done_byte;
+ pointer++;
+ }
+
+ number=get_number(string,&pointer);
+
+ if (number>255) {
+ fprintf(stderr,"Byte too big!\n");
+ }
+ else {
+ temp_byte=number;
+ write(output_fd,&temp_byte,1);
+ count++;
+ }
+
+ }
+
+done_byte:
+ return count;
+
+}
+
+int write_32bits(char *string, int output_fd) {
+
+ int pointer=0,count=0,number=0;
+// unsigned char temp_int[4];
+
+ while(1) {
+
+ while(!isdigit(string[pointer])) {
+ if (string[pointer]=='\n') goto done_32;
+ pointer++;
+ }
+
+ number=get_number(string,&pointer);
+
+ write(output_fd,&number,4);
+ count+=4;
+ }
+done_32:
+ return count;
+
+}
+
+
+
+
+int main(int argc, char **argv) {
+
+ FILE *input,*header,*labels,*output;
+ int output_fd,byte_count;
+ char input_filename[]="data.inc";
+ char output_raw_filename[]="data.raw";
+ char output_lzss_filename[]="data.lzss";
+ char output_header_filename[]="data.header";
+ char output_labels_filename[]="data.labels";
+ int offset=0,pointer,temp_pointer;
+ char input_line[BUFSIZ];
+ char temp_label_string[BUFSIZ];
+
+ input=fopen(input_filename,"r");
+ if (input==NULL) goto file_error;
+
+ output_fd=open(output_raw_filename,O_WRONLY|O_CREAT|O_TRUNC,0666);
+ if (output_fd<0) goto file_error;
+
+ labels=fopen(output_labels_filename,"w");
+ if (labels==NULL) goto file_error;
+
+ while(1) {
+
+ if ( fgets(input_line,BUFSIZ,input) ==NULL) goto close_file;
+
+ pointer=0;
+
+ while(pointer0) &&
+ (input_line[temp_pointer]!='\t') &&
+ (input_line[temp_pointer]!=' ')) temp_pointer--;
+
+ memcpy(temp_label_string,input_line+temp_pointer,
+ pointer-temp_pointer);
+ temp_label_string[pointer-temp_pointer]='\0';
+ fprintf(labels,".equ %s,%i+DATA_OFFSET\n",temp_label_string,offset);
+ }
+
+
+
+
+ pointer++;
+ }
+done_with_string: ;
+
+
+ }
+
+
+
+close_file:
+ fclose(labels);
+ close(output_fd);
+ fclose(input);
+
+ printf("Original size of data segment = %i bytes\n",offset);
+
+ input=fopen(output_raw_filename,"r");
+ if (input==NULL) goto file_error;
+
+ output=fopen(output_lzss_filename,"w");
+ if (output==NULL) goto file_error;
+
+ header=fopen(output_header_filename,"w");
+ if (header==NULL) goto file_error;
+
+ byte_count=lzss_encode_better(input,header,output,'\0',1024,2);
+
+ printf("Compressed data segment = %i bytes\n",byte_count);
+
+ fprintf(header,".equ TB_DATA_SIZE,%i\n",offset);
+ fclose(header);
+ fclose(input);
+ fclose(output);
+
+file_error:
+ return 0;
+}
diff --git a/tb_asm/configure.c b/tb_asm/configure.c
new file mode 100644
index 0000000..e2e2186
--- /dev/null
+++ b/tb_asm/configure.c
@@ -0,0 +1,71 @@
+#include
+
+#include /* strncpy */
+#include /* uname */
+#include /* system */
+
+#include "arch.h"
+
+int linux_detect_arch(void) {
+
+ /* Yes this is a bit messy, but it cleans up the makefile a bit *\
+ \* The C-Preproccessor can be out friend ;) */
+
+/* return ARCH_SPARC; */
+
+#if defined(__alpha__)
+ return ARCH_ALPHA;
+#elif defined(__arm__)
+ return ARCH_ARM;
+#elif defined(__cris__)
+ return ARCH_CRIS;
+#elif defined(__ia64__)
+ return ARCH_IA64;
+#elif defined(i386)
+ return ARCH_IX86;
+#elif (defined(mc68000) || #cpu(m68k))
+ return ARCH_M68K;
+#elif defined(__mips__)
+ return ARCH_MIPS;
+#elif defined(__parisc__)
+ return ARCH_PARISC;
+#elif defined(__PPC__)
+ return ARCH_PPC;
+#elif defined(__s390__)
+ return ARCH_S390;
+#elif defined(__sh3__) || defined(__sh2__) || defined(__sh4)
+ return ARCH_SH3
+#elif defined(__sparc__)
+ return ARCH_SPARC;
+#elif defined(__vax__)
+ return ARCH_VAX;
+#else
+ return ARCH_UNKNOWN;
+#endif
+
+}
+
+int main(int argc, char **argv) {
+
+ struct utsname buf;
+ char temp_string[256],arch[65];
+ int command_override=0;
+
+ if (argc>1) {
+ command_override=1;
+ }
+
+ uname(&buf);
+
+ sprintf(temp_string,"rm -f tb_asm.s");
+ system(temp_string);
+
+
+ strncpy(arch,arch_names[linux_detect_arch()],63);
+ printf("+ compiling for %s architecture\n",arch);
+
+ sprintf(temp_string,"ln -n -s tb_asm.%s.s tb_asm.s",arch);
+ system(temp_string);
+
+ return 0;
+}
diff --git a/tb_asm/data.inc b/tb_asm/data.inc
new file mode 100644
index 0000000..738852d
--- /dev/null
+++ b/tb_asm/data.inc
@@ -0,0 +1,488 @@
+clear_screen: .ascii "\033[2J\n\0"
+default_colors: .ascii "\017\033[0m\n\0"
+score_file: .ascii "/tmp/tb_asm.hsc\0"
+
+menu_arrow: .ascii " --> \0"
+menu_blank: .ascii " \0"
+menu_pointer: .ascii "^\0"
+
+title_string: .byte 14,5,0
+ .ascii "Merciless Marauding Malicious Marketers\0"
+
+vmw_string: .byte 15,15,7
+ .ascii "A VMW Software Production\0"
+
+menu_new_string: .ascii "New Game\0"
+menu_about_string: .ascii "About\0\0\0\0"
+menu_story_string: .ascii "Story\0\0\0\0"
+menu_hi_string: .ascii "Hi Score\0"
+menu_quit_string: .ascii "Quit\0\0\0\0\0"
+menu_no_string: .ascii "NO! \0\0\0"
+menu_yes_string: .ascii "YES! \0\0\0"
+
+menu_help_string: .byte 7,20,0
+ .ascii "F1 or 'h' for HELP\0"
+
+bonus_points_line: .byte 15,5,14
+ .ascii "BONUS POINTS\0"
+no_bonus_line: .byte 14,7,5
+ .ascii "NO BONUSES THIS LEVEL\0"
+no_shield_line: .byte 14,7,5
+ .ascii "NO SHIELD HITS = +1000\0"
+shot_every_line: .byte 14,8,5
+ .ascii "DESTROYED EVERY ENEMY = +5000\0"
+perfect_shot_line: .byte 14,9,5
+ .ascii "PERFECT SHOT = +5000\0"
+
+
+about_line_0: .byte 13,0,7
+ .ascii "TOM BOMBEM\0"
+ .byte 14,1,11
+ .ascii "by\0"
+ .byte 9,2,6
+ .ascii "Vince Weaver\0"
+ .byte 12,3,0
+ .ascii "author if you squint ->\0"
+ .byte 11,5,0
+ .ascii "* Testing my asm skills\0"
+ .byte 10,7,0
+ .ascii "* Based on Tom Bombem:\0"
+ .byte 10,8,2
+ .ascii "Invasion of Inanimate\0"
+ .byte 10,9,2
+ .ascii "Objects, a game I\0"
+ .byte 10,10,2
+ .ascii "started 10 years ago\0"
+ .byte 10,11,2
+ .ascii "in Pascal/asm and is\0"
+ .byte 10,12,2
+ .ascii "still languishing\0"
+ .byte 10,13,2
+ .ascii "uncompleted in C/SDL.\0"
+ .byte 5,17,0
+ .ascii "Contact Vince:\0"
+ .byte 9,18,0
+ .ascii "vince@deater.net\0"
+ .byte 9,19,0
+ .ascii "http://www.deater.net/weave/\0"
+
+
+
+story_line_0: .byte 15,17,0
+ .ascii "It is the year 2025. All telemarketers\0"
+ .byte 15,18,0
+ .ascii "and unsolicited bulk e-mailers have\0"
+ .byte 15,19,0
+ .ascii "been exiled to Phobos.\0"
+
+story_line_1: .byte 10,17,0
+ .ascii "Right before being trapped forever they\0"
+ .byte 10,18,0
+ .ascii "manage to launch one last marketing\0"
+ .byte 10,19,0
+ .ascii "droid. \0"
+ # note spaces needed to overwrite old text?
+
+story_line_2:
+ .byte 9,0,0
+ .ascii "You are Tom Bombem.\0"
+ .byte 9,2,0
+ .ascii "You drew the short straw.\0"
+ .byte 9,4,0
+ .ascii "So it is up to you to\0"
+ .byte 9,5,2
+ .ascii "fight through the ads\0"
+ .byte 9,6,2
+ .ascii "and destroy the evil\0"
+ .byte 9,7,2
+ .ascii "marketing robot, thus\0"
+ .byte 9,8,2
+ .ascii "restoring harmony to\0"
+ .byte 9,9,2
+ .ascii "the space lanes.\0"
+ .byte 11,12,7
+ .ascii "GOOD LUCK!\0"
+
+ending_line:
+ .byte 15,0,0
+ .ascii "INCOMING MESSAGE FROM\0"
+ .byte 15,1,5
+ .ascii "** EARTH **\0"
+ .byte 14,3,0
+ .ascii "Congratulations Tom!\0"
+ .byte 14,4,0
+ .ascii "You've destroyed the\0"
+ .byte 14,5,2
+ .ascii "Marketing Menace!!\0"
+ .byte 14,7,0
+ .ascii "But wait...\0"
+ .byte 14,8,0
+ .ascii "Our sensors detect another batch of\0"
+ .byte 14,9,2
+ .ascii "enemies, moving even faster!\0"
+ .byte 14,11,0
+ .ascii "Feel free to quit at any time, but\0"
+ .byte 14,12,2
+ .ascii "remember no paycheck bonus unless\0"
+ .byte 14,13,2
+ .ascii "all are destroyed.\0"
+ .byte 14,15,0
+ .ascii "PS Your pet guinea\0"
+ .byte 14,16,3
+ .ascii "pig is doing\0"
+ .byte 14,17,3
+ .ascii "well.\0"
+ .byte 14,17,16
+ .ascii "-->\0"
+ .byte 15,22,0
+ .ascii "** END TRANSMISSION **\0"
+ending_line_2:
+ .byte 9,0,10
+ .ascii "Tom: *Sigh*\0"
+ .byte 15,10,0
+ .ascii "Press Any Key to Resume Fighting\0"
+
+
+help_line_0: .byte 15,0,10
+ .ascii "TOM BOMBEM\0"
+ .byte 7,1,14
+ .ascii "by\0"
+ .byte 15,2,9
+ .ascii "Vince Weaver\0"
+ .byte 15,4,0
+ .ascii "Key Bindings:\0"
+ .byte 7,6,2
+ .ascii "UP or 'i' : Move menu up\0"
+ .byte 7,7,2
+ .ascii "DOWN or 'm' : Move menu down\0"
+ .byte 7,8,2
+ .ascii "ENTER\0"
+ .byte 7,8,15
+ .ascii ": Selects current option\0"
+ .byte 7,10,2
+ .ascii "RIGHT or 'k' : Move ship right\0"
+ .byte 7,11,2
+ .ascii "LEFT of 'j' : Move ship left\0"
+ .byte 7,12,2
+ .ascii "SPACEBAR\0"
+ .byte 7,12,15
+ .ascii ": Shoots\0"
+ .byte 7,14,2
+ .ascii "F1 or 'h' : Displays help\0"
+ .byte 7,15,2
+ .ascii "ESC or 'q' : Quits\0"
+ .byte 7,16,2
+ .ascii "'p'\0"
+ .byte 7,16,15
+ .ascii ": Pauses\0"
+ .byte 7,17,2
+ .ascii "'s'\0"
+ .byte 7,17,15
+ .ascii ": Toggles sound\0"
+game_over_line: .byte 12,8,14
+ .ascii " GAME OVER! \0"
+game_paused_line: .byte 12,8,13
+ .ascii " GAME PAUSED! \0"
+quit_line: .byte 12,7,9
+ .ascii " QUIT? Are you sure? \0"
+block: .byte 219,0
+underscore: .ascii "_\0"
+
+shields_line: .byte 0,21,0
+ .ascii "SHIELDS:\0"
+score_line: .byte 15,22,0
+ .ascii "SCORE:\0"
+hiscore_line: .byte 15,22,20
+ .ascii "HISCORE:\0"
+level_line: .byte 15,23,0
+ .ascii "LEVEL:\0"
+
+high_score_line: .byte 14,7,15
+ .ascii "HIGH SCORE\0"
+
+new_high_line: .byte 13,5,13
+ .ascii "NEW HIGH SCORE\0"
+ .byte 14,7,2
+ .ascii "Use the arrows to pick your initials\0"
+ .byte 14,8,5
+ .ascii "Press ENTER when you are done\0"
+
+hiscore: .long 500
+hi_player: .ascii "KRG\0"
+
+game_flags: .byte 2 # bit 0 = Previously Paused
+ # bit 1 = Sound On/Off
+ # bit 2 = Shield/Score change?
+
+# timespec for nanosleep
+milisecond: .long 0
+ .long 1000000
+hundred_microsecond: .long 0
+ .long 100000
+#
+
+# vmw_soft.h
+# vmw @ 8,6
+# A VMW Software Production" @ 7,15
+
+vmw_sprite:
+.byte 23,8
+.byte 0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x2,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x2,0x1,0x1,0x1,0x1,0x1,0x1,0x1
+.byte 0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x2,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x2,0x1,0x1,0x1,0x1,0x1,0x1,0x1
+.byte 0x0,0x4,0x4,0x4,0x4,0x4,0x2,0x2,0x2,0x1,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x1,0x1,0x1,0x1,0x1,0x0
+.byte 0x0,0x4,0x4,0x4,0x4,0x4,0x2,0x2,0x2,0x1,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x1,0x1,0x1,0x1,0x1,0x0
+.byte 0x0,0x0,0x4,0x4,0x4,0x2,0x2,0x2,0x2,0x2,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x1,0x1,0x1,0x0,0x0
+.byte 0x0,0x0,0x4,0x4,0x4,0x2,0x2,0x2,0x2,0x2,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x1,0x1,0x1,0x0,0x0
+.byte 0x0,0x0,0x0,0x4,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x1,0x0,0x0,0x0
+.byte 0x0,0x0,0x0,0x4,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x1,0x0,0x0,0x0
+
+# opener.h
+# 40x20
+# 0,5 Merciless Marauding Malicious Marketers
+
+opener_sprite:
+.byte 40,20
+.byte 0x9,0x9,0x9,0x0,0x9,0x9,0x9,0x0,0x9,0x0,0x0,0x0,0x9,0x0,0xC,0xC,0x0,0x0,0xC,0xC,0xC,0x0,0xC,0x0,0x0,0x0,0xC,0x0,0xC,0xC,0x0,0x0,0xC,0xC,0x0,0xC,0x0,0x0,0x0,0xC
+.byte 0x0,0x9,0x0,0x0,0x9,0x0,0x9,0x0,0x9,0x9,0x0,0x9,0x9,0x0,0xC,0x0,0xC,0x0,0xC,0x0,0xC,0x0,0xC,0xC,0x0,0xC,0xC,0x0,0xC,0x0,0xC,0x0,0xC,0x0,0x0,0xC,0xC,0x0,0xC,0xC
+.byte 0x0,0x9,0x0,0x0,0x9,0x0,0x9,0x0,0x9,0x0,0x9,0x0,0x9,0x0,0xC,0xC,0x0,0x0,0xC,0x0,0xC,0x0,0xC,0x0,0xC,0x0,0xC,0x0,0xC,0xC,0x0,0x0,0xC,0xC,0x0,0xC,0x0,0xC,0x0,0xC
+.byte 0x0,0x9,0x0,0x0,0x9,0x0,0x9,0x0,0x9,0x0,0x0,0x0,0x9,0x0,0xC,0x0,0xC,0x0,0xC,0x0,0xC,0x0,0xC,0x0,0x0,0x0,0xC,0x0,0xC,0x0,0xC,0x0,0xC,0x0,0x0,0xC,0x0,0x0,0x0,0xC
+.byte 0x0,0x9,0x0,0x0,0x9,0x9,0x9,0x0,0x9,0x0,0x0,0x0,0x9,0x0,0xC,0xC,0x0,0x0,0xC,0xC,0xC,0x0,0xC,0x0,0x0,0x0,0xC,0x0,0xC,0xC,0x0,0x0,0xC,0xC,0x0,0xC,0x0,0x0,0x0,0xC
+.byte 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
+.byte 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0
+.byte 0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xF,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
+.byte 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
+.byte 0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xF,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
+.byte 0x0,0x0,0x0,0x0,0x0,0x7,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xB,0x0,0x0,0x0
+.byte 0x0,0xE,0x0,0x0,0x0,0x7,0x7,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xB,0x4,0x4
+.byte 0x0,0xE,0xE,0xE,0x9,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0x9,0x9,0x9,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xB,0xC,0xC
+.byte 0xE,0xE,0x4,0xC,0x9,0xF,0x4,0x2,0x9,0x2,0x9,0xF,0xF,0x9,0x9,0x9,0x9,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xB,0x0,0xC,0xC
+.byte 0x0,0xE,0xE,0xC,0x9,0xF,0x4,0x2,0x9,0x2,0x9,0xF,0xF,0x9,0x9,0x9,0x9,0x9,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xC,0xC
+.byte 0x0,0x0,0x0,0xE,0x9,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0xF,0xF,0xF,0xF,0xF,0xF,0x0,0x0,0x0,0x0,0xE,0x7,0x7,0x7,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xC,0xC
+.byte 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xF,0x0,0x0,0x0,0x0,0x4,0x4
+.byte 0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
+.byte 0x0,0xF,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xF,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
+.byte 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0
+
+
+# vince.h
+# 16x20
+
+vince_sprite:
+.byte 16,20
+.byte 0x0,0x0,0x8,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0x8,0x0,0x0,0x0,0x0
+.byte 0x0,0x8,0x7,0xf,0xf,0xf,0xf,0x7,0xf,0xf,0xf,0xf,0x7,0x7,0x0,0x0
+.byte 0x8,0x7,0x7,0x7,0x7,0x7,0x8,0x7,0xf,0x7,0x7,0xf,0xf,0xf,0x7,0x0
+.byte 0x7,0x8,0x0,0x8,0x7,0x7,0x7,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0x8
+.byte 0x7,0x0,0x8,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0x7
+.byte 0x8,0x0,0x7,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0x7,0xf,0x7,0x7,0x8,0x8
+.byte 0x8,0x8,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0x8,0x8,0x0,0x8,0x7
+.byte 0x8,0x7,0xf,0xf,0xf,0xf,0x7,0xf,0xf,0xf,0x7,0x0,0x8,0x0,0x8,0x7
+.byte 0x7,0x8,0x8,0x7,0xf,0x8,0x0,0x8,0x7,0xf,0x7,0x0,0x0,0x0,0x0,0x8
+.byte 0x0,0x7,0x0,0x8,0xf,0x0,0x0,0x8,0x0,0x8,0xf,0x8,0x0,0x0,0x0,0x8
+.byte 0x0,0x7,0x8,0x7,0xf,0x8,0x0,0x0,0x7,0xf,0xf,0x7,0x0,0x0,0x0,0x7
+.byte 0x0,0xf,0x8,0xf,0xf,0xf,0x7,0x7,0xf,0xf,0xf,0xf,0x0,0x0,0x0,0x7
+.byte 0x0,0xf,0x7,0x8,0x8,0x7,0xf,0xf,0xf,0xf,0xf,0x8,0x8,0x8,0x7,0x7
+.byte 0x0,0xf,0xf,0x8,0x0,0x7,0xf,0xf,0xf,0xf,0x7,0x0,0x7,0x7,0x7,0x0
+.byte 0x0,0xf,0xf,0x7,0x8,0x7,0x7,0xf,0xf,0xf,0x7,0x0,0x7,0x7,0x8,0x0
+.byte 0x0,0x7,0x7,0x0,0x8,0x0,0x0,0x7,0x7,0x0,0x0,0xf,0x8,0x7,0x0,0x0
+.byte 0x0,0x8,0xf,0xf,0x8,0xf,0xf,0x7,0x0,0x0,0x8,0x7,0x7,0x8,0x0,0x0
+.byte 0x0,0x0,0xf,0x7,0x7,0x7,0xf,0x7,0x7,0x8,0x8,0xf,0x7,0x0,0x0,0x0
+.byte 0x0,0x0,0x7,0xf,0xf,0xf,0xf,0x8,0x8,0x0,0x8,0xf,0x8,0x0,0x0,0x0
+.byte 0x0,0x0,0x0,0x8,0x8,0x0,0x0,0x0,0x0,0x0,0x7,0xf,0x8,0x0,0x0,0x0
+
+
+# phobos.h
+
+# 40x16
+
+phobos_sprite:
+.byte 40,15
+.byte 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
+.byte 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf,0x0,0x0,0x0
+.byte 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
+.byte 0x0,0x0,0x0,0x0,0x0,0x7,0xf,0xf,0xf,0xf,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
+.byte 0x0,0x0,0x0,0x0,0x4,0xc,0xc,0xc,0xc,0xc,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
+.byte 0x0,0x0,0x0,0x4,0xc,0xc,0xc,0xc,0xc,0x4,0xc,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
+.byte 0x0,0x0,0x0,0x4,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
+.byte 0x0,0x0,0x0,0x4,0xc,0xc,0xc,0x4,0xc,0xc,0xc,0xc,0x0,0x0,0x0,0x0,0x0,0x8,0x6,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
+.byte 0x0,0x0,0x0,0x4,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
+.byte 0x0,0x0,0x0,0x4,0xc,0xc,0xc,0xc,0xc,0x4,0xc,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
+.byte 0x0,0x0,0x0,0x0,0x4,0xc,0xc,0xc,0xc,0xc,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
+.byte 0x0,0x0,0x0,0x0,0x0,0x7,0xf,0xf,0xf,0xf,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
+.byte 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
+.byte 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
+.byte 0x0,0x0,0x0,0xf,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
+
+
+# 3x1
+evil_ship_sprite:
+.byte 3,1
+.byte 0x3,0xb,0x3
+
+# tom.h
+# 16x18
+
+tom_sprite:
+.byte 16,18
+.byte 0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x9,0x9,0x9,0x9,0x0,0x0,0x0,0x0
+.byte 0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0,0x8,0x8,0x9,0x9,0x0,0x0,0x0,0x0
+.byte 0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0,0x8,0x8,0x9,0x9,0x0,0x0,0x0,0x0
+.byte 0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0,0x8,0x8,0x9,0x9,0x0,0x0,0x0,0x0
+.byte 0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0,0x8,0x8,0x9,0x9,0x0,0x0,0x0,0x0
+.byte 0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x9,0x9,0x0,0x0,0x0,0x0,0x0,0x0
+.byte 0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x9,0x9,0x9,0x9,0x9,0x9,0x9,0x9
+.byte 0x1,0x1,0x9,0x9,0x1,0x1,0x1,0x1,0x9,0x9,0xc,0xc,0x1,0x1,0x9,0x9
+.byte 0x1,0x1,0x9,0x9,0x1,0x1,0x1,0x1,0x9,0x9,0x9,0x9,0x1,0x1,0x9,0x9
+.byte 0x1,0x1,0x9,0x9,0x1,0x1,0x1,0x1,0x9,0x9,0x9,0x9,0x1,0x1,0x9,0x9
+.byte 0x1,0x1,0x9,0x9,0x1,0x1,0x1,0x1,0x9,0x9,0x9,0x9,0x1,0x1,0x9,0x9
+.byte 0x1,0x1,0x9,0x9,0x1,0x1,0x1,0x1,0x9,0x9,0x9,0x9,0x1,0x1,0x9,0x9
+.byte 0x3,0x3,0xb,0xb,0x1,0x1,0x9,0x9,0x1,0x1,0x9,0x9,0x3,0x3,0xb,0xb
+.byte 0x0,0x0,0x0,0x0,0x1,0x1,0x9,0x9,0x1,0x1,0x9,0x9,0x0,0x0,0x0,0x0
+.byte 0x0,0x0,0x0,0x0,0x1,0x1,0x9,0x9,0x1,0x1,0x9,0x9,0x0,0x0,0x0,0x0
+.byte 0x0,0x0,0x0,0x0,0x1,0x1,0x9,0x9,0x1,0x1,0x9,0x9,0x0,0x0,0x0,0x0
+.byte 0x0,0x0,0x0,0x0,0x3,0x3,0xb,0xb,0x3,0x3,0xb,0xb,0x0,0x0,0x0,0x0
+.byte 0x0,0x0,0x0,0x0,0x8,0x8,0x7,0x7,0x8,0x8,0x7,0x7,0x0,0x0,0x0,0x0
+
+# game_sprites.h
+
+# 8x4
+ship_sprite:
+.byte 0x8,0x4
+.byte 0x0,0x0,0x9,0x9,0x9,0x0,0x0,0x0
+.byte 0x0,0x7,0xf,0xf,0xf,0x7,0x0,0x0
+.byte 0x7,0x7,0xf,0x7,0xf,0x7,0x7,0x0
+.byte 0x0,0x0,0x0,0xe,0x0,0x0,0x0,0x0
+
+
+# 1x3
+missile_sprite:
+.byte 0x1,0x3
+.byte 0x7
+.byte 0x7
+.byte 0xe
+
+# 3x2
+enemy_sprites:
+
+enemy_sprite0:
+.byte 0x3,0x2
+.byte 0xf,0xf,0x4
+.byte 0xf,0xf,0xf
+
+enemy_sprite1:
+.byte 0x3,0x2
+.byte 0x9,0x0,0x9
+.byte 0x0,0x9,0x0
+
+enemy_sprite2:
+.byte 0x3,0x2
+.byte 0x2,0xa,0x2
+.byte 0x2,0xa,0x2
+
+enemy_sprite3:
+.byte 0x3,0x2
+.byte 0x3,0x6,0x6
+.byte 0x3,0x6,0x6
+
+enemy_sprite4:
+.byte 0x3,0x2
+.byte 0x0,0xe,0x0
+.byte 0xe,0x0,0xe
+
+enemy_sprite5:
+.byte 0x3,0x2
+.byte 0xc,0xf,0xf
+.byte 0xc,0x7,0x7
+
+
+explosion_sprites:
+
+explosion_sprite0:
+.byte 0x3,0x2
+.byte 0xe,0xe,0xc
+.byte 0xc,0xe,0x8
+
+explosion_sprite1:
+.byte 0x3,0x2
+.byte 0x7,0x7,0x4
+.byte 0x4,0x7,0x0
+
+explosion_sprite2:
+.byte 0x3,0x2
+.byte 0x8,0x8,0x0
+.byte 0x0,0x8,0x8
+
+
+# boss.h
+
+# 3x2
+
+smoke_sprites:
+
+smoke_sprite0:
+.byte 0x3,0x1
+.byte 0x0,0x8,0x0
+
+smoke_sprite1:
+.byte 0x3,0x1
+.byte 0x8,0x7,0x8
+
+smoke_sprite2:
+.byte 0x3,0x1
+.byte 0x7,0x4,0x7
+
+# 13x3
+boss_sprite:
+.byte 0xd,0x3
+.byte 0xf,0x7,0x4,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0x4,0x7,0xf
+.byte 0xf,0x8,0x7,0x4,0x4,0x3,0xb,0x3,0x4,0x4,0x7,0x8,0xf
+.byte 0xf,0x0,0x8,0x7,0x3,0xb,0xe,0xb,0x3,0x7,0x8,0x0,0xf
+
+
+# 1x2
+laser_sprites:
+
+laser_sprite0:
+.byte 0x1,0x2
+.byte 0xd
+.byte 0x5
+
+laser_sprite1:
+.byte 0x1,0x2
+.byte 0x5
+.byte 0xd
+
+# ending.h
+
+# 7x7
+tom_head_sprite:
+.byte 0x7,0x7
+.byte 0x0,0x1,0x1,0x1,0x9,0x9,0x0
+.byte 0x0,0x1,0x0,0x0,0x8,0x9,0x0
+.byte 0x0,0x1,0x0,0x0,0x8,0x9,0x0
+.byte 0x0,0x1,0x0,0x0,0x8,0x9,0x0
+.byte 0x0,0x1,0x0,0x0,0x8,0x9,0x0
+.byte 0x0,0x0,0x1,0x1,0x9,0x0,0x0
+.byte 0x1,0x1,0x1,0x1,0x9,0x9,0x9
+
+
+# 5x6
+earth_sprite:
+.byte 0x5,0x6
+.byte 0x0,0x7,0xf,0xf,0x0
+.byte 0x2,0xA,0xA,0x9,0x9
+.byte 0x1,0xA,0x9,0x9,0x9
+.byte 0x1,0x9,0xA,0xA,0x9
+.byte 0x1,0x9,0xA,0x9,0x9
+.byte 0x0,0x7,0xf,0xf,0x0
+
+# 19x7
+susie_sprite:
+.byte 0x13,0x7
+.byte 0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x8,0x0,0xf,0xf,0x0,0x7,0x7,0x7
+.byte 0x7,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x8,0x0,0x0,0x7,0x7
+.byte 0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7
+.byte 0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7
+.byte 0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x7,0x7
+.byte 0x7,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x7,0x7,0x7,0x7
+.byte 0x7,0x7,0x7,0x7,0x8,0x8,0x8,0x7,0x7,0x7,0x7,0x7,0x8,0x8,0x8,0x7,0x7,0x7,0x7
diff --git a/tb_asm/lzss.c b/tb_asm/lzss.c
new file mode 100644
index 0000000..7ec9aa4
--- /dev/null
+++ b/tb_asm/lzss.c
@@ -0,0 +1,320 @@
+/**************************************************************
+ LZSS.C -- A Data Compression Program
+ (tab = 4 spaces)
+***************************************************************
+ 4/6/1989 Haruhiko Okumura
+ Use, distribute, and modify this program freely.
+ Please send me your improved versions.
+ PC-VAN SCIENCE
+ NIFTY-Serve PAF01022
+ CompuServe 74050,1022
+**************************************************************
+
+ WARNING: order of match_position and match_lenght changed!
+ see lines 178 to 182
+ Mofication by
+
+
+ Also modified to have N,F,etc, etc to be parameters, not
+ hard-coded -- vmw
+ */
+
+
+
+#include
+#include
+#include
+#include
+
+
+#define num_trees 256
+
+ /* initialize trees */
+void newInitTree(int ring_buffer_size,int binary_search_index,
+ int *rson, int *dad) {
+
+ int i;
+
+ /* For i = 0 to N - 1, rson[i] and lson[i] will be the right and
+ left children of node i. These nodes need not be initialized.
+ Also, dad[i] is the parent of node i. These are initialized to
+ NIL (= N), which stands for 'not used.'
+ For i = 0 to 255, rson[N + i + 1] is the root of the tree
+ for strings that begin with character i. These are initialized
+ to NIL. Note there are 256 trees. */
+
+ for (i=ring_buffer_size+1; i<=ring_buffer_size+num_trees; i++)
+ rson[i] = binary_search_index;
+ for (i=0; i= 0) {
+ if (rson[p] != binary_search_index) p = rson[p];
+ else {
+ rson[p] = r;
+ dad[r] = p;
+ return;
+ }
+ }
+
+ else {
+ if (lson[p] != binary_search_index) p = lson[p];
+ else {
+ lson[p] = r;
+ dad[r] = p;
+ return;
+ }
+ }
+
+ for(i = 1; i < match_length_limit; i++)
+ if ((cmp = key[i] - text_buf[p + i]) != 0) break;
+ if (i > *match_length) {
+ *match_position = p;
+ if ((*match_length = i) >= match_length_limit) break;
+ }
+
+ }
+
+ dad[r] = dad[p];
+ lson[r] = lson[p];
+ rson[r] = rson[p];
+ dad[lson[p]] = r;
+ dad[rson[p]] = r;
+
+ if (rson[dad[p]] == p) rson[dad[p]] = r;
+ else lson[dad[p]] = r;
+ dad[p] = binary_search_index; /* remove p */
+
+}
+
+ /* deletes node p from tree */
+void newDeleteNode(int p, int binary_search_index,
+ int *dad, int *rson, int *lson) {
+
+ int q;
+
+ if (dad[p] == binary_search_index) return; /* not in tree */
+ if (rson[p] == binary_search_index) q = lson[p];
+ else if (lson[p] == binary_search_index) q = rson[p];
+ else {
+ q = lson[p];
+ if (rson[q] != binary_search_index) {
+ do { q = rson[q]; } while (rson[q] != binary_search_index);
+ rson[dad[q]] = lson[q];
+ dad[lson[q]] = dad[q];
+ lson[q] = lson[p];
+ dad[lson[p]] = q;
+ }
+ rson[q] = rson[p]; dad[rson[p]] = q;
+ }
+ dad[q] = dad[p];
+ if (rson[dad[p]] == p) rson[dad[p]] = q;
+ else lson[dad[p]] = q;
+ dad[p] = binary_search_index;
+}
+
+int lzss_encode_better(FILE *infile,FILE *header,FILE *outfile,
+ unsigned char frequent_char,
+ int ring_buffer_size, int position_length_threshold) {
+
+// unsigned char frequent_char='#';
+// int ring_buffer_size=1024; /* N */
+ int match_length_limit; //=64; /* F */
+ /*int position_length_threshold=2; THRESHOLD */
+ int binary_search_index=ring_buffer_size; /* NIL */
+ int position_bits; //=10;
+// int length_bits=16-position_bits;
+
+ unsigned long int codesize = 0; /* code size counter */
+
+ int i, c, len, r, s, last_match_length, code_buf_ptr;
+
+ unsigned char code_buf[8*2+1], mask;
+
+ unsigned char *text_buf;
+
+ int match_position, match_length; /* of longest match. These are
+ set by the InsertNode() procedure. */
+ int *lson, *rson, *dad; /* left & right children &
+ parents -- These constitute
+ binary search trees. */
+
+
+ /* determine stuff from ring_buffer_size */
+ /* fake log2 algorithm */
+
+ i=1;
+ while (((ring_buffer_size-1)>>i) >=1) {
+ i++;
+ };
+
+ position_bits=i;
+ match_length_limit=1<<(16-position_bits);
+// printf("%i, %i %i %i '%c'\n",ring_buffer_size,position_bits,match_length_limit
+// ,position_length_threshold,frequent_char);
+
+
+
+
+
+
+ /* ring buffer of size N, with extra F-1
+ bytes to facilitate string comparison */
+ text_buf=calloc(ring_buffer_size+match_length_limit-1,sizeof(unsigned char));
+ lson=calloc(ring_buffer_size+1,sizeof(int));
+ rson=calloc(ring_buffer_size+num_trees+1,sizeof(int));
+ dad=calloc(ring_buffer_size+1,sizeof(int));
+
+ newInitTree(ring_buffer_size,binary_search_index,rson,dad); /* initialize trees */
+
+ code_buf[0] = 0; /* code_buf[1..16] saves eight units of code, and
+ code_buf[0] works as eight flags, "1" representing
+ that the unit is an unencoded letter (1 byte),
+ "0" a position-and-length pair (2 bytes).
+ Thus, eight units require at most 16 bytes of code. */
+ code_buf_ptr = mask = 1;
+ s = 0;
+ r = ring_buffer_size - match_length_limit;
+
+ if (header!=NULL) {
+ fprintf(header,".equ FREQUENT_CHAR,'%c'\n",frequent_char);
+ fprintf(header,".equ N,%i\n",ring_buffer_size);
+ fprintf(header,".equ F,%i\n",match_length_limit);
+ fprintf(header,".equ THRESHOLD,%i\n",position_length_threshold);
+ fprintf(header,".equ P_BITS,%i\n",position_bits);
+ fprintf(header,".equ POSITION_MASK,%i\n",(0xff>>(8-(position_bits-8))));
+ }
+ if (outfile!=NULL) {
+ fprintf(outfile,"tb_data_begin:\n");
+ }
+ /* Clear the buffer with any character that will appear often. */
+ for(i=0; i<(ring_buffer_size-match_length_limit); i++)
+ text_buf[i]=frequent_char;
+
+// printf("%i to %i = %i\n",0,ring_buffer_size-match_length_limit,frequent_char);
+
+// printf("%i to %i = ",r,r+match_length_limit);
+ for(len=0; len len) match_length = len; /* match_length
+ may be spuriously long near the end of text. */
+ if (match_length <= position_length_threshold) {
+ match_length=1; /* Not long enough match. Send one byte. */
+ code_buf[0] |= mask; /* 'send one byte' flag */
+ code_buf[code_buf_ptr++] = text_buf[r]; /* Send uncoded. */
+// printf("single: %i @ %i\n",text_buf[r],r);
+ } else {
+// printf("pos : %i\tlen : %i\n",match_position,match_length);
+
+ code_buf[code_buf_ptr++] = (unsigned char) match_position;
+
+
+ code_buf[code_buf_ptr++] = (unsigned char)
+ ( ((match_position>>8) & (0xff >> (8-(position_bits-8)))) |
+ ((match_length-(position_length_threshold+1))<<(position_bits-8)) );
+
+// code_buf[code_buf_ptr++] = (unsigned char)
+// (((match_position >> 8) & 7) |
+// (match_length - (position_length_threshold+1))<<3);
+
+ }
+ if ((mask <<= 1) == 0) { /* Shift mask left one bit. */
+ if (outfile!=NULL) {
+ fprintf(outfile,"\t.byte\t");
+ for(i = 0; i < code_buf_ptr; i++) { /* Send at most 8 units of */
+ fprintf(outfile,"%d%c",code_buf[i],(i==code_buf_ptr-1)?'\n':',');
+ }
+ }
+ codesize += code_buf_ptr;
+ code_buf[0] = 0; code_buf_ptr = mask = 1;
+ }
+ last_match_length = match_length;
+ for (i = 0; i < last_match_length && (c = getc(infile)) != EOF; i++) {
+ newDeleteNode(s,binary_search_index,
+ dad,rson,lson); /* Delete old strings and */
+ text_buf[s] = c; /* read new bytes */
+ if (s < match_length_limit - 1) text_buf[s + ring_buffer_size] = c; /* If the position is
+ near the end of buffer, extend the buffer to make
+ string comparison easier. */
+ s = (s + 1) & (ring_buffer_size - 1);
+ r = (r + 1) & (ring_buffer_size - 1);
+ /* Since this is a ring buffer, increment the position
+ modulo N. */
+ newInsertNode(r,ring_buffer_size,binary_search_index,
+ match_length_limit,text_buf,rson,lson,dad,
+ &match_length,&match_position);
+ /* Register the string in text_buf[r..r+F-1] */
+ }
+
+ while (i++ < last_match_length) { /* After the end of text, */
+ newDeleteNode(s,binary_search_index,
+ dad,rson,lson); /* no need to read, but */
+ s = (s + 1) & (ring_buffer_size - 1);
+ r = (r + 1) & (ring_buffer_size - 1);
+ if (--len) newInsertNode(r,ring_buffer_size,binary_search_index,
+ match_length_limit,text_buf,rson,lson,dad,
+ &match_length,&match_position);
+ /* buffer may not be empty. */
+ }
+ } while (len > 0); /* until length of string to be processed is zero */
+
+ if (code_buf_ptr > 1) { /* Send remaining code. */
+ if (outfile!=NULL) {
+ fprintf(outfile,"\t.byte\t");
+ for(i = 0; i < code_buf_ptr; i++) {
+ fprintf(outfile,"%d%c",code_buf[i],(i==code_buf_ptr-1)?'\n':',');
+ }
+ }
+ codesize += code_buf_ptr;
+ }
+
+ if (outfile!=NULL) fprintf(outfile,"tb_data_end:\n");
+ free(text_buf);
+ free(lson);
+ free(rson);
+ free(dad);
+ return codesize;
+}
diff --git a/tb_asm/lzss.h b/tb_asm/lzss.h
new file mode 100644
index 0000000..2d8f3b9
--- /dev/null
+++ b/tb_asm/lzss.h
@@ -0,0 +1,4 @@
+int lzss_encode(FILE *infile,FILE *outfile);
+int lzss_encode_better(FILE *infile,FILE *header,FILE *outfile,
+ unsigned char frequent_char,
+ int ring_buffer_size, int position_length_threshold);
diff --git a/tb_asm/optimization b/tb_asm/optimization
new file mode 100644
index 0000000..aeb42fa
--- /dev/null
+++ b/tb_asm/optimization
@@ -0,0 +1,57 @@
+Chart of size optimization
+Using gas 2.11.93.0.2
+
+goal = 8192 bytes
+
+Version Size (bytes) Notes
+~~~~~~~~ ~~~~~~~~~~~~~ ~~~~~~
+ 0.26 25422 First working version
+ 0.26 13260 Stripped
+ 0.27 13172 Removing extraneous spaces from strings
+ 0.27 11076 Compressed Data Segment
+ 0.28 8940 Removed ".data" line to force data+text in same segment
+ 0.28 8668 Using sstrip "super-strip"
+ 0.29 8656 move get_char to return status in carry flag
+ 1 byte immediate moves -> push/pop
+ 0.29 8620 make "blit_219"
+ 0.29 8592 Optimizing "do_story" routine to remove %bp use
+ 0.29 8556 Optimize "do_menu" to use lea
+ 0.29 8544 convert verify_quit to use zero flag result
+ 0.29 8528 convert check_inside to use carry flag for status
+ 0.29 8452 move sound_freq to one 32bit value rather than 16 f/d pair
+ 0.29 8448 optimize high score routines
+ 0.29 8440 change cmp $0/jl to just js
+ 0.30 8312 messing with new_game
+ 0.30 8283 more removal of bx->bp in new_game
+ 0.30 8231 cheat, have functions called at end of other functions instead have them follow and thus shave the end saving a call
+ 0.30 8228 remove extraneous phobos_sprite line
+ 0.30 8193 Messing with jmping midway into functions for code re-use
+ 0.30 8187 merging the ioctl commands ;)
+ 0.31 8151 fixing the game to work again, culling unneeded code
+ 0.32 8174 Added some game balancing stuff bloating it back up a bit
+
+I am guessing with further code manipulation could get another 100-200
+bytes off. But have become lazy.
+
+Why optimize for size? It makes you realize how wasteful high level
+code is even with optimizing compilers. Also on x86 optimizing for size is
+the same from 386 on up. Optimizing for speed is so convoluted you have to
+pick a particular generation of processor and even then it takes lots
+of tuning because speed can depent on other things such as cache hits.
+One nice thing about programs under 8k, they most likely fit in
+the icache entirely ;)
+
+Big lessons here. Function calls are killer! They take up 6 bytes!
+Avoid them whenever possible.
+
+Also, loading 32bit constants is also a pain. Also take 6 bytes!
+Not as bad as on RISC where can take up to 8 bytes. Luckily x86
+allows push imm/pop reg to load 8bit constant into 32 bit register
+in 3 bytes.
+
+Doing anything in memory rather than register is at least 6+ bytes!
+Not as bad as RISC where you must often load/modify/store (12bytes)
+but still a pain. Would possibly be mitigated if more registers
+available, but that would probably make code-size bigger to accomodate
+extra opcodes [waiting for x86-64 to see].
+
diff --git a/tb_asm/sstrip/Makefile b/tb_asm/sstrip/Makefile
new file mode 100644
index 0000000..cb4e92e
--- /dev/null
+++ b/tb_asm/sstrip/Makefile
@@ -0,0 +1,11 @@
+# Makefile for sstrip
+
+ifeq ($(ARCH),)
+ ARCH = $(shell uname -m)
+endif
+
+sstrip: sstrip.c
+ gcc -ggdb -Wall -W -DARCHITECTURE=\"asm_elf_$(ARCH).h\" -o sstrip sstrip.c
+
+clean:
+ rm -f sstrip *~ *.o
diff --git a/tb_asm/sstrip/README b/tb_asm/sstrip/README
new file mode 100644
index 0000000..218376c
--- /dev/null
+++ b/tb_asm/sstrip/README
@@ -0,0 +1,40 @@
+sstrip is a small utility that removes the contents at the end of an
+ELF file that are not part of the program's memory image.
+
+Most ELF executables are built with both a program header table and a
+section header table. However, only the former is required in order
+for the OS to load, link and execute a program. sstrip attempts to
+extract the ELF header, the program header table, and its contents,
+leaving everything else in the bit bucket. It can only remove parts of
+the file that occur at the end, after the parts to be saved. However,
+this almost always includes the section header table, and occasionally
+a few random sections that are not used when running a program.
+
+It should be noted that the GNU bfd library is (understandably)
+dependent on the section header table as an index to the file's
+contents. Thus, an executable file that has no section header table
+cannot be used with gdb, objdump, or any other program based upon the
+bfd library, at all. In fact, the program will not even recognize the
+file as a valid executable. (This limitation is noted in the source
+code comments for bfd, and is marked "FIXME", so this may change at
+some future date. However, I would imagine that it is a pretty
+low-priority item, as executables without a section header table are
+rare in the extreme.) This probably also explains why strip doesn't
+offer the option to do this.
+
+Shared library files may also have their section header table removed.
+Such a library will still function; however, it will no longer be
+possible for a compiler to link a new program against it.
+
+As an added bonus, sstrip also tries to removes trailing zero bytes
+from the end of the file. (This normally cannot be done with an
+executable that has a section header table.)
+
+sstrip is a very simplistic program. It depends upon the common
+practice of putting the parts of the file that contribute to the
+memory image at the front, and the remaining material at the end. This
+permits it to discard the latter material without affecting file
+offsets and memory addresses in what remains. Of course, the ELF
+standard permits files to be organized in almost any order, so if a
+pathological linker decided to put its section headers at the top,
+sstrip would be useless on such executables.
diff --git a/tb_asm/sstrip/README.MORE b/tb_asm/sstrip/README.MORE
new file mode 100644
index 0000000..2e0234e
--- /dev/null
+++ b/tb_asm/sstrip/README.MORE
@@ -0,0 +1,5 @@
+This utility by Brian Raiter
+Available at his web-site
+http://www.muppetlabs.com/~breadbox/software/elfkickers.html
+Included here as per the GPL.
+
diff --git a/tb_asm/sstrip/asm_elf_RiSC.h b/tb_asm/sstrip/asm_elf_RiSC.h
new file mode 100644
index 0000000..5d294ff
--- /dev/null
+++ b/tb_asm/sstrip/asm_elf_RiSC.h
@@ -0,0 +1,3 @@
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2LSB
+#define ELF_ARCH 0xffff
diff --git a/tb_asm/sstrip/asm_elf_alpha.h b/tb_asm/sstrip/asm_elf_alpha.h
new file mode 100644
index 0000000..403e169
--- /dev/null
+++ b/tb_asm/sstrip/asm_elf_alpha.h
@@ -0,0 +1,6 @@
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS ELFCLASS64
+#define ELF_DATA ELFDATA2LSB
+#define ELF_ARCH EM_ALPHA
diff --git a/tb_asm/sstrip/asm_elf_arm.h b/tb_asm/sstrip/asm_elf_arm.h
new file mode 100644
index 0000000..8a5a1f1
--- /dev/null
+++ b/tb_asm/sstrip/asm_elf_arm.h
@@ -0,0 +1,10 @@
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS ELFCLASS32
+//#ifdef __ARMEB__
+//#define ELF_DATA ELFDATA2MSB
+//#else
+#define ELF_DATA ELFDATA2LSB
+//#endif
+#define ELF_ARCH EM_ARM
diff --git a/tb_asm/sstrip/asm_elf_armbe.h b/tb_asm/sstrip/asm_elf_armbe.h
new file mode 100644
index 0000000..8a5a1f1
--- /dev/null
+++ b/tb_asm/sstrip/asm_elf_armbe.h
@@ -0,0 +1,10 @@
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS ELFCLASS32
+//#ifdef __ARMEB__
+//#define ELF_DATA ELFDATA2MSB
+//#else
+#define ELF_DATA ELFDATA2LSB
+//#endif
+#define ELF_ARCH EM_ARM
diff --git a/tb_asm/sstrip/asm_elf_armv5tel.h b/tb_asm/sstrip/asm_elf_armv5tel.h
new file mode 100644
index 0000000..8a5a1f1
--- /dev/null
+++ b/tb_asm/sstrip/asm_elf_armv5tel.h
@@ -0,0 +1,10 @@
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS ELFCLASS32
+//#ifdef __ARMEB__
+//#define ELF_DATA ELFDATA2MSB
+//#else
+#define ELF_DATA ELFDATA2LSB
+//#endif
+#define ELF_ARCH EM_ARM
diff --git a/tb_asm/sstrip/asm_elf_avr32.h b/tb_asm/sstrip/asm_elf_avr32.h
new file mode 100644
index 0000000..c7d9d6c
--- /dev/null
+++ b/tb_asm/sstrip/asm_elf_avr32.h
@@ -0,0 +1,7 @@
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2LSB
+//#define ELF_DATA ELFDATA2MSB
+#define ELF_ARCH EM_AVR32
diff --git a/tb_asm/sstrip/asm_elf_blackfin.h b/tb_asm/sstrip/asm_elf_blackfin.h
new file mode 100644
index 0000000..0ff41b4
--- /dev/null
+++ b/tb_asm/sstrip/asm_elf_blackfin.h
@@ -0,0 +1,6 @@
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2LSB
+#define ELF_ARCH EM_BLACKFIN
diff --git a/tb_asm/sstrip/asm_elf_crisv32.h b/tb_asm/sstrip/asm_elf_crisv32.h
new file mode 100644
index 0000000..01407f3
--- /dev/null
+++ b/tb_asm/sstrip/asm_elf_crisv32.h
@@ -0,0 +1,6 @@
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2LSB
+#define ELF_ARCH EM_CRIS
diff --git a/tb_asm/sstrip/asm_elf_frv.h b/tb_asm/sstrip/asm_elf_frv.h
new file mode 100644
index 0000000..f40d06e
--- /dev/null
+++ b/tb_asm/sstrip/asm_elf_frv.h
@@ -0,0 +1,6 @@
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2MSB
+#define ELF_ARCH EM_FRV
diff --git a/tb_asm/sstrip/asm_elf_h8300.h b/tb_asm/sstrip/asm_elf_h8300.h
new file mode 100644
index 0000000..3d04b96
--- /dev/null
+++ b/tb_asm/sstrip/asm_elf_h8300.h
@@ -0,0 +1,6 @@
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2MSB
+#define ELF_ARCH EM_H8_300
diff --git a/tb_asm/sstrip/asm_elf_i686.h b/tb_asm/sstrip/asm_elf_i686.h
new file mode 100644
index 0000000..74c343f
--- /dev/null
+++ b/tb_asm/sstrip/asm_elf_i686.h
@@ -0,0 +1,5 @@
+/* These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2LSB
+#define ELF_ARCH EM_386
diff --git a/tb_asm/sstrip/asm_elf_ia64.h b/tb_asm/sstrip/asm_elf_ia64.h
new file mode 100644
index 0000000..e44b218
--- /dev/null
+++ b/tb_asm/sstrip/asm_elf_ia64.h
@@ -0,0 +1,6 @@
+/* These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS ELFCLASS64
+#define ELF_DATA ELFDATA2LSB
+#define ELF_ARCH EM_IA_64
+
diff --git a/tb_asm/sstrip/asm_elf_m32r.h b/tb_asm/sstrip/asm_elf_m32r.h
new file mode 100644
index 0000000..37effc9
--- /dev/null
+++ b/tb_asm/sstrip/asm_elf_m32r.h
@@ -0,0 +1,7 @@
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2LSB
+//#define ELF_DATA ELFDATA2MSB
+#define ELF_ARCH EM_M32R
diff --git a/tb_asm/sstrip/asm_elf_m68k.h b/tb_asm/sstrip/asm_elf_m68k.h
new file mode 100644
index 0000000..f15efc8
--- /dev/null
+++ b/tb_asm/sstrip/asm_elf_m68k.h
@@ -0,0 +1,6 @@
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2MSB
+#define ELF_ARCH EM_68K
diff --git a/tb_asm/sstrip/asm_elf_microblaze.h b/tb_asm/sstrip/asm_elf_microblaze.h
new file mode 100644
index 0000000..46a0cef
--- /dev/null
+++ b/tb_asm/sstrip/asm_elf_microblaze.h
@@ -0,0 +1,8 @@
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define EM_XILINX_MICROBLAZE 0xbaab
+#define ELF_ARCH EM_XILINX_MICROBLAZE
+#define ELF_CLASS ELFCLASS32
+//#define ELF_DATA ELFDATA2LSB
+#define ELF_DATA ELFDATA2MSB
diff --git a/tb_asm/sstrip/asm_elf_mips.h b/tb_asm/sstrip/asm_elf_mips.h
new file mode 100644
index 0000000..f2844c0
--- /dev/null
+++ b/tb_asm/sstrip/asm_elf_mips.h
@@ -0,0 +1,8 @@
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS ELFCLASS32
+//#define ELF_CLASS ELFCLASS64
+#define ELF_DATA ELFDATA2MSB
+//#define ELF_DATA ELFDATA2LSB
+#define ELF_ARCH EM_MIPS
diff --git a/tb_asm/sstrip/asm_elf_mips64.h b/tb_asm/sstrip/asm_elf_mips64.h
new file mode 100644
index 0000000..f2844c0
--- /dev/null
+++ b/tb_asm/sstrip/asm_elf_mips64.h
@@ -0,0 +1,8 @@
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS ELFCLASS32
+//#define ELF_CLASS ELFCLASS64
+#define ELF_DATA ELFDATA2MSB
+//#define ELF_DATA ELFDATA2LSB
+#define ELF_ARCH EM_MIPS
diff --git a/tb_asm/sstrip/asm_elf_mipsel.h b/tb_asm/sstrip/asm_elf_mipsel.h
new file mode 100644
index 0000000..936e086
--- /dev/null
+++ b/tb_asm/sstrip/asm_elf_mipsel.h
@@ -0,0 +1,7 @@
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS ELFCLASS32
+//#define ELF_CLASS ELFCLASS64
+#define ELF_DATA ELFDATA2LSB
+#define ELF_ARCH EM_MIPS
diff --git a/tb_asm/sstrip/asm_elf_mn10300.h b/tb_asm/sstrip/asm_elf_mn10300.h
new file mode 100644
index 0000000..bcdc504
--- /dev/null
+++ b/tb_asm/sstrip/asm_elf_mn10300.h
@@ -0,0 +1,6 @@
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2LSB
+#define ELF_ARCH EM_MN10300
diff --git a/tb_asm/sstrip/asm_elf_parisc.h b/tb_asm/sstrip/asm_elf_parisc.h
new file mode 100644
index 0000000..2d84866
--- /dev/null
+++ b/tb_asm/sstrip/asm_elf_parisc.h
@@ -0,0 +1,8 @@
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_DATA ELFDATA2MSB
+#define ELF_ARCH EM_PARISC
+
+//#define ELF_CLASS ELFCLASS64
+#define ELF_CLASS ELFCLASS32
diff --git a/tb_asm/sstrip/asm_elf_ppc.h b/tb_asm/sstrip/asm_elf_ppc.h
new file mode 100644
index 0000000..f2fe3ad
--- /dev/null
+++ b/tb_asm/sstrip/asm_elf_ppc.h
@@ -0,0 +1,7 @@
+# define ELF_ARCH EM_PPC
+# define ELF_CLASS ELFCLASS32
+# define ELF_DATA ELFDATA2MSB
+
+//# define ELF_ARCH EM_PPC64
+//# define ELF_CLASS ELFCLASS64
+//# define ELF_DATA ELFDATA2MSB
diff --git a/tb_asm/sstrip/asm_elf_s390.h b/tb_asm/sstrip/asm_elf_s390.h
new file mode 100644
index 0000000..d3a5218
--- /dev/null
+++ b/tb_asm/sstrip/asm_elf_s390.h
@@ -0,0 +1,7 @@
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS ELFCLASS32
+//#define ELF_CLASS ELFCLASS64
+#define ELF_DATA ELFDATA2MSB
+#define ELF_ARCH EM_S390
diff --git a/tb_asm/sstrip/asm_elf_sh3.h b/tb_asm/sstrip/asm_elf_sh3.h
new file mode 100644
index 0000000..3c38330
--- /dev/null
+++ b/tb_asm/sstrip/asm_elf_sh3.h
@@ -0,0 +1,7 @@
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2LSB
+//#define ELF_DATA ELFDATA2MSB
+#define ELF_ARCH EM_SH
diff --git a/tb_asm/sstrip/asm_elf_sparc.h b/tb_asm/sstrip/asm_elf_sparc.h
new file mode 100644
index 0000000..4079fee
--- /dev/null
+++ b/tb_asm/sstrip/asm_elf_sparc.h
@@ -0,0 +1,6 @@
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_ARCH EM_SPARC
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2MSB
diff --git a/tb_asm/sstrip/asm_elf_sparc64.h b/tb_asm/sstrip/asm_elf_sparc64.h
new file mode 100644
index 0000000..4079fee
--- /dev/null
+++ b/tb_asm/sstrip/asm_elf_sparc64.h
@@ -0,0 +1,6 @@
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_ARCH EM_SPARC
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2MSB
diff --git a/tb_asm/sstrip/asm_elf_vax.h b/tb_asm/sstrip/asm_elf_vax.h
new file mode 100644
index 0000000..d373256
--- /dev/null
+++ b/tb_asm/sstrip/asm_elf_vax.h
@@ -0,0 +1,6 @@
+/* These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2LSB
+#define ELF_ARCH EM_VAX
+
diff --git a/tb_asm/sstrip/asm_elf_x86_64.h b/tb_asm/sstrip/asm_elf_x86_64.h
new file mode 100644
index 0000000..a3a16e7
--- /dev/null
+++ b/tb_asm/sstrip/asm_elf_x86_64.h
@@ -0,0 +1,6 @@
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS ELFCLASS64
+#define ELF_DATA ELFDATA2LSB
+#define ELF_ARCH EM_X86_64
diff --git a/tb_asm/sstrip/asm_elf_xtensa.h b/tb_asm/sstrip/asm_elf_xtensa.h
new file mode 100644
index 0000000..fd85aa3
--- /dev/null
+++ b/tb_asm/sstrip/asm_elf_xtensa.h
@@ -0,0 +1,8 @@
+/*
+ * These are used to set parameters in the core dumps.
+ */
+
+# define ELF_DATA ELFDATA2LSB
+//# define ELF_DATA ELFDATA2MSB
+#define ELF_CLASS ELFCLASS32
+#define ELF_ARCH EM_XTENSA
diff --git a/tb_asm/sstrip/sstrip.c b/tb_asm/sstrip/sstrip.c
new file mode 100644
index 0000000..6119640
--- /dev/null
+++ b/tb_asm/sstrip/sstrip.c
@@ -0,0 +1,498 @@
+/* sstrip: Copyright (C) 1999-2001 by Brian Raiter, under the GNU
+ * General Public License. No warranty. See COPYING for details.
+ * Various changes by Vince Weaver
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include ARCHITECTURE /* made local as new distros don't have it */
+
+#if ELF_CLASS == ELFCLASS32
+#define Elf_Ehdr Elf32_Ehdr
+#define Elf_Phdr Elf32_Phdr
+#else
+#define Elf_Ehdr Elf64_Ehdr
+#define Elf_Phdr Elf64_Phdr
+#endif
+
+/* Endianess of the host */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+static int little_endian=1;
+#else
+static int little_endian=0;
+#endif
+
+static int swap_bytes=0;
+
+/* The name of the program.
+ */
+static char const *progname;
+
+/* The name of the current file.
+ */
+static char const *filename;
+
+
+/* A simple error-handling function. 0 is always returned for the
+ * convenience of the caller.
+ */
+static int err(char const *errmsg)
+{
+ fprintf(stderr, "%s: %s: %s\n", progname, filename, errmsg);
+ return 0;
+}
+
+/* A macro for I/O errors: The given error message is used only when
+ * errno is not set.
+ */
+#define ferr(msg) (err(errno ? strerror(errno) : (msg)))
+
+/* readelfheader() reads the ELF header into our global variable, and
+ * checks to make sure that this is in fact a file that we should be
+ * munging.
+ */
+static int readelfheader(int fd, Elf_Ehdr *ehdr) {
+ errno = 0;
+ if (read(fd, ehdr, sizeof *ehdr) != sizeof *ehdr) {
+ return ferr("missing or incomplete ELF header.");
+ }
+
+ /* Check the ELF signature.
+ */
+ if (!(ehdr->e_ident[EI_MAG0] == ELFMAG0 &&
+ ehdr->e_ident[EI_MAG1] == ELFMAG1 &&
+ ehdr->e_ident[EI_MAG2] == ELFMAG2 &&
+ ehdr->e_ident[EI_MAG3] == ELFMAG3)) {
+ printf("missing ELF signature.");
+ exit(0);
+ }
+
+ /* Compare the file's class and endianness with the program's.
+ */
+
+ if (ELF_DATA == ELFDATA2LSB) { /* 2's complement, little endian */
+ if (!little_endian) {
+ fprintf(stderr,"Warning! Host and target endianess don't match!\n");
+ swap_bytes=1;
+ }
+ }
+ else if (ELF_DATA == ELFDATA2MSB) { /* 2's complement, big endian */
+ if (little_endian) {
+ fprintf(stderr,"Warning! Host and target endianess don't match!\n");
+ swap_bytes=1;
+ }
+ }
+ else {
+ err("Unknown endianess type.");
+ }
+
+ if (ELF_CLASS == ELFCLASS64) {
+ if (sizeof(void *)!=8) err("host!=elf word size not supported");
+ }
+ else if (ELF_CLASS == ELFCLASS32) {
+ if (sizeof(void *)!=4) err("host!=elf word size not supported");
+ }
+ else {
+ err("Unknown word size");
+ }
+
+ if (ehdr->e_ident[EI_DATA] != ELF_DATA) {
+ err("ELF file has different endianness.");
+ }
+
+ if (ehdr->e_ident[EI_CLASS] != ELF_CLASS) {
+ err("ELF file has different word size.");
+ }
+
+ /* Check the target architecture.
+ */
+ { unsigned short machine;
+ machine=ehdr->e_machine;
+ if (swap_bytes) machine=bswap_16(machine);
+
+ if (machine != ELF_ARCH) {
+ fprintf(stderr, "Warning! "
+ "ELF file created for different architecture: %d\n",
+ ehdr->e_machine);
+ }
+ }
+
+ /* Verify the sizes of the ELF header and the program segment
+ * header table entries.
+ */
+ { short ehsize;
+ ehsize=ehdr->e_ehsize;
+ if (swap_bytes) ehsize=bswap_16(ehsize);
+
+ if (ehsize != sizeof(Elf_Ehdr)) {
+ fprintf(stderr,"Warning! "
+ "unrecognized ELF header size: %d != %ld\n",
+ ehdr->e_ehsize,(long)sizeof(Elf_Ehdr));
+ }
+ }
+
+ {
+ short phentsize;
+ phentsize=ehdr->e_phentsize;
+ if (swap_bytes) phentsize=bswap_16(phentsize);
+
+ if (phentsize != sizeof(Elf_Phdr)) {
+ fprintf(stderr,"Warning! "
+ "unrecognized program segment header size: %d != %ld\n",
+ ehdr->e_phentsize,(long)sizeof(Elf_Phdr));
+ }
+ }
+
+ /* Finally, check the file type.
+ */
+ {short e_type;
+ e_type=ehdr->e_type;
+ if (swap_bytes) e_type=bswap_16(e_type);
+
+ if (e_type != ET_EXEC && e_type != ET_DYN) {
+ return err("not an executable or shared-object library.");
+ }
+ }
+
+ return 1;
+}
+
+/* readphdrtable() loads the program segment header table into memory.
+ */
+static int readphdrtable(int fd, Elf_Ehdr const *ehdr, Elf_Phdr **phdrs) {
+
+ size_t size;
+
+ short e_phnum;
+
+ /* should be endian safe, as zero is the same in all endianesses */
+ if (!ehdr->e_phoff || !ehdr->e_phnum) {
+ return err("ELF file has no program header table.");
+ }
+
+ e_phnum=ehdr->e_phnum;
+ if (swap_bytes) e_phnum=bswap_16(e_phnum);
+
+ size = e_phnum * sizeof **phdrs;
+
+ if (!(*phdrs = malloc(size))) {
+ return err("Out of memory!");
+ }
+
+ errno = 0;
+
+ if (read(fd, *phdrs, size) != (ssize_t)size) {
+ return ferr("missing or incomplete program segment header table.");
+ }
+
+ return 1;
+}
+
+/* getmemorysize() determines the offset of the last byte of the file
+ * that is referenced by an entry in the program segment header table.
+ * (Anything in the file after that point is not used when the program
+ * is executing, and thus can be safely discarded.)
+ */
+static int getmemorysize(Elf_Ehdr const *ehdr, Elf_Phdr *phdrs,
+ unsigned long *newsize)
+{
+ Elf_Phdr *phdr;
+ unsigned long size, n ,end=0;
+ int i;
+
+ unsigned long e_phoff;
+ short e_phnum;
+
+ unsigned long p_offset,p_filesz;
+
+ e_phoff=ehdr->e_phoff;
+
+#if (ELF_CLASS==ELFCLASS64)
+ if (swap_bytes) e_phoff=bswap_64(e_phoff);
+#else
+ if (swap_bytes) e_phoff=bswap_32(e_phoff);
+#endif
+
+ e_phnum=ehdr->e_phnum;
+ if (swap_bytes) e_phnum=bswap_16(e_phnum);
+
+ /* Start by setting the size to include the ELF header and the
+ * complete program segment header table.
+ */
+ size = e_phoff + e_phnum * sizeof *phdrs;
+
+ if (size < sizeof *ehdr) {
+ size = sizeof *ehdr;
+ printf("-> Adjusting that to %ld\n",size);
+ }
+
+ /* Then keep extending the size to include whatever data the
+ * program segment header table references.
+ */
+ for (i = 0, phdr = phdrs ; i < e_phnum ; ++i, ++phdr) {
+ /* endian safe as PT_NULL is zero */
+ if (phdr->p_type != PT_NULL) {
+
+ p_offset=phdr->p_offset;
+ p_filesz=phdr->p_filesz;
+#if (ELF_CLASS==ELFCLASS64)
+ if (swap_bytes) {
+ p_offset=bswap_64(p_offset);
+ p_filesz=bswap_64(p_filesz);
+ }
+#else
+ if (swap_bytes) {
+ p_offset=bswap_32(p_offset);
+ p_filesz=bswap_32(p_filesz);
+ }
+#endif
+
+ n = p_offset + p_filesz;
+ if (n > size)
+ size = n;
+ end=size;
+ }
+ }
+
+ *newsize = size;
+ return 1;
+}
+
+/* truncatezeros() examines the bytes at the end of the file's
+ * size-to-be, and reduces the size to exclude any trailing zero
+ * bytes.
+ */
+static int truncatezeros(int fd, unsigned long *newsize)
+{
+ unsigned char contents[1024];
+ unsigned long size, n;
+
+ size = *newsize;
+ do {
+ n = sizeof contents;
+ if (n > size)
+ n = size;
+ if (lseek(fd, size - n, SEEK_SET) == (off_t)-1)
+ return ferr("cannot seek in file.");
+ if (read(fd, contents, n) != (ssize_t)n)
+ return ferr("cannot read file contents");
+ while (n && !contents[--n])
+ --size;
+ } while (size && !n);
+
+ /* Sanity check.
+ */
+ if (!size)
+ return err("ELF file is completely blank!");
+
+ *newsize = size;
+ return 1;
+}
+
+/* modifyheaders() removes references to the section header table if
+ * it was stripped, and reduces program header table entries that
+ * included truncated bytes at the end of the file.
+ */
+static int modifyheaders(Elf_Ehdr *ehdr, Elf_Phdr *phdrs,
+ unsigned long newsize)
+{
+ Elf_Phdr *phdr;
+ int i;
+
+ unsigned long e_shoff;
+ short e_phnum;
+ unsigned long p_offset,p_filesz;
+
+ e_shoff=ehdr->e_shoff;
+#if (ELF_CLASS==ELFCLASS64)
+ if (swap_bytes) {
+ e_shoff=bswap_64(e_shoff);
+ }
+#else
+ if (swap_bytes) {
+ e_shoff=bswap_32(e_shoff);
+ }
+#endif
+
+ e_phnum=ehdr->e_phnum;
+ if (swap_bytes) e_phnum=bswap_16(e_phnum);
+
+
+ /* If the section header table is gone, then remove all references
+ * to it in the ELF header.
+ */
+ if (e_shoff >= newsize) {
+ ehdr->e_shoff = 0; /* all OK because 0 is endian neutral */
+ ehdr->e_shnum = 0;
+ ehdr->e_shentsize = 0;
+ ehdr->e_shstrndx = 0;
+ }
+
+ /* The program adjusts the file size of any segment that was
+ * truncated. The case of a segment being completely stripped out
+ * is handled separately.
+ */
+ for (i = 0, phdr = phdrs ; i < e_phnum ; ++i, ++phdr) {
+
+ p_offset=phdr->p_offset;
+ p_filesz=phdr->p_filesz;
+#if (ELF_CLASS==ELFCLASS64)
+ if (swap_bytes) {
+ p_offset=bswap_64(p_offset);
+ p_filesz=bswap_64(p_filesz);
+ }
+#else
+ if (swap_bytes) {
+ p_offset=bswap_32(p_offset);
+ p_filesz=bswap_32(p_filesz);
+ }
+#endif
+
+ if (p_offset >= newsize) {
+ p_offset = newsize;
+#if (ELF_CLASS==ELFCLASS64)
+ if (swap_bytes) {
+ phdr->p_offset=bswap_64(p_offset);
+ }
+#else
+ if (swap_bytes) {
+ phdr->p_offset=bswap_32(p_offset);
+ }
+#endif
+ phdr->p_filesz = 0;
+ } else if (p_offset + p_filesz > newsize) {
+ p_filesz = newsize - p_offset;
+#if (ELF_CLASS==ELFCLASS64)
+ if (swap_bytes) {
+ phdr->p_filesz=bswap_64(p_filesz);
+ }
+#else
+ if (swap_bytes) {
+ phdr->p_filesz=bswap_32(p_filesz);
+ }
+#endif
+
+ }
+ }
+
+ return 1;
+}
+
+/* commitchanges() writes the new headers back to the original file
+ * and sets the file to its new size.
+ */
+static int commitchanges(int fd, Elf_Ehdr const *ehdr, Elf_Phdr *phdrs,
+ unsigned long newsize)
+{
+ size_t n;
+ unsigned long e_phoff;
+ short e_phnum;
+
+ e_phnum=ehdr->e_phnum;
+ if (swap_bytes) e_phnum=bswap_16(e_phnum);
+
+ e_phoff=ehdr->e_phoff;
+#if (ELF_CLASS==ELFCLASS64)
+ if (swap_bytes) {
+ e_phoff=bswap_64(e_phoff);
+ }
+#else
+ if (swap_bytes) {
+ e_phoff=bswap_32(e_phoff);
+ }
+#endif
+
+
+ /* Save the changes to the ELF header, if any.
+ */
+ if (lseek(fd, 0, SEEK_SET))
+ return ferr("could not rewind file");
+ errno = 0;
+ if (write(fd, ehdr, sizeof *ehdr) != sizeof *ehdr)
+ return err("could not modify file");
+
+ /* Save the changes to the program segment header table, if any.
+ */
+ if (lseek(fd, e_phoff, SEEK_SET) == (off_t)-1) {
+ err("could not seek in file.");
+ goto warning;
+ }
+ n = e_phnum * sizeof *phdrs;
+ if (write(fd, phdrs, n) != (ssize_t)n) {
+ err("could not write to file");
+ goto warning;
+ }
+
+ /* Eleventh-hour sanity check: don't truncate before the end of
+ * the program segment header table.
+ */
+ if (newsize < e_phoff + n)
+ newsize = e_phoff + n;
+
+ /* Chop off the end of the file.
+ */
+ if (ftruncate(fd, newsize)) {
+ err("could not resize file");
+ goto warning;
+ }
+
+ return 1;
+
+ warning:
+ return err("ELF file may have been corrupted!");
+}
+
+/* main() loops over the cmdline arguments, leaving all the real work
+ * to the other functions.
+ */
+int main(int argc, char *argv[]) {
+
+ int fd;
+ Elf_Ehdr ehdr;
+ Elf_Phdr *phdrs;
+ unsigned long newsize;
+ char **arg;
+ int failures = 0;
+
+ if (argc < 2 || argv[1][0] == '-') {
+ printf("Usage: sstrip FILE...\n"
+ "sstrip discards all nonessential bytes from an executable.\n\n"
+ "Version 2.0 Copyright (C) 2000,2001 Brian Raiter.\n"
+ "This program is free software, licensed under the GNU\n"
+ "General Public License. There is absolutely no warranty.\n");
+ return EXIT_SUCCESS;
+ }
+
+ progname = argv[0];
+
+ for (arg = argv + 1 ; *arg != NULL ; ++arg) {
+
+ filename = *arg;
+
+ fd = open(*arg, O_RDWR);
+ if (fd < 0) {
+ ferr("can't open");
+ ++failures;
+ continue;
+ }
+
+ if (!(readelfheader(fd, &ehdr) &&
+ readphdrtable(fd, &ehdr, &phdrs) &&
+ getmemorysize(&ehdr, phdrs, &newsize) &&
+ truncatezeros(fd, &newsize) &&
+ modifyheaders(&ehdr, phdrs, newsize) &&
+ commitchanges(fd, &ehdr, phdrs, newsize)))
+ ++failures;
+
+ close(fd);
+ }
+
+ return failures ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/tb_asm/tb_asm.ix86.s b/tb_asm/tb_asm.ix86.s
new file mode 100644
index 0000000..fbebf75
--- /dev/null
+++ b/tb_asm/tb_asm.ix86.s
@@ -0,0 +1,3543 @@
+# Tom Bombem in x86 Assmbler version 0.32
+#
+# by Vince Weaver
+#
+# assemble with "as -o tb_asm.o tb_asm.ix86.s"
+# link with "ld -o tb_asm tb_asm.o"
+
+
+# GAME CONSTANTS
+
+.equ SCREEN_WIDTH, 40
+.equ SCREEN_HEIGHT, 24
+.equ BYTES_PER_PIXEL, 2
+.equ NUM_MISSILES, 2
+.equ NUM_ENEMIES, 6
+.equ SCROLL_SPEED, 2
+.equ UP_SHIELDS, 32
+.equ WAVE_SIZE, 16 # power of 2
+.equ WAVES_TILL_BOSS, 6 # plus level*2
+
+ # from ~/linux/include/asm/unistd.h
+.equ SYSCALL_READ, 3
+.equ SYSCALL_WRITE, 4
+.equ SYSCALL_OPEN, 5
+.equ SYSCALL_CLOSE, 6
+.equ SYSCALL_IOCTL, 54
+.equ SYSCALL_FCNTL, 55
+.equ SYSCALL_GETTIMEOFDAY, 78
+.equ SYSCALL_NANOSLEEP, 162
+
+ # from ~/linux/include/asm/ioctls.h
+.equ TCGETS, 0x5401
+.equ TCSETS, 0x5402
+
+ # from ~/linux/include/asm/fcntl.h
+.equ F_GETFL, 3
+.equ F_SETFL, 4
+.equ O_NONBLOCK, 0x0800
+.equ O_RDONLY, 0x000
+.equ O_WRONLY, 0x001
+.equ O_CREAT, 0x040
+.equ O_TRUNC, 0x200
+.equ SIXSIXSIX, 0666
+
+
+
+ # from ~/linux/include/asm/termbits.h
+.equ C_LFLAG_OFF, 12
+.equ VMIN_OFF, 23
+.equ ICANON, 2
+.equ ECHO, 8
+
+ # struct offsets
+.equ ENEMIES_OUT, 0
+.equ ENEMIES_EXPLODING, 1
+.equ ENEMIES_XADD, 2
+.equ ENEMIES_YADD, 3
+.equ ENEMIES_XMIN, 4
+.equ ENEMIES_XMAX, 5
+.equ ENEMIES_KIND, 6
+.equ ENEMIES_X, 7
+.equ ENEMIES_Y, 9
+.equ ENEMIES_SIZE, 11
+
+.equ MISSILE_OUT, 0
+.equ MISSILE_X, 1
+.equ MISSILE_Y, 2
+
+
+ # game_flags bit
+.equ PAUSED, 0x01
+.equ SOUND, 0x02
+.equ SOUND_PENDING, 0x04
+.equ PERFECT_SHIELD, 0x08
+.equ PERFECT_ENEMY, 0x10
+.equ PERFECT_SHOT, 0x20
+.equ ALL_THREE, PERFECT_SHIELD|PERFECT_ENEMY|PERFECT_SHOT
+
+.include "data.header"
+
+ .globl _start
+_start:
+
+ #####################################
+ # decompress data segment
+
+# LZSS decompression algorithm implementation
+# by Stephan Walter 2002, based on LZSS.C by Haruhiko Okumura 1989
+# optimized some more by Vince Weaver
+
+ # we used to fill the buffer with FREQUENT_CHAR
+ # but, that only gains us one byte of space in the lzss image.
+ # the lzss algorithm does automatic RLE... pretty clever
+ # so we compress with NUL as FREQUENT_CHAR and it is pre-done for us
+
+
+ mov $(N-F), %bp # R
+ mov $tb_data_begin, %esi # %esi points to logo (for lodsb)
+ mov $DATA_OFFSET, %edi # point to out_buffer
+
+decompression_loop:
+ lodsb # load in a byte
+
+ mov $0xff, %bh # re-load top as a hackish 8-bit counter
+ mov %al, %bl # move in the flags
+
+test_flags:
+ cmp $tb_data_end, %esi # have we reached the end?
+ jge done_decompress # if so, exit
+
+ shr $1, %ebx # shift bottom bit into carry flag
+ jc discreet_char # if set, we jump to discreet char
+
+offset_length:
+ lodsw # get match_length and match_position
+ mov %eax,%edx # copy to edx
+ # no need to mask dx, as we do it
+ # by default in output_loop
+
+ shr $(P_BITS),%eax
+ add $(THRESHOLD+1),%al
+
+ mov %al,%cl # cl = (ax >> P_BITS) + THRESHOLD + 1
+ # (=match_length)
+
+output_loop:
+ and $POSITION_MASK,%dh # mask it
+ mov text_buf(%edx), %al # load byte from text_buf[]
+ inc %edx # advance pointer in text_buf
+store_byte:
+ stosb # store it
+
+ mov %al, text_buf(%ebp) # store also to text_buf[r]
+ inc %ebp # r++
+ and $(N-1), %bp # mask r
+
+ loop output_loop # repeat until k>j
+
+ or %bh,%bh # if 0 we shifted through 8 and must
+ jnz test_flags # re-load flags
+
+ jmp decompression_loop
+
+discreet_char:
+ lodsb # load a byte
+ inc %ecx # we set ecx to one so byte
+ # will be output once
+ # (how do we know ecx is zero?)
+
+ jmp store_byte # and cleverly store it
+
+done_decompress:
+# end of LZSS code
+
+
+ #####################################
+ # setup non-echo mode
+ #
+
+ # ioctl(0,TCGETS,&old_tty)
+ # AKA tcgetattr(0,&old_tty);
+
+ mov $old_tty,%edx # save values to retstore at end
+ call tcgetattr
+
+ mov $new_tty,%edx # get values to modify
+ call tcgetattr
+
+ # turn off "canonical mode"
+ # by clearing ICANON bit
+ # new_tty.c_lflag&=~ICANON;
+
+ andl $(~ICANON),(new_tty+C_LFLAG_OFF)
+
+ # turn off "echo mode"
+ # by clearing ECHO bit
+ # new_tty.c_lflag&=~ECHO;
+
+ andl $(~ECHO),(new_tty+C_LFLAG_OFF)
+
+ # set minimum number of characters
+ # to read as 1
+ # new_tty.c_cc[VMIN]=1;
+
+ movb $1,(new_tty+VMIN_OFF)
+
+ # apply our new tty values
+ call tcsetattr # %edx still points to new_tty
+
+
+ ##################################
+ # make stdin non-blocking
+ #
+ # use fctl rather than fctl64
+ push $SYSCALL_FCNTL # for compatibility (no need of 2GB)
+ pop %eax
+ xor %ebx,%ebx # stdin = 0
+ push $F_GETFL # we want to get flags
+ pop %ecx
+ int $0x80
+
+ mov %eax,%edx # copy result of GETFL to edx
+ orw $O_NONBLOCK,%dx # set the NONBLOCK bit
+
+ push $SYSCALL_FCNTL
+ pop %eax # use fctl again
+ xor %ebx,%ebx # stdin = 0
+ push $F_SETFL # want to set flags this time
+ pop %ecx
+ int $0x80
+
+ ###############################
+ # clear the framebuffer
+
+ call clear_framebuffer
+
+ ###############################
+ # clear the screen
+
+ mov $clear_screen,%ecx # send the escape code to clear screen
+ call write_stdout
+
+ ##############################
+ # draw VMW logo
+
+ mov $vmw_sprite,%esi # Load in sprite
+ mov $((0x8<<8)+0x6),%ax # Load in x and y co-ords
+ call blit_219
+
+ # put "A VMW Software Production"
+ # white, x=7, y=15
+ mov $vmw_string,%esi
+ call put_text_line_inline
+
+ call dump_to_screen # dump framebuffer to screen
+
+ push $3
+ pop %ecx # Pause 3 seconds
+ call pause_a_while
+
+ ################################
+ # Main Menu Loop
+
+opening_screen:
+
+ ###############################
+ # clear the framebuffer
+
+ call clear_framebuffer
+
+ ##############################
+ # title screen
+
+ mov $opener_sprite,%esi # load the title sprite
+ xor %eax,%eax # at 0,0
+ call blit_219
+ # Yellow, title_string,x=0 y=5
+ mov $title_string,%esi # Malicious Marketers
+ call put_text_line_inline
+
+ call dump_to_screen # copy to screen
+
+ #########################
+ # pause for 10 seconds
+ # or less if key pressed
+
+ push $10
+ pop %ecx
+ call pause_a_while
+
+ #########################
+ # set variables
+
+ xor %ebp,%ebp # menu-item=0
+
+ #########################
+ # draw attention block
+ #
+
+ xor %bl,%bl # color = 0
+ call put_attention_block
+
+ ####################################
+ # put the "press F1 for help" string
+
+ mov $menu_help_string,%esi # color grey x=0 y=20
+ call put_text_line_inline
+
+ ####################################
+ # draw the menu
+
+ mov $((5<<16)+(10<<8)+6),%eax # x=10 y=6
+ call do_menu
+
+ cmp $0,%bp
+ jne check_1
+ call new_game
+ jmp opening_screen
+check_1:
+ cmp $1,%bp
+ jne check_2
+ call do_about
+check_2:
+ cmp $2,%bp
+ jne check_3
+ call do_story
+ jmp opening_screen
+check_3:
+ cmp $3,%bp
+ jne check_4
+ call do_hi_score
+ call wait_until_keypressed
+
+check_4:
+ cmp $4,%bp
+ jne check_5
+ call verify_quit
+ jnz exit
+ jmp opening_screen
+check_5:
+ cmp $5,%bp
+ jne end_handle_lf
+ call display_help
+
+end_handle_lf:
+ jmp opening_screen
+
+
+ #################################
+ # Exit
+ #################################
+exit:
+
+ mov $default_colors,%ecx # restore from line-draw mode
+ call write_stdout
+
+ andb $(~SOUND),game_flags # turn sound off
+ mov $(750<<16)+125,%ebx # default sound=750Hz 125ms
+ call play_sound # No way I know of to save/restore
+ # actual values
+
+ mov $old_tty,%edx # restore the saved tty values
+ call tcsetattr
+
+ xor %ebx,%ebx # set return value as zero
+ xor %eax,%eax
+ inc %eax # put exit syscall number (1) in eax
+ int $0x80 # and exit
+
+
+
+ #################################
+ # verify quit
+ #################################
+ # zero flag clear if we do want to quit
+verify_quit:
+
+ mov $15,%bl
+ call put_attention_block # put a white attention block
+
+ mov $quit_line,%esi
+ call put_text_line_inline # put the text
+
+ xor %ebp,%ebp
+ mov $(5<<24)+(2<<16)+(9<<8)+8,%eax
+ # offset 5, 2 lines
+ # at 9,8
+
+ # slide into do_menu
+
+
+ #########################
+ # Do menu
+ #########################
+ # ax= x,y dx=label_offset,num_options
+ # returns %bp=option
+ # destroys %ecx
+do_menu:
+ push %eax
+
+write_menu_loop:
+ xor %ecx,%ecx # clear line counter
+ pop %eax # restore x,y,label_offset,num_options
+ push %eax
+
+do_menu_loop:
+ mov %eax,%edx
+ ror $16,%edx # move label_offset,num_options -> dx
+
+ cmp %ecx,%ebp # are we the selected menu?
+ jne menu_no_arrow # if not, no_arrow
+
+ mov $menu_arrow,%esi # if so, arrow
+ mov $13,%bh # set text color pink
+
+ jmp write_menu_text
+
+menu_no_arrow:
+ mov $menu_blank,%esi # not selected, so blank
+ mov $5,%bh # set text color purple
+
+write_menu_text:
+ mov $14,%bl # yellow arrow
+ call put_text_xy # write out the arrow or blank
+
+ mov %bh,%bl # swap in text color
+
+ # point to the proper string
+
+ add %dh,%cl
+ lea menu_new_string(%ecx,%ecx,8),%esi
+ sub %dh,%cl
+
+ add $5,%ah # text 5 right of arrow
+
+ call put_text_xy # put the text
+
+ inc %al # increment y
+ sub $5,%ah # restore x
+ inc %ecx # increment the count
+
+ cmp %dl,%cl # have we shown them all?
+ jne do_menu_loop # if not, loop
+
+ call dump_to_screen # dump results to screen
+
+menu_key_loop:
+ call get_a_char # get a character
+ jnc menu_check_key # if valid key, check it
+ call milisec_nanosleep
+ jmp menu_key_loop
+
+menu_check_key:
+ pop %edx # convoluted way
+ push %edx # to get num_options into %dl
+ shr $16,%edx
+ xor %dh,%dh
+
+check_q:
+ cmp $'q',%al # are we 'q'?
+ jne check_h
+ mov %dx,%bp # if so move to last menu item
+ dec %bp
+check_h:
+ cmp $'h',%al # are we 'h'?
+ jne check_i
+ mov $5,%bp # if so move beyond and
+ mov $'\n',%al # trigger enter
+
+check_i:
+ cmp $'i',%al # are we up?
+ jne check_m
+dec_menu:
+ sub $1,%bp
+ jns write_menu_loop # if not, ok
+ mov %dx,%bp # if so, wrap
+ dec %bp
+ jmp write_menu_loop
+
+check_m:
+ cmp $'m',%al # are we down?
+ jne check_j
+inc_menu:
+ inc %bp # move down
+ cmp %dx,%bp # are we too far?
+ jne write_menu_loop # if not ok
+ xor %bp,%bp # if so, wrap
+ jmp write_menu_loop
+
+check_j:
+ cmp $'j',%al # are we right?
+ je dec_menu # then pretend we are down
+
+check_k:
+ cmp $'k',%al # are we left?
+ je inc_menu # then pretend we are up
+
+check_LF:
+ cmp $'\n',%al # check for enter/space
+ je exit_menu
+ cmp $'\r',%al
+ je exit_menu
+ cmp $' ',%al
+ je exit_menu
+
+ jmp write_menu_loop # unknown key, loop
+
+exit_menu:
+ pop %eax # clean up stack
+ xor $0,%ebp # set zero flag with result
+
+ ret
+
+
+
+
+
+ ######################
+ # NEW GAME
+ ######################
+ #
+
+new_game:
+
+ # re-clear all bss variables to zero
+
+ xor %eax,%eax
+ mov $(game_vars),%edi
+ mov $(end_game_vars-game_vars),%ecx
+
+ rep
+ stosb
+
+ call load_hi_score # load hi_score
+
+ ###########################
+ # init vars that need to be initialized
+
+ movw $(18<<8),x # ship's x=18
+ movb $8,shields # shields start as 8
+ movb $1,level # level starts as 1
+
+ ##########################
+ # Starting a new level!
+
+new_level:
+ call clear_framebuffer # clear screen
+
+ mov $8,%bl
+ call put_attention_block # put attention block
+
+ mov $menu_blank,%esi
+ mov $15,%bl
+ mov $8,%al
+ mov %bl,%ah
+ call put_text_xy
+ mov $menu_blank,%esi
+ mov $20,%ah
+ call put_text_xy # clear an opening
+
+
+ mov $level_line+3,%esi
+ mov $16,%ah
+ call put_text_xy # print "LEVEL:"
+
+ xor %eax,%eax
+ movb level,%al # Convert level to ascii
+ mov $level_string,%edi
+ call num_to_ascii
+
+ mov $level_string,%esi # print level_string
+ mov $((23<<8)+8),%eax
+ mov $15,%bl
+ call put_text_xy
+
+ call dump_to_screen
+
+ push $2 # Pause 2 seconds or until keypress
+ pop %ecx
+ call pause_a_while
+
+ ##############################
+ # set new_level variables
+ # hackish but decreses code size
+
+ mov $enemies_spawned,%edi
+ xor %eax,%eax
+ inc %eax # eax = 1
+ stosw # enemies_spawned = 1
+ neg %ax # ax=-1
+ stosw # current_init_x = -1
+ stosb # current_enemy_kind = -1
+ push $30
+ pop %eax # al=30
+ stosb # enemy_wait=30
+ xor %eax,%eax # al=0
+
+# add $6,%al
+
+ stosb # current_enemy_type=0
+
+# xor %eax,%eax
+ stosb # enemy_wave=0
+
+ orb $ALL_THREE,game_flags # set the three bonuses to ON
+
+ movb level,%al # mave waves_till_boss
+ add %al,%al # equal WAVES_TILL_BOSS + 2*level
+ addb $WAVES_TILL_BOSS,%al
+ mov %al,waves_till_boss
+
+ ########################
+ # RANDOMIZE TIMER
+
+ call randomize_timer
+
+ # Draw the Stars
+
+ xor %eax,%eax # clear eax
+
+ mov $1600,%ecx # clear the background
+ mov $background,%edi
+ push %edi
+ rep
+ stosb
+
+ mov $100,%ecx # we want to draw 100 stars
+draw_stars:
+ pop %edi # point to "background"
+ push %edi
+ push $40
+ pop %ebx # move 40 into bx
+ call random # call rand()%40 (y)
+ imulb %bl # multiply result by 40 (screen width)
+ add %eax,%edi # add to background pointer
+
+ call random # call rand()%40 again (x)
+ add %eax,%edi # add this to background pointer
+
+ push $2
+ pop %ebx # call rand()%2
+ call random
+
+ add $7,%al # put either light or dark grey star
+
+ stosb # and store it
+
+ loop draw_stars # loop
+ pop %edi
+
+main_game_loop:
+
+ ############
+ # clear screen
+ ############
+
+ call clear_framebuffer # clear the screen
+
+ ###########
+ # Scroll the Stars
+ ###########
+
+ mov scroll_frames,%bx # get scroll val from memory
+ mov scroll,%ax # get scroll value
+ inc %bx # increment frames
+ cmp $SCROLL_SPEED,%bx # have we had enough frames to scroll?
+ jge scroll_it # if so move ahead
+ mov %bx,scroll_frames # else store scroll back
+ jmp show_stars # and jump to the stars
+
+scroll_it:
+ movw $0,scroll_frames # clear scroll_frames
+
+ sub $40,%ax # decrement it
+ jns write_scroll # is it less than zero?
+ mov $(40*40-40),%ax # if so wrap to (40*40-40)
+write_scroll:
+ movw %ax,scroll # store new scroll value to RAM
+
+show_stars:
+ mov $background,%esi # background as src
+ mov $40,%bl # 40 wide
+ mov $'.',%dl # stars are dots
+
+ cmp $(20*40),%ax # do we have to wrap?
+ jg half_scroll # if so we need 2 blits
+
+ #########
+ # plain 40x20 blit
+
+ add %eax,%esi # else just offset into background
+ xor %eax,%eax # put at 0,0
+ mov $20,%dh # 20 high
+
+ call blit_already_know_xsize_ysize
+ jmp done_scrolling # done putting stars
+
+half_scroll:
+
+ ##############
+ # top half of wrap blit
+
+ add %eax,%esi # offset into background
+ idiv %bl # divide offset by 40 to get scroll
+
+ push %eax # store this offset
+
+ # scroll=%al
+ # we want x=0,y=0
+ # we want xsize=40,ysize=40-scroll
+ # we want framebuffer=background+40*scroll
+
+ mov $40,%dh
+ sub %al,%dh # ysize=40-scroll
+
+ xor %eax,%eax # x=0,y=0
+
+ call blit_already_know_xsize_ysize
+
+ ################
+ # bottom half of wrap bit
+
+ mov $background,%esi # start at top of background
+ pop %eax # restore scroll value
+
+ # scroll=%al
+ # we want y=40-scroll
+ # we want ysize=scroll-20
+
+ mov %al,%dh
+ sub $20,%dh # ysize=scroll-20
+
+ neg %al
+ add $40,%al # y=40-scroll
+ xor %ah,%ah # x=0
+
+ call blit_already_know_xsize_ysize
+
+
+done_scrolling:
+
+ #############
+ # Put out new enemies
+ #############
+
+ #################################################
+ # Keep a count of how close to place enemies
+ # Don't want all to appear at once
+
+ incb between_enemy_delay # between_enemy_delay++
+ movb enemy_wait,%al # get time to wait
+ cmp %al,between_enemy_delay # is delay>wait?
+ jne move_enemies # if not, no enemies this frame
+
+ movb $0,between_enemy_delay # reset between_enemy_delay
+
+ ###########################
+ # See if we want to change the current enemy type
+
+ cmpb $7,current_enemy_type
+ jne not_boss
+ movw $1,enemies_spawned # don't keep enemy count w boss
+not_boss:
+
+ # each wave is WAVE_SIZE-1. Should we make this random?
+
+ mov enemies_spawned,%ax
+ test $(WAVE_SIZE-1),%al # See if multiple of 16
+ jnz same_enemy_type
+
+
+ ###############################
+ # CHANGE THE ENEMY TYPE
+
+ incw enemies_spawned # if we keep at multiple of 16
+ # we have problems if enemy
+ # not output right away. so inc
+
+ push $6
+ pop %ebx
+ call random
+ mov %al,current_enemy_type # current_enemy_type=rand()%6
+
+ incb enemy_wave # increment which wave we are on
+
+ movb waves_till_boss,%al
+ cmpb %al,enemy_wave # have we reached boss yet?
+ jl not_boss_yet # if not, no boss yet
+
+ movb $6,current_enemy_type # if so, set type to prepare_for_boss
+
+not_boss_yet:
+
+ #####################################
+ # Set some constants
+ # These can be over-ridden later?
+
+set_enemy_constants:
+
+ #################
+ # issue speed
+
+ mov $25,%ah # enemy wait standard is 25
+
+ mov level,%al
+ dec %al # 1 -> 0 for better math
+ shl $3,%al
+ sub %al,%ah # adjust for level
+
+ cmp $5,current_enemy_type
+ jne check_wait_underflow
+ sub $10,%ah
+check_wait_underflow:
+ cmp $0,%ah
+ jge write_out_enemy_wait
+ xor %ah,%ah
+
+write_out_enemy_wait:
+ movb %ah,enemy_wait
+
+
+ movb $-1,current_enemy_kind
+ movw $-1,current_init_x
+
+same_enemy_type:
+
+ #############################
+ # Find an empty enemy slot
+
+ mov $enemy_0,%ebp # point to first enemy
+ push $NUM_ENEMIES
+ pop %ecx # loop through all enemies
+
+find_enemy_slot:
+ mov %ebp,%esi
+ lodsb # get enemy[i].out
+ test $1,%al # is the enemy out?
+ jz add_enemy # if not keep going
+
+ add $ENEMIES_SIZE,%ebp # move to next enemy struct
+ loop find_enemy_slot # and loop
+
+ jmp move_enemies
+
+add_enemy:
+
+ ##################
+ # first see if need to wait till all enemies gone
+ # (types 2 and 6 do this)
+
+ cmpb $2,current_enemy_type
+ jne check_type_6
+
+ movb total_enemies_out,%al # are total enemies_out >0?
+ cmp $0,%al
+ jne move_enemies # if so, wait longer
+
+
+ movb $3,current_enemy_type # all gone, so move on to type 3
+
+ push $6
+ pop %ebx
+ call random
+ mov %al,current_enemy_kind # current_enemy_kind=rand()%6;
+
+ push $36
+ pop %ebx
+ call random
+ mov %al,%ah # ah is the significant part
+ mov %ax,current_init_x # current_init_x=rand()%36
+ jmp setup_enemy_defaults
+
+check_type_6:
+ cmpb $6,current_enemy_type
+ jne check_type_7
+
+ ################
+ # before boss stuff
+
+ movb total_enemies_out,%al # are total enemies_out >0?
+ cmp $0,%al
+ jne move_enemies # if so, wait longer
+
+ mov $9,%bl
+ call put_attention_block # put up a text_box
+
+ mov $bonus_points_line,%esi # print bonus point title
+ call put_text_line_inline
+
+ testb $(ALL_THREE),game_flags # see if we have a bonus
+ jz no_bonus_at_all
+
+ testb $(PERFECT_SHIELD),game_flags # do we have perfect shields?
+ jz no_pshield_bonus
+
+ mov $no_shield_line,%esi # if so print message
+ call put_text_line_inline
+ addl $1000,score # add 1000 to score
+
+no_pshield_bonus:
+
+ testb $(PERFECT_ENEMY),game_flags # did we kill all enemies?
+ jz no_penemy_bonus
+
+ mov $shot_every_line,%esi # if so print message
+ call put_text_line_inline
+ addl $5000,score # add 5000 to score
+
+no_penemy_bonus:
+
+ testb $(PERFECT_SHOT),game_flags # did we never miss a shot?
+ jz no_pshot_bonus
+
+ mov $perfect_shot_line,%esi # if so, print message
+ call put_text_line_inline
+ addl $5000,score # add 5000 to score
+
+no_pshot_bonus:
+ jmp done_showing_bonus
+
+no_bonus_at_all:
+ mov $no_bonus_line,%esi # print no bonus message
+ call put_text_line_inline
+
+done_showing_bonus:
+ call dump_to_screen
+
+ call wait_long_time
+ call wait_until_keypressed
+
+ #################
+ # setup boss
+
+ mov $boss_x,%edi
+ xor %eax,%eax
+ mov $13,%ah
+ stosw # movw $(13<<8),boss_x
+ mov $1,%ah
+ stosw # movw $(1<<8),boss_xadd
+
+ push $40
+ pop %ebx
+ call random
+ add $10,%ax
+ stosw # movw %ax,boss_count
+
+ xor %al,%al
+ stosb # movb $0,boss_smoke
+ stosb # movb $0,boss_exploding
+ inc %al
+ stosb # movb $1,boss_waiting
+
+ mov level,%al
+ shl $2,%al
+ add $20,%al
+ stosb # movb %al,boss_hits
+
+ movb $7,current_enemy_type
+ movb $20,enemy_wait
+ jmp move_enemies
+
+check_type_7:
+
+ # if boss, and he's waiting, don't produce enemies
+
+ cmpb $7,current_enemy_type
+ jne setup_enemy_defaults
+ cmpb $0,boss_waiting
+ jne move_enemies
+
+
+ ###############################
+ # setup enemy defaults
+setup_enemy_defaults:
+ incw enemies_spawned # enemies_spawned++
+ incw total_enemies_out # total_enemies_out++;
+
+ mov %ebp,%edi
+ mov $1,%al
+ stosb # movb $1,ENEMIES_OUT(%ebp)
+ # enemies[i].out=1
+ xor %al,%al
+ stosb # movb $0,ENEMIES_EXPLODING(%ebp)
+ # enemies[i].exploding=0;
+
+
+ add $2,%edi # skip xadd,yadd
+
+ stosb # movb $0,ENEMIES_XMIN(%ebp)
+ # enemies[i].xmin=0;
+ mov $37,%al
+ stosb # movb $37,ENEMIES_XMAX(%ebp)
+ # enemies[i].xmax=37;
+
+
+
+ ##########################################
+ # if enemy_kind < 0 then kind=random()%6
+ # else use enemy_kind value
+
+ movb current_enemy_kind,%al # get enemy_kind
+ cmp $0,%al # is it less than 0?
+ jge no_random_kind # if not move ahead
+ push $6
+ pop %ebx # get rand()%6
+ call random
+no_random_kind:
+ stosb # movb %al,ENEMIES_KIND(%ebp)
+ # enemies[i].kind=enemy_kind
+
+ ######################################
+ # if init_x < 0 then x=random()%37
+ # else, use the "init_x" value
+
+ movw current_init_x,%ax # get init_x
+ cmp $0,%ax # is it less than zero?
+ jge no_random_x # if so skip ahead
+random_x:
+ push $36
+ pop %ebx # get random%36
+ call random
+ mov %al,%ah # high byte is significant
+no_random_x:
+ stosw # movw %ax,ENEMIES_X(%ebp)
+ # store enemies[i].x
+ xor %eax,%eax
+ stosw # movw $0,ENEMIES_Y(%ebp)
+ # enemies[i].y=0;
+
+
+ #################################
+ # enemy type specific inits
+
+ movb current_enemy_type,%bl
+ movb level,%dl
+ shl $4,%dl
+ cmp $0,%bl
+ jne enemy_type_1
+
+ #####################
+ # ENEMY_TYPE 0
+ # diagonal, no wait, movement proportional to level
+
+enemy_type_0:
+ movb %dl,ENEMIES_XADD(%ebp) # xadd = level*8
+ movb %dl,ENEMIES_YADD(%ebp) # yadd = level*8
+ jmp move_enemies
+
+ ##########################
+ # ENEMY_TYPE 1
+ # Horizontal, then fall.
+
+enemy_type_1:
+ sub $1,%bl
+ jnz enemy_type_3
+
+ mov $5*8,%al
+ movb %al,ENEMIES_XADD(%ebp) # enemies[i].xadd=5*8;
+
+ push $100
+ pop %ebx
+ call random
+ neg %al
+ movb %al,ENEMIES_YADD(%ebp) # enemies[i].yadd=-(rand()%100);
+
+ jmp move_enemies
+
+ ##########################
+ # Enemy Type 3
+ # type two waits for clear
+ # then diagonal, all of same type
+
+enemy_type_3: # skip type 2
+ sub $2,%bl
+ jnz enemy_type_4
+
+ mov $5*8,%al
+ movb %al,ENEMIES_XADD(%ebp) # enemies[i].xadd=5;
+
+ movb %dl,ENEMIES_YADD(%ebp) # enemies[i].yadd=level;
+
+ jmp move_enemies
+
+
+ ###########################
+ # Enemy Type 4
+ # "wiggle"
+
+enemy_type_4:
+ sub $1,%bl
+ jnz enemy_type_5
+
+ mov $4*8,%al
+ movb %al,ENEMIES_XADD(%ebp) # enemies[i].xadd=4;
+
+ movb %dl,ENEMIES_YADD(%ebp) # enemies[i].yadd=level;
+
+ push $34
+ pop %ebx
+ call random
+ add $2,%al
+
+ movb %al,ENEMIES_XMIN(%ebp) # enemies[i].xmin=2+rand()%34;
+ shl $8,%ax
+ movw %ax,ENEMIES_X(%ebp) # enemies[i].x=enemies[i].xmin*8;
+
+ push $20
+ pop %ebx
+ call random
+ mov %al,%dl
+ mov ENEMIES_XMIN(%ebp),%al
+ add %dl,%al
+
+ cmp $35,%al
+ jle xmax_ok
+ mov $35,%al
+
+xmax_ok:
+ mov %al,ENEMIES_XMAX(%ebp) # enemies[i].xmax=enemies[i].xmin+(rand()%20);
+
+ jmp move_enemies
+
+ #########################
+ # Enemy Type 5
+ # "rain"
+
+enemy_type_5:
+ sub $1,%bl
+ jnz enemy_type_7
+
+ push $4
+ pop %ebx
+ call random # get rand()%4
+
+ test $3,%al # see if bottom two bits 00
+ jnz no_use_own_x # ak, one chance in 4
+
+ mov x,%ax # one chance in 4 use
+ mov %ax,ENEMIES_X(%ebp) # enemies[i].x=x;
+
+no_use_own_x:
+
+ movb $0,ENEMIES_XADD(%ebp) # enemies[i].xadd=0;
+ movb %dl,ENEMIES_YADD(%ebp) # enemies[i].yadd=2;
+
+ jmp move_enemies
+
+ #########################
+ # Enemy Type 7
+ # things flung by boss
+
+enemy_type_7:
+ movb $0,ENEMIES_XADD(%ebp) # enemies[i].xadd=0;
+ movb %dl,ENEMIES_YADD(%ebp) # enemies[i].yadd=2;
+
+ mov boss_x,%ax
+ add $5,%ah
+ mov %ax,ENEMIES_X(%ebp) # enemies[i].x=(boss.x+5)*8;
+ movw $(3<<8),ENEMIES_Y(%ebp) # enemies[i].y=3*8;
+
+ #######################
+ # Move Enemies
+ #######################
+
+move_enemies:
+
+ mov $enemy_0,%ebp # point to first enemy
+ push $NUM_ENEMIES
+ pop %ecx # loop through all enemies
+
+move_enemies_loop:
+ mov %ebp,%esi
+ lodsb # get enemy[i].out
+ test $1,%al # is the enemy out?
+ jz loop_move_enemies # if so keep looping
+
+move_enemies_x:
+ xor %eax,%eax
+ inc %esi # point to xadd
+
+ lodsb
+ cmp $0,%al # is it zero?
+ je move_enemies_y # if so, move along to y
+
+ cbw # sign extend al to ax
+ addw %ax,ENEMIES_X(%ebp) # enemies[i].x+=enemies[i].xadd
+
+ # check x bounds
+
+ mov ENEMIES_X(%ebp),%dx
+ cmp ENEMIES_XMAX(%ebp),%dh # is enemies[i].x>enemies[i].xmax?
+ jg switch_x_dir # if so, switch direction
+ cmp ENEMIES_XMIN(%ebp),%dh # is enemies[i].x now fall
+ shl $4,%al #
+ mov %al,ENEMIES_YADD(%ebp) # enemies[i].yadd=2*level;
+ movb $0,ENEMIES_XADD(%ebp) # enemies[i].xadd=0;
+
+ jmp ship_enemy_collision_detect
+
+no_special_case:
+
+ add %ax,ENEMIES_Y(%ebp) # enemies[i].y+=yadd
+
+ cmpb $18,ENEMIES_Y+1(%ebp) # is y>18?
+ jle ship_enemy_collision_detect # if not move ahead
+
+ decb total_enemies_out # we are off screen. remove
+ movb $0,ENEMIES_OUT(%ebp) # enemies[i].out=0
+ andb $~PERFECT_ENEMY,game_flags
+
+ship_enemy_collision_detect:
+
+ ##########################################
+ # Ship <-> Enemies Collision Detection
+ ##########################################
+
+ cmpb $0,ENEMIES_EXPLODING(%ebp) # if enemy is exploding
+ jne loop_move_enemies # don't check for collision
+
+ movw x,%ax # check x
+ mov %ah,%al
+ add $6,%al # through x+6
+
+ movw ENEMIES_X(%ebp),%dx # check enemies[i].x
+ mov %dh,%dl
+ add $2,%dl # through enemies[i].x+2
+
+ call check_inside
+ jnc loop_move_enemies
+
+ mov $16,%ah # check y
+ mov %ah,%al
+ add $2,%al # through y+2
+
+ movw ENEMIES_Y(%ebp),%dx # check enemies[i].y
+ mov %dh,%dl
+ add $1,%dl # through enemies[i].y+1
+
+ call check_inside
+ jnc loop_move_enemies
+
+ movb $1,ENEMIES_EXPLODING(%ebp)
+ decb shields
+
+ andb $~PERFECT_SHIELD,game_flags
+
+ movl $(120<<16+50),sound_freq
+ orb $SOUND_PENDING,game_flags # set_sound(120,50);
+
+loop_move_enemies:
+ add $ENEMIES_SIZE,%ebp # move to next enemy struct
+ sub $1,%ecx # loop, but more than 128 away
+ jnz move_enemies_loop # so have to do it by hand
+
+ ###################
+ # Draw the Enemies
+ ###################
+
+ # Make out,exploding flags?
+ # out,exploding,kind,x,y
+ # xadd,yadd,xmin,xmax
+
+ mov $enemy_0,%ebp # point to first enemy
+ push $NUM_ENEMIES
+ pop %ecx # loop through all enemies
+
+draw_enemies:
+ mov %ebp,%esi
+ lodsb # get enemy[i].out
+ test $1,%al # is the enemy out?
+ jz loop_draw_enemies # if so keep looping
+
+ xor %eax,%eax
+ lodsb # load "exploding" info
+ cmp $0,%al
+ je not_exploding
+
+handle_exploding:
+ push %eax
+ shr $1,%al
+ # *2 for slow-down reasons)
+ lea explosion_sprites(,%eax,8),%edx
+ # base+offset*8
+ pop %eax # restore exploding
+ inc %al # increment exploding
+ mov %al,ENEMIES_EXPLODING(%ebp) # store back exploding
+
+ cmp $7,%al # is exploding > 7?
+ jle cont_handle_exploding
+
+ movb $0,0(%ebp) # enemy[i].out=0
+ decb total_enemies_out # enemies_out--
+
+cont_handle_exploding:
+ add $5,%esi # skip to enemies_x
+ jmp enemies_xy
+
+not_exploding:
+ xor %eax,%eax
+ add $4,%esi # skip to kind
+ lodsb # get kind
+ lea enemy_sprites(,%eax,8),%edx
+ # kind muliplied by 8 and added on
+
+enemies_xy:
+ lodsw # load xh
+ lodsb #
+ lodsb # load yh (little endian)
+
+ mov %edx,%esi # proper sprite
+
+ push %ecx
+ call blit_219 # actually blit things
+ pop %ecx
+
+loop_draw_enemies:
+ add $ENEMIES_SIZE,%ebp # move to next enemy struct
+ loop draw_enemies # and loop
+
+
+ ##########################
+ # Draw the Boss
+ ##########################
+draw_the_boss:
+
+ cmpb $7,current_enemy_type # are we at end-of-level boss?
+ jne done_with_boss # if not skip all this nonsense
+
+
+ cmpb $1,boss_exploding # if boss is exploding
+ je skip_draw_boss # don't draw it
+
+ mov $boss_sprite,%esi
+ movw boss_x,%ax
+ xor %al,%al
+ call blit_219 # blit(boss_sprite,framebuffer,219,boss.x,0,13,3);
+
+skip_draw_boss:
+
+ ########################
+ # Draw Smoke
+
+ cmpb $0,boss_smoke # is the boss smoking?
+ je skip_draw_smoke # if not skip ahead
+
+
+ xor %eax,%eax
+ movb boss_smoke,%al
+ shr $2,%al
+ lea smoke_sprites(%eax,%eax,4),%esi
+ push %esi
+ movw boss_x,%ax
+ add $5,%ah
+ mov $3,%al
+ push %eax
+ call blit # blit(smoke_sprites[boss.smoke/4],framebuffer,219,boss.x+5,3,3,1);
+
+ pop %eax
+ subw boss_xadd,%ax
+ mov $4,%al
+ pop %esi
+ call blit # blit(smoke_sprites[boss.smoke/4],framebuffer,219,boss.x+5-boss.xadd,4,3,1);
+
+ decb boss_smoke # boss.smoke--;
+
+
+skip_draw_smoke:
+
+ ########################
+ # Boss Laser Shoot
+
+ cmpb $0,boss_shooting # is the boss shooting?
+ je skip_boss_shooting # if not skip ahead
+
+ decb boss_shooting # boss.shooting--
+
+ xor %eax,%eax
+ movb boss_shooting,%al # move boss.shooting into %eax
+ push %eax # saveon stack
+
+ add $200,%ax # add 200
+ movw %ax,sound_freq+2 # save as sound_freq
+ movw $20,sound_freq
+ orb $SOUND_PENDING,game_flags # set sound to play
+
+ pop %eax # restore boss_shooting
+
+ and $1,%eax # get low bit of boss shooting
+ lea laser_sprites(,%eax,4),%esi # point to proper laser sprite
+
+ xor %ecx,%ecx # clear ecx counter
+
+boss_shoot_loop:
+
+ mov boss_x,%ax # get boss_x into ax
+ mov %cl,%al
+ shl $1,%al
+ add $3,%al
+
+ push %eax
+ push %ecx
+ push %esi
+ call blit_219 # blit(laser_sprite[boss.shooting%2],framebuffer,219,boss.x,3+(i*2),1,2);
+ pop %esi
+ pop %ecx
+ pop %eax
+
+ add $12,%ah
+ push %ecx
+ push %esi
+ call blit # blit(laser_sprite[boss.shooting%2],framebuffer,219,boss.x+12,3+(i*2),1,2);
+ pop %esi
+ pop %ecx
+
+ add $1,%ecx
+ cmp $8,%ecx
+ jl boss_shoot_loop
+
+skip_boss_shooting:
+
+ #######################
+ # boss dead
+
+ cmpb $0,boss_exploding
+ je boss_is_not_exploding
+
+ movb $1,boss_waiting
+
+ push $30 # 30 random smokes
+ pop %ecx
+big_explosion:
+ xor %eax,%eax
+ movb boss_exploding,%al # get exploding amount
+ shr $3,%al # div 3
+ lea smoke_sprites(%eax,%eax,4),%esi # and that much smoke
+
+ push $4
+ pop %ebx
+ call random
+ mov %al,%dl # y=rand()%4
+
+ push $11
+ pop %ebx
+ call random
+ mov %al,%dh # x=rand()%11
+
+ movw boss_x,%ax
+ add %dh,%ah # boss_x+x
+ mov %dl,%al
+
+ push %ecx
+ push %esi
+ call blit_219
+ pop %esi
+ pop %ecx
+
+ loop big_explosion
+
+ movl $(120<<16+20),sound_freq
+ orb $SOUND_PENDING,game_flags # set_sound(120,20);
+
+ decb boss_exploding
+
+ cmpb $0,boss_exploding # are we done exploding?
+ jne not_dead_yet
+
+ cmpb $1,level # only show ending
+ jne no_ending # after level1
+
+ call do_ending
+no_ending:
+
+ addl $1000,score # 1000 points for killing boss
+
+ cmpb $7,level
+ je new_level # can't go past level 7!
+
+ incb level # level++
+
+
+ jmp new_level # start new level
+
+not_dead_yet:
+
+ jmp move_boss
+
+boss_is_not_exploding:
+
+ decw boss_count
+ cmpw $0,boss_count
+ jge move_boss
+
+ #############################################
+ # toggle boss waiting state if count is up
+
+ cmpb $0,boss_waiting
+ je make_boss_wait
+stop_boss_waiting:
+ movb $0,boss_waiting # boss.waiting=0;
+ mov $320,%ebx
+ call random
+ add $40,%ax
+ mov %ax,boss_count # boss.count=40+rand()%320;
+ jmp move_boss
+
+make_boss_wait:
+ movb $1,boss_waiting
+ push $40
+ pop %ebx
+ call random
+ add $30,%ax
+ mov %ax,boss_count # boss.count=30+rand()%40;
+ movb $30,boss_shooting # boss.shooting=30;
+
+move_boss:
+ cmpb $0,boss_waiting
+ jne laser_collision
+
+ movw boss_x,%ax
+ addw boss_xadd,%ax # boss.x+=boss.xadd;
+ mov %ax,boss_x
+
+ cmp $26,%ah
+ jg boss_reverse
+boss_under:
+ cmp $0,%ah
+ jge laser_collision
+
+boss_reverse:
+ negw boss_xadd
+ addw boss_xadd,%ax
+ mov %ax,boss_x
+
+laser_collision:
+ #######################
+ # Collision detection for lasers
+
+ cmpb $0,boss_shooting
+ je done_with_boss
+
+ movw boss_x,%dx
+ mov %dh,%dl
+
+ movw x,%ax
+ mov %ah,%al
+ add $6,%al
+ call check_inside
+
+ jc laser_hit
+
+ add $12,%dh
+ mov %dh,%dl
+
+ movw x,%ax
+ mov %ah,%al
+ add $6,%al
+ call check_inside
+
+ jnc done_with_boss
+
+laser_hit:
+ testb $3,boss_shooting
+ jnz done_with_boss
+ decb shields # if (boss.shooting%7==0) shields--;
+
+done_with_boss:
+
+
+
+ ########################
+ # Move the Missiles
+ ########################
+
+ mov $missile_0,%ebp # point to first missile
+ push $NUM_MISSILES
+ pop %ecx # loop through all missiles
+
+move_missiles:
+ mov %ebp,%esi
+ lodsb # get missile[i].out
+ test $1,%al # is the missile out?
+ jz loop_move_missiles # if not keep looping
+
+ lodsb # load x
+ lodsb # load y
+ dec %al # y--
+ mov %esi,%edi
+ dec %edi
+ stosb # store y back out
+
+ cmp $0,%al # is y<0?
+ jg missile_collision_detection # if not keep going
+
+ andb $(~PERFECT_SHOT),game_flags # not a perfect shot
+ mov %ebp,%edi # destroy missile
+ xor %al,%al
+ stosb
+ jmp loop_move_missiles
+
+ #################################
+ # Missile Collision Detection
+
+missile_collision_detection:
+ push %ecx # save missile count
+ mov MISSILE_X(%ebp),%dh # move missile[i].x -> dh
+ mov MISSILE_Y(%ebp),%dl # move missile[i].y -> dl
+ push %edx # save missile info for later
+
+ mov $enemy_0,%ebx
+ mov $NUM_ENEMIES,%ecx
+check_missile_enemy:
+ cmpb $0,ENEMIES_OUT(%ebx)
+ je loop_missile_enemy
+
+ cmpb $0,ENEMIES_EXPLODING(%ebx)
+ jne loop_missile_enemy
+
+ pop %edx # restore missile x,y
+ push %edx
+
+ mov %dh,%dl # missile x is 1 wide
+
+ movw ENEMIES_X(%ebx),%ax # get enemies x
+ mov %ah,%al
+ add $2,%al # enemy x is two wide
+ call check_inside
+ jnc loop_missile_enemy
+
+ pop %edx
+ push %edx
+ mov %dl,%dh # only check head of missile?
+
+ movw ENEMIES_Y(%ebx),%ax
+ mov %ah,%al
+ add $1,%al
+ call check_inside
+ jnc loop_missile_enemy
+
+
+ # Collision!
+
+ movb $1,ENEMIES_EXPLODING(%ebx)
+ addl $10,score
+
+ movl $(150<<16+40),sound_freq
+ orb $SOUND_PENDING,game_flags # set_sound(150,40);
+
+ addb $1,shield_up_count # add 1 to shield bonus count
+ cmpb $UP_SHIELDS,shield_up_count # have we hit limit?
+ jl no_shield_bonus # if not move on
+
+ movb $0,shield_up_count # reset shield_up_count to 0
+ addb $1,shields # add one to shields
+
+ movl $(220<<16+50),sound_freq
+ orb $SOUND_PENDING,game_flags # set_sound(220,50);
+
+ cmpb $10,shields # are we greater than 10?
+ jle no_shield_bonus
+ movb $10,shields # if so, set to 10
+
+no_shield_bonus:
+
+ movb $0,MISSILE_OUT(%ebp) # set missile out to 0
+
+loop_missile_enemy:
+ add $ENEMIES_SIZE,%ebx
+ dec %ecx
+ cmp $0,%ecx
+ jnz check_missile_enemy
+
+
+check_missile_boss:
+
+ pop %edx # missile[i].x,missile[i].y
+ pop %ecx # missile count
+
+ # Missile <-> Boss Collision Detection
+
+ cmpb $7,current_enemy_type # see if boss is out
+ jne done_missile_collision
+
+ cmpb $1,boss_exploding # be sure boss is not exploding
+ je done_missile_collision
+
+ movw boss_x,%ax
+ mov %ah,%al
+ add $13,%al
+
+ push %edx
+ mov %dh,%dl
+ call check_inside
+ pop %edx
+
+ jnc done_missile_collision
+
+check_boss_y:
+
+ xor %eax,%eax
+ add $2,%al
+
+ mov %dl,%dh
+ call check_inside
+
+ jnc done_missile_collision
+
+ movl $(150<<16+50),sound_freq
+ orb $SOUND_PENDING,game_flags # set_sound(150,50);
+
+ movb $0,MISSILE_OUT(%ebp)
+ movb $11,boss_smoke
+
+ decb boss_hits # decrement hits left
+ cmpb $0,boss_hits # are we done?
+ jge done_missile_collision # if not, go on
+
+ movb $23,boss_exploding # start boss exploding
+ movb $0,boss_shooting # have him stop shooting
+
+ # destroy all extant missiles
+
+ push %ecx
+
+ mov $enemy_0,%ebx # point to first missile
+ mov $NUM_ENEMIES,%ecx # loop through all missiles
+destroy_enemies:
+ movb $2,ENEMIES_EXPLODING(%ebx)
+ add $ENEMIES_SIZE,%ebx
+ loop destroy_enemies
+
+ pop %ecx
+
+done_missile_collision:
+
+
+loop_move_missiles:
+ add $3,%ebp
+ dec %ecx
+ cmp $0,%ecx
+ jnz move_missiles
+
+done_move_missiles:
+
+
+
+ ########################
+ # Draw the Missiles
+ ########################
+
+ mov $missile_0,%ebp # point to first missile
+ push $NUM_MISSILES
+ pop %ecx # loop through all missiles
+
+draw_missiles:
+ mov %ebp,%esi
+ lodsb # get missile[i].out
+ test $1,%al # is the missile out?
+ jz loop_draw_missiles # if so keep looping
+
+ lodsb # load x
+ shl $8,%ax
+ lodsb # load y
+
+ mov $missile_sprite,%esi # missile sprite
+ push %ecx
+ call blit_219 # actually blit things
+ pop %ecx
+
+loop_draw_missiles:
+ add $3,%ebp # move to next missile struct
+ loop draw_missiles # and loop
+
+
+ #############################
+ # Read the keyboard
+ #############################
+
+game_read_keyboard:
+
+ call get_a_char
+ jc move_ship
+
+game_q:
+ cmp $'q',%al # are we 'q'?
+ jne game_j # if not, move on
+
+ call verify_quit # pop up "sure you want to quit"
+ jnz done_game # then game over
+
+ jmp set_pause_flag # if not act like paused then cont
+
+game_j:
+ cmp $'j',%al # are we "j" [right] ?
+ jne game_k # if not keep going
+
+ mov xadd,%bx # load in xadd from RAM
+ cmp $0,%bx # are we less than zero?
+ jg game_j_0 # if not go ahead
+ add $(-128),%bx # add -128 to xadd
+ jmp game_j_done
+game_j_0:
+ xor %ebx,%ebx # switching direction, make xadd 0
+game_j_done:
+ mov %bx,xadd # store back to RAM
+ jmp game_read_keyboard # done
+
+
+game_k:
+ cmp $'k',%al # are we 'k'? [left]
+ jne game_p # if not move ahead
+
+ mov xadd,%bx # load in xadd from RAM
+ cmp $0,%bx # are we less than zero?
+ jl game_j_0 # then changing direction
+ # set to 0 ( OPT reuse game_j)
+
+ add $(128),%bx # add 128 to xadd
+ jmp game_j_done # (OPT reuse game_j code)
+
+game_p:
+ cmp $'p',%al # did we press 'p'?
+ jne game_s # if not, move on
+
+ mov $14,%bl # put attention block
+ call put_attention_block
+
+ mov $game_paused_line,%esi # print "GAME PAUSED!"
+
+ push $1
+ pop %ecx
+
+ call text_screen_keypressed_ret
+ # call put_text_inline
+ # call dump_to_screen
+ # call wait_until_keypressed
+
+
+ jmp set_pause_flag
+
+game_s:
+ cmp $'s',%al # did we press 's'?
+ jne game_h # if not, move on
+ xorb $SOUND,game_flags # toggle sound bit
+ jmp game_read_keyboard
+
+game_h:
+ cmp $'h',%al # Did we press 'h'?
+ jne game_space # if not, move on
+ call display_help # display help
+set_pause_flag:
+ orb $PAUSED,game_flags # set the "paused" flag
+ jmp game_read_keyboard
+
+game_space:
+ cmp $' ',%al # Did we press ' '?
+ jne game_unknown # If not, move on
+
+ mov $missile_0,%esi # point to first missile
+ push $NUM_MISSILES
+ pop %ecx # loop through all missiles
+fire_missiles:
+ lodsb # get missile[i].out
+ cmp $0,%al # is it empty?
+ jne end_fire_loop # if not keep looping
+
+ mov %esi,%edi # point to missile[i].out
+ dec %edi
+ mov $1,%al # indicate that it's out
+ stosb
+
+ mov x,%ax
+ shr $8,%ax
+ add $3,%al
+ stosb # missile[i].x=shipx+3
+
+ mov $16,%al
+ stosb # missile[i].y=shipy
+
+ movl $(110<<16+30),sound_freq
+ orb $SOUND_PENDING,game_flags # set_sound(110,30);
+
+ jmp game_read_keyboard # finished shooting
+
+end_fire_loop:
+ add $2,%esi # point to next missile
+ loop fire_missiles # loop
+
+game_unknown:
+ jmp game_read_keyboard
+
+
+ ########################
+ # move the ship
+ ########################
+
+move_ship:
+ mov x,%ax # restore x from memory
+ mov xadd,%bx # restore xadd from memory
+
+ add %bx,%ax # x+=xadd
+
+check_x_under:
+ jns check_x_over # if not go ahead
+ xor %ax,%ax # if under clear x and xadd
+ xor %bx,%bx
+check_x_over:
+ cmp $33,%ah # are we over 33?
+ jle blit_ship # if not draw ship
+ mov $33,%ah # x=33, xadd=0
+ xor %bx,%bx
+blit_ship:
+ mov %ax,x # write updated values out to RAM
+ mov %bx,xadd
+
+ mov $ship_sprite,%esi # load the ship-centric pic
+ mov $16,%al # x already in ah, 16=y
+ call blit_219
+
+ ###########################
+ # draw the info bar
+ ###########################
+
+
+ cmpb $0,shields # are shields <0?
+ jl done_game # if so, GAME OVER
+
+ movb $12,shields_line # make SHIELDS line red
+ jg draw_shields_bar # are we at zero shields?
+ movb $14,shields_line # if so make SHIELDS line yellow
+
+draw_shields_bar:
+ xor %ecx,%ecx # clear count
+ movb shields,%dl # move shields into dl
+ mov $21,%al # y=21
+ mov $10,%ah # x starts at 10
+
+shield_bar_loop:
+ cmp %dl,%cl # is count greater than shields?
+ jge shield_empty # if so, put empty
+
+ mov $block,%esi # if not, put a block
+
+ mov $4,%bl # color=dark red
+ cmp $4,%ecx # if less than 4
+ jl draw_shield
+
+ mov $12,%bl # color=light red
+ cmp $8,%ecx # if 48
+
+ jmp draw_shield
+
+shield_empty:
+
+ mov $underscore,%esi # put a dark grey underscore
+ mov $8,%bl
+
+draw_shield:
+
+ call put_text_xy # put the char
+ add $2,%ah # move x over by 2
+
+ inc %ecx # increment counter
+ cmp $10,%ecx # are we less than 10?
+ jne shield_bar_loop # if so keep looping
+
+
+ # Should convert to ascii at score changetime
+ # And not update score string here
+
+ mov $shields_line,%esi # print "SHIELDS:","SCORE:",
+ push $4 # "HISCORE:","LEVEL:"
+ pop %ecx
+ call put_text_inline
+
+ mov score,%eax # Convert score to ascii
+ mov $score_string,%edi
+ call num_to_ascii
+
+ mov $score_string,%esi # print score_string
+ mov $((8<<8)+22),%eax
+ mov $15,%bl
+ call put_text_xy
+
+ xor %eax,%eax
+ movb level,%al # Convert level to ascii
+ mov $level_string,%edi
+ call num_to_ascii
+
+ mov $level_string,%esi # print level_string
+ mov $((8<<8)+23),%eax
+ mov $15,%bl
+ call put_text_xy
+
+ mov hiscore,%eax # Convert hiscore to ascii
+ mov $hiscore_string,%edi
+ call num_to_ascii
+
+ mov $hiscore_string,%esi # print hiscore_string
+ mov $((32<<8)+22),%eax
+ mov $15,%bl
+ call put_text_xy
+
+ testb $SOUND_PENDING,game_flags # is a sound pending?
+ jz no_sound_effect # if not, move ahead
+ andb $~SOUND_PENDING,game_flags # clear sound_pending flag
+ movl sound_freq,%ebx
+ call play_sound # play the sound
+
+
+no_sound_effect:
+
+ #################################################
+ # Finally draw it all to the screen
+ #################################################
+
+ call dump_to_screen
+
+ ##################################################
+ # Frame limit... keep it at ~30 frames/sec
+ ##################################################
+ # Assumes we don't lag more than a second
+ # Seriously, if we lag more than 10ms we are screwed anyway
+
+frame_limit:
+ mov $game_time,%ebx # get current time
+ call gettimeofday
+
+ mov game_time+4,%ebx # move usecs to %ebx
+ mov game_old_time,%eax # mov old usecs to %eax
+
+ mov %ebx,%ecx
+
+ sub %eax,%ebx # time delta in %ebx
+
+ cmp $0,%ebx
+ jge time_no_adjust
+ add $1000000,%ebx # correct for underflow
+
+time_no_adjust:
+
+ cmp $30000,%ebx # have we waited 30ms?
+ jg done_frame_limit # if so, move on
+
+ call hundred_usec_nanosleep # else, sleep a bit
+
+ jmp frame_limit
+
+
+done_frame_limit:
+ mov %ecx,game_old_time # store as old time
+
+
+ testb $PAUSED,game_flags # were we paused?
+ jz game_not_paused
+
+ andb $(~PAUSED),game_flags # clear PAUSED flag
+ mov $game_time,%ebx # get current time
+ call gettimeofday
+
+ mov game_time+4,%ebx # move usecs to %ebx
+
+game_not_paused:
+
+ ########################
+ # LOOP until FINISHED
+ ########################
+
+ jmp main_game_loop # LOOP until finished
+
+done_game:
+
+ ########################
+ # GAME OVER
+ ########################
+
+ mov $14,%bl # put attention block
+ call put_attention_block
+
+ mov $game_over_line,%esi # print "GAME OVER!"
+ call put_text_line_inline
+
+ call dump_to_screen
+
+ call wait_long_time
+
+ #############################
+ # Play sad music
+
+ cmpb $0,shields
+ jg no_bum_bum
+
+ testb $SOUND,game_flags
+ jz no_bum_bum
+
+ call wait_long_time
+
+ mov $(164<<16+500),%ebx
+ call play_sound # set_sound(164,500);
+
+ call dump_to_screen
+
+ call wait_long_time
+
+ mov $(130<<16+500),%ebx
+ call play_sound # set_sound(130,500);
+
+ call dump_to_screen
+
+ jmp show_hi_score
+
+no_bum_bum:
+ push $3
+ pop %ecx # Pause 3 seconds or until keypress
+ call pause_a_while
+
+show_hi_score:
+
+ call clear_framebuffer # clear screen
+
+ mov score,%eax # get score
+ mov hiscore,%ebx # get hiscore
+ cmp %ebx,%eax # is score less than hiscore?
+ jle no_new_hiscore # if so skip ahead
+
+ mov %eax,hiscore # score is the new hiscore
+
+ call new_hi_score
+
+no_new_hiscore:
+ call save_hi_score
+ call do_hi_score # show the hiscore
+ call wait_long_time
+
+ push $5
+ pop %ecx # Pause 5 seconds or until keypress
+ call pause_a_while
+
+ ret
+
+
+
+ ######################
+ # RANDOMIZE TIMER
+ ######################
+ # We want a seed that is not divisible by 2 or 5
+ # to enhance the quality of subsequent pseudo-random
+ # numbers
+ ###############
+ # destroys eax,ebx,ecx,edx
+
+randomize_timer:
+ mov $random_seed,%ebx # get current time
+ call gettimeofday
+
+ mov random_seed,%eax # use seconds since 1970 as seed
+
+ push $5
+ pop %ecx # we will be dividing by 5 later
+
+try_again:
+ inc %eax # hackish way, but keeps logic simple
+ # and we only have 50/50 of even anyway
+
+ test $0x1,%al # check if even
+ jz try_again # if so inc and try again
+
+ xor %edx,%edx # clear out top 32 bits
+ idivl %ecx # divide edx:eax by 5
+
+ cmp $0,%edx # check if remainder is zero
+ je try_again # if so inc by 1 and try again
+
+ and $0xffffff,%eax # we're doing fixed point so
+ # trim some high-order digits
+
+ mov %eax,random_seed # store back to memory
+
+ ret
+
+
+ ######################
+ # RANDOM
+ ######################
+ # pseudo-random number generator
+ ######################
+ # bx = mod [aka high range]
+ # ax returned with random number
+
+random:
+
+ # The following algorithm from the Hewlett Packard HP-20S
+ # Scientific Calculator manual, September 1998, p75-76
+ #
+ # The algorithm r = FractionalPart (997r )
+ # i+1 i
+ #
+ # Where r0 is a starting value between 0 and 1.
+ # The generator passes the chi-square frequency test for
+ # uniformity, and serial and run tests for randomness.
+ # The more significant digits are more random than the
+ # less significant. If r0 * 10e7 is not divisible
+ # by 2 or 5 you get 500,000 numbers w/o repeating.
+ #
+ # modified to be fixed-point integer only by Vince Weaver
+
+ push %edx
+ push %ecx
+ push %ebx
+
+ mov random_seed,%eax # get current seed
+
+ mov $997,%ecx
+ mull %ecx # multiply by 997
+
+ and $0xffffff,%eax # keep to ~7 digits
+ mov %eax,random_seed # store back the seed
+
+
+ shr $8,%eax # high order most random
+ and $0xffff,%eax # we limit random nums to 0-65535 range
+
+ pop %ebx # get high limit
+ cdq # clear dx
+ divw %bx # divide by limit
+ mov %dx,%ax # move remainder to ax
+
+ pop %ecx
+ pop %edx
+
+ ret
+
+ ########################
+ # wait_long_time
+ ########################
+wait_long_time:
+ push $5
+ pop %ecx
+wait_loop:
+ push %ecx
+ call inflection_point
+ pop %ecx
+ loop wait_loop
+ ret
+
+
+ ########################
+ # inflection_point
+ ########################
+ # pause hard, and clear keypresses
+ # used in a sudden stop of action
+inflection_point:
+ mov $150,%ecx
+sleep_250ms:
+ call milisec_nanosleep
+ loop sleep_250ms
+
+ # slide in and also
+ # clear keyboard buffer
+
+ ##########################
+ # clear_keyboard_buffer
+ ##########################
+clear_keyboard_buffer:
+
+ call get_char
+ jnc clear_keyboard_buffer
+
+ ret
+
+
+ #################################
+ # do_ending
+ #################################
+do_ending:
+ call wait_long_time # pause a sop up keyboard in case
+ # still firing keys at boss
+
+ call clear_framebuffer # clear screen
+
+ push $16 # want to write 16 lines of text
+ pop %ecx
+
+ mov $ending_line,%esi
+ call put_text_inline
+
+ mov $earth_sprite,%esi # Draw Picture of Earth
+ mov $(32<<8),%ax
+ call blit_219
+
+ # draw picture of Susie
+ # %esi follows that of earth
+ mov $(20<<8+15),%ax
+ call blit
+
+ call dump_to_screen
+
+ call wait_long_time
+
+ call wait_until_keypressed
+
+ call clear_framebuffer
+
+ mov $tom_head_sprite,%esi # put head picture
+ xor %eax,%eax # at 0,0
+ call blit_219
+
+
+ mov $ending_line_2,%esi
+
+ push $2 # put two lines of text
+
+ jmp pop_text_screen_keypressed_ret
+
+ # insane code reuse
+ # pop %ecx
+ # call put_text_inline
+ # call dump_to_screen
+ # call wait_until_keypressed
+ # ret
+
+
+ #################################
+ # do_about
+ #################################
+do_about:
+
+ call clear_framebuffer
+
+ mov $vince_sprite,%esi # load the ego-centric pic
+ mov $(24<<8),%eax # at 24,0
+ call blit_219
+
+ mov $about_line_0,%esi
+ push $15
+
+ jmp pop_text_screen_keypressed_ret
+
+ # insane code re-use
+ #pop %ecx
+ #call put_text_inline
+ #call dump_to_screen
+ #call wait_until_keypressed
+ #ret
+
+
+
+ #################################
+ # do_story
+ #################################
+do_story:
+
+ call clear_framebuffer
+
+ mov $phobos_sprite,%esi # load the mars pic
+ xor %eax,%eax # at 0,0
+ inc %eax
+ call blit_219
+
+ mov $story_line_0,%esi # write the story text
+ push $3
+ pop %ecx
+ call put_text_inline
+
+ push %esi
+ call dump_to_screen
+ pop %esi
+
+ push $8
+ pop %ecx
+
+ call pause_a_while # pause for up to 8 seconds
+
+ # esi points at story_line_1
+ # saved from before
+ push $3
+ pop %ecx
+ call put_text_inline
+
+ call dump_to_screen
+
+ push $4
+ pop %ecx
+ call pause_a_while # pause for up to 4 seconds
+
+ mov $(19<<8+9),%ax
+ push %eax
+
+phobos_loop:
+ mov $evil_ship_sprite,%esi # load the evil ship
+ call blit_219 # and draw it to the screen
+
+ call dump_to_screen
+
+ push $30
+ pop %ecx
+
+phobos_delay:
+ call milisec_nanosleep # delay 30ms
+ loop phobos_delay
+
+ mov $menu_blank+2,%esi # erase the ship
+ pop %eax
+ push %eax
+ call put_text_xy
+
+ pop %eax # increment x
+ inc %ah
+ push %eax
+
+ cmp $37,%ah # have we reached end of screen?
+ jne phobos_loop # if not, loop
+
+ pop %eax # restore stack
+
+ push $4
+ pop %ecx
+ call pause_a_while # pause for up to 4 seconds
+
+ call clear_framebuffer
+
+ mov $tom_sprite,%esi # load the tom pic
+ mov $(24<<8)+1,%eax # at 24,1
+ call blit_219
+
+ mov $story_line_2,%esi # put the tom related story
+ push $9
+ pop %ecx
+ call put_text_inline
+
+ call dump_to_screen
+
+ push $20
+ pop %ecx # pause for up to 20 seconds
+
+ # cheat and slide into
+ # pause a while
+
+
+ ############################
+ # Pause a While
+ ############################
+ # ecx = seconds
+ #
+pause_a_while:
+ mov $time_of_day,%ebx # get starting time
+ call gettimeofday
+
+ mov (time_of_day),%eax # store usecs in eax
+
+pause_loop:
+ push %eax
+ push %ebx
+ push %ecx
+ call get_char
+ pop %ecx
+ pop %ebx
+ pop %eax
+ jnc pause_end # if keypressed, end
+
+ call milisec_nanosleep # sleep a bit
+
+ mov $time_of_day,%ebx # get current time
+ call gettimeofday
+
+ mov (time_of_day),%ebx # put usecs in ebx
+
+ sub %eax,%ebx # ebx=new-old
+
+ cmp %ebx,%ecx
+ jg pause_loop
+pause_end:
+
+ ret
+
+
+ ######################
+ # Help
+ ######################
+ #
+
+display_help:
+ call clear_framebuffer
+
+ mov $help_line_0,%esi
+ push $18
+
+pop_text_screen_keypressed_ret:
+ pop %ecx
+text_screen_keypressed_ret:
+ call put_text_inline
+
+ call dump_to_screen
+
+ # cheat and slide into
+ # wait until keypressed
+
+ #######################
+ # Wait until keypressed
+ #######################
+ #
+wait_until_keypressed:
+
+ call get_char
+ jnc wait_exit
+ call milisec_nanosleep
+ jmp wait_until_keypressed
+
+wait_exit:
+ ret
+
+
+ ##################
+ # mov_edi_x_y
+ ##################
+ # makes edi point to framebuffer
+ # plus proper x,y offset
+ #
+ # ah=x al=y
+ # %eax,%ecx,%edi destroyed
+
+mov_edi_x_y:
+ mov $framebuffer,%edi # point to frame buffer
+ xor %ecx,%ecx # clear cx
+ mov %al,%cl # want to offset by y
+
+ cmp $0,%cl # if at x,0 don't offset
+ je offset_x
+
+offset_y:
+ add $(SCREEN_WIDTH*2),%edi # offset by y*2
+ loop offset_y
+
+offset_x:
+ and $0xffff,%eax # make sure top of eax clear
+ shr $7,%eax # add in x*2
+ add %eax,%edi
+
+ ret
+
+ ##################
+ # BLIT
+ ##################
+ # esi=source
+ # ah=x al=y
+ # (for already_know_only) bl=xsize,dh=ysize
+ # dl=char to write
+ # destroyed: %eax,%ebx,%ecx,%edx,%edi
+
+blit_219:
+ mov $219,%dl
+
+blit:
+ push %eax # save x,y
+ lodsb # get x-size from sprite
+ mov %al,%bl
+ lodsb # get y-size from sprite
+ mov %al,%dh
+ pop %eax # restore x,y
+
+blit_already_know_xsize_ysize:
+
+ and $0xff,%ebx # clear high bits of ebx
+
+ call mov_edi_x_y # point edi to proper place in framebuf
+
+blit_y_loop:
+ mov %bl,%cl # restore x-size counter
+
+blit_x_loop:
+
+ lodsb # get color info
+ cmp $0,%al # is it zero?
+ jz no_color # if so skip the write
+
+ mov %dl,%ah # get character
+ stosw # store char/color
+ jmp check_x
+
+no_color:
+ inc %edi # increment pointer
+ inc %edi
+check_x:
+ loop blit_x_loop # do while x<0
+
+ add $(SCREEN_WIDTH*2),%edi # move to next line
+ sub %ebx,%edi # by adding y-size then
+ sub %ebx,%edi # subtracting x-offset
+
+ sub $1,%dh # decrement y counter
+ jnz blit_y_loop # if not zero we loop
+
+ ret
+
+
+
+
+
+ #####################
+ # do_hi_score
+ #####################
+
+do_hi_score:
+ call load_hi_score # load hi-score from disk
+
+ mov $12,%bl # color light-red
+ call put_attention_block # put an attention block
+
+ mov $high_score_line,%esi # write "HIGH SCORE"
+ call put_text_line_inline
+
+ mov $hiscore_buffer,%edi # point to temp buffer
+ mov $' ',%al # space
+ stosb
+
+ mov $hi_player,%esi # put the high-players name
+ mov $3,%ecx
+ rep
+ movsb
+
+ mov $' ',%al # pad with ' '
+ stosb
+ stosb
+
+ mov hiscore,%eax # Convert hiscore to ascii
+ call num_to_ascii
+ mov $' ',%ax
+ stosw
+
+ mov $hiscore_buffer,%esi # point to buffer again
+ mov $15,%bl # white
+ mov $9,%al # y=9
+
+ mov $40,%ah # Center... start with 40
+ mov %esi,%edx
+strlen:
+ cmp $0,0(%edx) # repeat till end
+ je done_strlen
+ inc %edx
+ dec %ah # subtracting from the 40
+
+ jmp strlen
+done_strlen:
+ shr $1,%ah # divide by 2
+
+ call put_text_xy # put hiscore name/score
+
+ # cheat and slide into
+ # dump_to_screen
+
+
+ ##################
+ # dump_to_screen
+ ##################
+ # eax,ebx,ecx,edx,esi,edi trashed
+ # ebp= ^[
+ # eax = scratch
+ # bl = block_mode
+ # dl = old_color
+ # dh = ysize
+ # ecx = xsize
+
+dump_to_screen:
+ push %ebp # we save ebp
+
+ mov $framebuffer,%esi # setup pointers
+ mov $out_buffer,%edi
+
+ mov $('['<<8+27),%bp # store ^[[ as it will be useful later
+
+
+ # write ^[[0;0H to home the cursor
+ mov %ebp,%eax
+ stosw
+ mov $( ('H'<<24)+('0'<<16)+ (';'<<8)+('0')),%eax
+ stosl
+
+ xor %bl,%bl # set block_mode
+ mov $17,%dl # set old_color
+
+ mov $(SCREEN_HEIGHT),%dh # load in y size
+
+dump_y_loop:
+ push $SCREEN_WIDTH
+ pop %ecx # restore x size
+dump_x_loop:
+
+ lodsw # load ascii/color
+
+ cmp %dl,%al # compare to current color
+ je blit_block # if the same, skip ahead
+
+ mov %al,%dl # store color as old_color
+
+ push %eax # save ascii/color on stack
+
+ mov %ebp,%eax
+ stosw # print ^[[
+
+ mov %dl,%al # restore color
+
+ shr $3,%al # get intensity bit
+ add $0x30,%al # convert to ascii
+ stosb # store
+
+ mov %dl,%ah # restore color
+ and $7,%ah # mask off intensity bit
+
+ # swap bits 3 and 1
+ # we use rgb, ansi does bgr. annoying
+ # There's probably a better way.
+ # Maybe a lookup table?
+ xor %al,%al
+ rcr $1,%ah
+ rcl $1,%al
+
+ rcr $1,%ah
+ rcl $1,%al
+
+ rcr $1,%ah
+ rcl $1,%al
+
+ add $0x30,%al # convert to ascii
+
+ mov $'m',%ah # tack on trailing m
+
+ shl $16,%eax
+ mov $(('3'<<8)+';'),%ax
+
+ stosl # finish writing out color
+
+ pop %eax # restore ascii/color
+
+blit_block:
+ cmp $219,%ah # are we the block char?
+ jne regular_char # if not skip ahead
+
+ cmp $1,%bl # are we in block mode?
+ je change_block_zero # if yes, skip ahead
+
+ mov $14,%al # switch to vt102 line-draw mode
+ stosb # with ^N
+ mov $1,%bl # set block mode flag
+
+change_block_zero:
+ mov $'0',%ah # 0 = block in vt102 line-draw
+ jmp blit_char
+
+regular_char:
+ cmp $1,%bl # are we in block mode?
+ jne blit_char # if we aren't, skip ahead
+
+ push %eax # switch to normal mode
+ mov $15,%al # with ^O
+ stosb
+ xor %bl,%bl # clear block mode flag
+ pop %eax
+
+blit_char:
+ shr $8,%ax # write out the ascii char
+ stosb
+
+blit_char_done:
+
+ loop dump_x_loop # loop until x done
+
+ mov $10,%al # write a line-feed
+ stosb
+
+ sub $1,%dh # loop until y done
+ jnz dump_y_loop
+
+ mov $0,%al # store terminating 0 char
+ stosb
+
+ mov $out_buffer,%ecx # write to stdout
+
+ pop %ebp
+
+ # hijack our way into
+ # write_stdout
+
+
+
+ #################################
+ # WRITE_STDOUT
+ #################################
+ # ecx has string
+ # eax,ebx,ecx,edx trashed
+write_stdout:
+
+ cdq # clear edx (depends on high bit
+ # of eax being 0)
+
+str_loop1:
+ inc %edx
+ cmpb $0,(%ecx,%edx) # repeat till zero
+ jne str_loop1
+
+write_stdout_dx_set:
+
+ push $SYSCALL_WRITE # put 4 in eax (write syscall)
+ pop %eax # in 3 bytes of code
+
+ xor %ebx,%ebx # put 1 in ebx (stdout)
+ inc %ebx # in 3 bytes of code
+
+ int $0x80 # run the syscall
+
+ ret
+
+
+
+
+ #########################
+ # Clear Framebuffer
+ #########################
+ # eax,ecx,edi trashed
+
+clear_framebuffer:
+ xor %eax,%eax
+ mov $' ',%ah # clear with black spaces
+ mov $framebuffer,%edi
+ mov $(SCREEN_WIDTH*SCREEN_HEIGHT),%ecx
+ rep
+ stosw
+ ret
+
+ ############################
+ # gettimeofday()
+ ############################
+ # ebx points to buffer
+gettimeofday:
+ push %eax
+ push %ecx
+ push $SYSCALL_GETTIMEOFDAY
+ pop %eax
+ xor %ecx,%ecx # NULL timezone
+ int $0x80 # run the syscall
+ pop %ecx
+ pop %eax
+ ret
+
+ ###########################
+ # nanosleep()
+ ###########################
+ # time to sleep in buffer pointed by ebx
+
+milisec_nanosleep:
+ push %ebx
+ mov $milisecond,%ebx
+ jmp mid_nanosecond
+
+hundred_usec_nanosleep:
+ push %ebx
+ mov $hundred_microsecond,%ebx
+mid_nanosecond:
+ call nanosleep
+ pop %ebx
+ ret
+
+nanosleep:
+ push %eax
+ push %ecx
+ push $SYSCALL_NANOSLEEP
+ pop %eax
+ # ebx=req or &time_we_want_to_sleep
+ xor %ecx,%ecx # ecx=rem or &remainder (if interrupted)
+ int $0x80 # run the syscall
+ pop %ecx
+ pop %eax
+ ret
+
+ ############################
+ # tcgetattr
+ ############################
+ # pointer to result in edx
+ # eax,ebx,ecx trashed
+tcgetattr:
+ mov $TCGETS,%ecx
+ jmp do_ioctl
+
+
+ ############################
+ # tcsetattr
+ ############################
+ # pointer to parameters in edx
+ # eax,ebx,ecx trashed
+tcsetattr:
+ mov $TCSETS,%ecx # TCSETS (or SNDCTL_TMR_TIMEBASE :( )
+do_ioctl:
+ push $SYSCALL_IOCTL
+ pop %eax # someone set up us the ioctl
+ xor %ebx,%ebx # STDIN
+ int $0x80 # syscall!
+ ret
+
+
+
+ #############################
+ # put_text_inline
+ #############################
+ # esi = data
+ # ecx = number of strings
+ #
+ # first color, then y, then x, then string
+
+put_text_line_inline:
+ push $1 # convenience function
+ pop %ecx # for those only wanting 1 line of text
+put_text_inline:
+ lodsb # get color
+ mov %al,%bl
+ lodsw # then get x,y
+ call put_text_xy
+ loop put_text_inline
+ ret
+
+
+ #############################
+ # put_text_xy
+ #############################
+ # esi = string
+ # ah=x al=y
+ # bl=color
+
+ # ebx trashed esi points to end of string
+
+put_text_xy:
+ push %eax
+ push %ecx # edi_x_y destroys this
+ call mov_edi_x_y # point to x,y in framebuffer
+ pop %ecx
+p_loop:
+ lodsb # load char
+ cmp $0,%al # is it zero?
+ je p_done # if so we are done
+
+ push %eax
+ mov %bl,%al # output color
+ stosb
+ pop %eax
+ stosb # output character
+ jmp p_loop
+p_done:
+ pop %eax
+ ret
+
+ #######################
+ # get_char
+ #######################
+ #
+ # returns char in al. carry set if invalid
+ # eax,ebx,ecx,edx all trashed
+
+get_char:
+
+ push $SYSCALL_READ
+ pop %eax
+ xor %ebx,%ebx # stdin
+ mov $in_char,%ecx # in_char
+ push $1
+ pop %edx # try to read 1 byte
+ int $0x80
+
+ cmp $1,%eax
+ jl no_char
+
+ movb (in_char),%al
+ clc
+ ret
+no_char:
+ stc
+ ret
+
+
+ #######################
+ # get_a_char
+ #######################
+ # cooks up get_char for arrows and F keys
+ # carry set it invalid, or cooked char in al
+
+get_a_char:
+ call get_char # grab a character
+ jc get_a_char_unknown
+
+ cmp $27,%al # see if escape
+ jne get_a_char_over # if not we are done
+
+ call get_char # get another character
+ jnc extended_char
+
+ mov $'q',%al # if was just esc return q
+ jmp get_a_char_over
+
+extended_char:
+ cmp $'[',%al # check if was ^[[
+ jne get_a_char_unknown
+
+ call get_char # get yet another character
+ jc get_a_char_unknown
+check_up:
+ cmp $'A',%al
+ jne check_down
+ mov $'i',%al
+ jmp get_a_char_over
+
+check_down:
+ cmp $'B',%al
+ jne check_right
+ mov $'m',%al
+ jmp get_a_char_over
+
+check_right:
+ cmp $'C',%al
+ jne check_left
+ mov $'k',%al
+ jmp get_a_char_over
+
+check_left:
+ cmp $'D',%al
+ jne check_f1
+ mov $'j',%al
+ jmp get_a_char_over
+
+check_f1:
+ cmp $'[',%al
+ jne get_a_char_unknown
+ call get_char # get yet _another_ char
+ jc get_a_char_unknown
+ cmp $'A',%al
+ jne get_a_char_unknown
+ mov $'h',%al
+ jmp get_a_char_over
+get_a_char_over:
+ clc
+ ret
+
+get_a_char_unknown:
+ stc
+ ret
+
+
+
+
+ #######################
+ # put_attention_block
+ #######################
+ # color is in bl
+
+put_attention_block:
+ push $5
+ pop %eax # x=0 y=5
+ call mov_edi_x_y
+
+ mov $'*',%ah
+ mov %bl,%al
+
+ mov $(40*7),%ecx
+
+ rep
+ stosw
+
+ ret
+
+
+ ####################
+ # num_to_ascii
+ ####################
+ # eax = value to print
+ # edi points to where we want it
+ # ebx,ecx,edx trashed
+
+
+num_to_ascii:
+ push $10
+ pop %ebx
+ xor %ecx,%ecx # clear ecx
+ div_by_10:
+ cdq # clear edx
+ div %ebx # divide
+ push %edx # save for later
+ inc %ecx # add to length counter
+ or %eax,%eax # was Q zero?
+ jnz div_by_10 # if not divide again
+
+write_out:
+ pop %eax # restore in reverse order
+ add $0x30, %al # convert to ASCII
+ stosb # save digit
+ loop write_out # loop till done
+ ret
+
+ ##########################
+ # check_inside
+ ##########################
+ # see if line dh -> dl ovelaps bigger line ah -> al
+ # used as half of 2d rectangular collision detection
+ # carry flag set if true, unset if not
+check_inside:
+
+ cmp %ah,%dl
+ jl ar_not_in
+ cmp %al,%dl
+ jle inside
+ar_not_in:
+ cmp %ah,%dh
+ jl outside
+ cmp %al,%dh
+ jg outside
+inside:
+ stc
+ ret
+outside:
+ clc
+ ret
+
+
+ ########################
+ # play_sound
+ ########################
+ # ebx=freq(hertz) / duration (ms)
+play_sound:
+
+ ##########################
+ # To set frequency
+ # ESC[10;FFF] where FFF=frequency in hertz
+ ######################
+ # To set duration
+ # ESC[11;DDD] where DDD = Duration
+
+ mov $sound_buffer,%edi
+ push $'0'
+ pop %ecx
+
+freq_loop:
+ mov %cl,%al
+ shl $24,%eax
+ add $('1'<<16 + '['<<8 + 27),%eax
+ stosl
+
+ mov $';',%al
+ stosb
+
+ xor %eax,%eax
+ ror $16,%ebx
+ mov %bx,%ax
+
+ push %ebx
+ push %ecx
+ call num_to_ascii
+ pop %ecx
+ pop %ebx
+
+ mov $']',%al
+ stosb
+
+ inc %cl
+ cmp $'2',%cl
+ jne freq_loop
+
+ testb $SOUND,game_flags # Check if sound on
+ jz no_bell
+
+
+ ##################
+ # and ^G is BEL as always
+ mov $7,%al
+ stosb
+no_bell:
+ xor %al,%al
+ stosb # NUL string termination
+
+ mov $sound_buffer,%ecx
+
+ jmp write_stdout # cheat and jmp instead of call
+ # write_stdout will ret for us
+
+
+
+
+ #########################
+ # Load Hi Score
+ #########################
+ #
+load_hi_score:
+
+ call check_existing_hi_score
+
+ jnc done_load_hiscore # if invalid/no file, jump ahead
+
+ btl $29,%eax # is 4th char "S" or "s"?
+ jc hiscore_clear_sound # if "s" we turn off sound
+
+hiscore_set_sound:
+ orb $SOUND,game_flags # and turn on sound
+ jmp hiscore_get_initials
+
+hiscore_clear_sound:
+ andb $(~SOUND),game_flags # and turn off sound
+hiscore_get_initials:
+
+ movl hiscore_buffer+4,%eax # get 4 bytes
+ movl %eax,hi_player # first 3 are initials
+
+ movl hiscore_buffer+8,%eax # get next 4 bytes
+ movl %eax,hiscore # which is 32 bit int
+
+done_load_hiscore:
+ ret
+
+
+ #####################
+ # Check Existing Hi Score
+ #####################
+ # cf=1 if valid previously existing file
+ # cf=0 file problem
+ # dl=0 file not found
+ # d1=1 file_invalid
+
+check_existing_hi_score:
+
+ push $SYSCALL_OPEN
+ pop %eax
+ mov $score_file,%ebx # "/tmp/tb_asm.hsc"
+ xor %ecx,%ecx # 0 = O_RDONLY
+ cdq # clear edx
+ int $0x80
+
+ cmp $0,%eax # see if fd opened
+ jl file_not_found # if not, exit
+
+ mov %eax,%ebx # move fd to %ebx
+
+ push $SYSCALL_READ # read
+ pop %eax
+ mov $hiscore_buffer,%ecx # into hiscore_buffer
+ mov $12,%dx # 12 bytes
+ int $0x80
+
+ push %eax
+
+ call close_file # close the file
+
+ pop %eax
+
+ cmp $12,%eax # did we read 12 bytes?
+ jne invalid_file # if not, invalid
+
+ movl hiscore_buffer,%eax # get first 4 bytes into eax
+ cmp $('b'<<8 + 't'),%ax # are first 2 chars "tb"?
+ jne invalid_file # if not, close
+
+ stc # valid file
+ ret
+
+file_not_found:
+ xor %dl,%dl # file_not_found
+ jmp file_done
+invalid_file:
+ mov $1,%dl # invalid file
+file_done:
+ clc # file problem
+ ret
+
+
+ ###############################
+ # New High Score
+ ###############################
+ #
+
+new_hi_score:
+
+ mov $9,%bl
+ call put_attention_block # make a bright blue attention block
+
+ mov $new_high_line,%esi # output the high score directions
+ push $3
+ pop %ecx
+ call put_text_inline
+
+ xor %edx,%edx # we use dx as a counter
+ movl $('A'<<16+'A'<<8+'A'),hi_player
+ # clear the hi-score initials
+
+ hiscore_loop:
+ mov $menu_blank,%esi # clear the initials line
+ mov $15,%bl
+ mov $17,%ah
+ mov $10,%al
+ push %esi
+ call put_text_xy
+
+ pop %esi # clear the pointer line
+ inc %al # y=11
+ call put_text_xy
+
+ mov $hi_player,%esi # put the initials
+ inc %ah # x=18
+ dec %al # y=10
+ call put_text_xy
+
+ mov $menu_pointer,%esi # "^"
+ mov %dl,%ah # dl is x
+ add $18,%ah
+ inc %al # y=11
+ call put_text_xy
+
+ push %edx
+ call dump_to_screen # print to screen
+ pop %edx
+
+hiscore_get_char:
+ call hundred_usec_nanosleep # sleep so don't use all CPU
+ push %edx
+ call get_a_char # call get_a_char
+ pop %edx
+
+ jc hiscore_get_char # then loop
+
+hiscore_k:
+ cmp $'k',%al # were we a right?
+ jne hiscore_j # if not move on
+
+ inc %dl # x++
+ cmp $2,%dl # is x > 2?
+ jle hiscore_loop # if not keep going
+ mov $0,%dl # otherwise wrap so x=0
+
+hiscore_j:
+ cmp $'j',%al # are we left?
+ jne hiscore_i # if not move on
+
+ sub $1,%dl # x--
+ # is x < 0?
+ jns hiscore_loop # if not keep going
+ mov $2,%dl # otherwise wrap so x=2
+
+hiscore_i:
+ cmp $'i',%al # are we up?
+ jne hiscore_m # if not move on
+
+ movb hi_player(%edx),%bl # get initial
+ dec %bl # decrement
+ cmp $64,%bl # are we less than '@'?
+ jge write_initial
+ mov $126,%bl # if so wrap to '~'
+write_initial:
+ movb %bl,hi_player(%edx) # write back inital
+ jmp hiscore_loop
+
+hiscore_m:
+ cmp $'m',%al # are we down?
+ jne hiscore_enter # if not, move on
+
+ movb hi_player(%edx),%bl # get initial
+ inc %bl # incrememnt it
+ cmp $126,%bl # are we > "~"?
+ jle write_initial
+ mov $64,%bl # if so wrap to "@"
+ jmp write_initial
+
+hiscore_enter:
+ cmp $'\n',%al # once we hit enter we are done
+ jne hiscore_loop
+
+ ret
+
+ ######################
+ # Save Hi Score
+ ######################
+ # also saves sound on/off
+
+save_hi_score:
+ call check_existing_hi_score
+ jc ok_to_write
+
+ cmp $1,%dl # we won't write if invalid file
+ je done_save_hi # we will if ours, or not there
+
+ok_to_write:
+
+ push $SYSCALL_OPEN
+ pop %eax
+ mov $score_file,%ebx # "/tmp/tb_asm.hsc"
+ mov $(O_WRONLY|O_CREAT|O_TRUNC),%ecx
+ mov $(SIXSIXSIX),%edx
+ int $0x80
+
+ cmp $0,%eax # see if fd opened
+ jl done_save_hi # if not, exit
+
+ mov %eax,%ebx # save fd
+
+ movl $('s'<<24+'a'<<16+'b'<<8+'t'),%eax
+
+ testb $SOUND,game_flags
+ jz no_save_sound
+ btrl $29,%eax
+no_save_sound:
+
+ mov %eax,hiscore_buffer
+ movl hi_player,%eax
+ mov %eax,hiscore_buffer+4
+ movl hiscore,%eax
+ mov %eax,hiscore_buffer+8
+
+ push $SYSCALL_WRITE # put 4 in eax (write syscall)
+ pop %eax # in 3 bytes of code
+
+ mov $hiscore_buffer,%ecx
+ mov $12,%edx
+
+ int $0x80 # run the syscall
+
+ # cheat and run into close_file
+
+
+ #####################
+ # Close File
+ #####################
+ # fd=ebx
+
+close_file:
+ push $SYSCALL_CLOSE # close the file
+ pop %eax
+ int $0x80
+done_save_hi:
+ ret
+
+
+
+################################################
+# DATA SEGMENT
+################################################
+
+# .data
+
+.include "data.labels"
+data_compressed:
+.include "data.lzss"
+
+
+##################################################
+# BSS SEGMENT
+##################################################
+
+#.bss
+.lcomm text_buf, (N+F-1)
+.lcomm DATA_OFFSET, TB_DATA_SIZE
+
+ # +1 for any wrap-around blits
+.lcomm framebuffer, SCREEN_WIDTH*(SCREEN_HEIGHT+1)*BYTES_PER_PIXEL
+.lcomm out_buffer, SCREEN_WIDTH*(SCREEN_HEIGHT+5)*10
+
+.lcomm sound_buffer, 12
+.lcomm sound_freq, 4
+
+.lcomm hiscore_buffer, 16
+
+.lcomm in_char, 1
+
+.lcomm random_seed, 8
+
+.lcomm old_time, 8
+.lcomm time_of_day, 8
+
+.lcomm game_old_time, 8
+.lcomm game_time, 8
+
+
+.lcomm game_vars,1
+
+.lcomm x, 2
+.lcomm xadd, 2
+.lcomm scroll, 2
+.lcomm scroll_frames, 2
+
+.lcomm missile_0, 3*NUM_MISSILES # out,x,y
+.lcomm enemy_0, ENEMIES_SIZE*NUM_ENEMIES
+ # out,exploding,kind,xw,yw
+ # xadd,yadd,xmin,xmax
+
+
+.lcomm score, 4
+.lcomm score_string, 10
+.lcomm hiscore_string,10
+.lcomm level, 1
+.lcomm level_string, 10
+
+.lcomm shields, 1
+.lcomm shield_up_count, 1
+
+
+.lcomm total_enemies_out, 1
+
+# next bunch in order to smallen init code
+.lcomm enemies_spawned, 2
+.lcomm current_init_x, 2
+.lcomm current_enemy_kind, 1
+.lcomm enemy_wait, 1
+.lcomm current_enemy_type, 1
+.lcomm enemy_wave, 1
+
+
+.lcomm between_enemy_delay,1
+.lcomm waves_till_boss,1
+
+
+# FIXME move some of these to be flags?
+.lcomm boss_x,2
+.lcomm boss_xadd,2
+.lcomm boss_count,2
+.lcomm boss_smoke,1
+.lcomm boss_exploding,1
+.lcomm boss_waiting,1
+.lcomm boss_hits,1
+.lcomm boss_shooting,1
+
+.lcomm background,1600
+
+.lcomm end_game_vars,1
+
+
+# From ~/linux/include/asm/termbits.h
+# struct termios {
+# unsigned int c_iflag; /* input mode flags */
+# unsigned int c_oflag; /* output mode flags */
+# unsigned int c_cflag; /* control mode flags */
+# unsigned int c_lflag; /* local mode flags */
+# unsigned char c_line; /* line discipline */
+# unsigned char c_cc[19]; /* control characters */
+# };
+
+.lcomm old_tty 40
+.lcomm new_tty 40
diff --git a/tb_asm/xpm/boss.xpm b/tb_asm/xpm/boss.xpm
new file mode 100644
index 0000000..eb43442
--- /dev/null
+++ b/tb_asm/xpm/boss.xpm
@@ -0,0 +1,35 @@
+/* XPM */
+static char * boss_xpm[] = {
+"40 20 12 1",
+" c None",
+". c #000000",
+"+ c #FC54FC",
+"@ c #A800A8",
+"# c #A8A8A8",
+"$ c #545454",
+"% c #FC5454",
+"& c #A80000",
+"* c #FCFCFC",
+"= c #00A8A8",
+"- c #54FCFC",
+"; c #FCFC54",
+"....$#$.......*#&%%%%%%%*.............",
+"....#$#.......*$#&&=-=&$*.............",
+"..............*.$#=-;-=#$.*.............",
+"..............+...........+.............",
+"..............@...........@.............",
+"..............+...........+.............",
+"..............@...........@.............",
+"..............+...........+.............",
+"..............@...........@.............",
+"..............+...........+.............",
+"..............@...........@.............",
+"..............+...........+.............",
+"..............@...........@.............",
+"..............+...........+.............",
+"..............@...........@.............",
+"..............+...........+.............",
+"..............@...........@.............",
+"..............+...........+.............",
+"..............@...........@.............",
+"..............+...........+............."};
diff --git a/tb_asm/xpm/default.xpm b/tb_asm/xpm/default.xpm
new file mode 100644
index 0000000..10872f5
--- /dev/null
+++ b/tb_asm/xpm/default.xpm
@@ -0,0 +1,40 @@
+/* XPM */
+static char * default_xpm[] = {
+"40 20 17 1",
+" c None",
+"0 c #000000",
+"1 c #0000A8",
+"2 c #00A800",
+"3 c #00A8A8",
+"4 c #A80000",
+"5 c #A800A8",
+"6 c #A85400",
+"7 c #A8A8A8",
+"8 c #545454",
+"9 c #5454FC",
+"A c #54FC54",
+"B c #54FCFC",
+"C c #FC5454",
+"D c #FC54FC",
+"E c #FCFC54",
+"F c #FCFCFC",
+"0123456789ABCDEF000000000000000000000000",
+"0000000000000000000000000000000000000000",
+"0000000000000000000000000000000000000000",
+"0000000000000000000000000000000000000000",
+"0000000000000000000000000000000000000000",
+"0000000000000000000000000000000000000000",
+"0000000000000000000000000000000000000000",
+"0000000000000000000000000000000000000000",
+"0000000000000000000000000000000000000000",
+"0000000000000000000000000000000000000000",
+"0000000000000000000000000000000000000000",
+"0000000000000000000000000000000000000000",
+"0000000000000000000000000000000000000000",
+"0000000000000000000000000000000000000000",
+"0000000000000000000000000000000000000000",
+"0000000000000000000000000000000000000000",
+"0000000000000000000000000000000000000000",
+"0000000000000000000000000000000000000000",
+"0000000000000000000000000000000000000000",
+"0000000000000000000000000000000000000000"};
diff --git a/tb_asm/xpm/ending.xpm b/tb_asm/xpm/ending.xpm
new file mode 100644
index 0000000..2e18423
--- /dev/null
+++ b/tb_asm/xpm/ending.xpm
@@ -0,0 +1,35 @@
+/* XPM */
+static char * ending_xpm[] = {
+"40 20 12 1",
+" c None",
+". c #000000",
+"+ c #A8A8A8",
+"@ c #5454FC",
+"# c #0000A8",
+"$ c #545454",
+"% c #54FC54",
+"& c #FCFCFC",
+"* c #00A8A8",
+"= c #54FCFC",
+"- c #00A800",
+"; c #A80000",
+"...###@@............+&&.................",
+"...#..$@...........-%%@@................",
+"...#..$@...........#%@@@................",
+"...#..$@...........#@%%@................",
+"...#..$@...........#@%@@................",
+"....##@.............+&&.................",
+"..####@@@@..............................",
+"..#@##@;#@..............................",
+"..#@##@@#@...+++++++++++++++++++........",
+"..#@##@@#@...+++++++++++$.&&.+++........",
+"..#@##@@#@...++.........$..$..++........",
+"..#@##@@#@...+.................+........",
+"..*=#@#@*=...+.................+........",
+"....#@#@.....+...............+++........",
+"....#@#@.....++............+++++........",
+"....#@#@.....++++$$$+++++$$$++++........",
+"....*=*=................................",
+"....$+$+................................",
+"........................................",
+"........................................"};
diff --git a/tb_asm/xpm/missile.xpm b/tb_asm/xpm/missile.xpm
new file mode 100644
index 0000000..9da8c7f
--- /dev/null
+++ b/tb_asm/xpm/missile.xpm
@@ -0,0 +1,40 @@
+/* XPM */
+static char * missile_xpm[] = {
+"40 20 17 1",
+" c None",
+". c #000000",
+"+ c #A8A8A8",
+"@ c #FCFCFC",
+"# c #FCFC54",
+"$ c #5454FC",
+"% c #A80000",
+"& c #545454",
+"* c #00A800",
+"= c #A85400",
+"- c #FC5454",
+"; c #00A8A8",
+"> c #54FC54",
+", c #0000A8",
+"' c #A800A8",
+") c #54FCFC",
+"! c #FC54FC",
+".,*;#'=+&$>)-!#@........................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"....+..........@@%...$.$...##-..........",
+"....+..........@@@....$....-#&..........",
+"....+...................................",
+"...%%%.........*>*...;==...++%..........",
+"....#..........*>*...;==...%+...........",
+"........................................",
+".........+......#....-@@...&&...........",
+".........+.....#.#...-++....&&..........",
+".........#..............................",
+"..............$$$.......................",
+".............+@@@+......................",
+"............++@+@++.....................",
+"...............#........................"};
diff --git a/tb_asm/xpm/opener.xpm b/tb_asm/xpm/opener.xpm
new file mode 100644
index 0000000..dda6340
--- /dev/null
+++ b/tb_asm/xpm/opener.xpm
@@ -0,0 +1,38 @@
+/* XPM */
+static char * opener_xpm[] = {
+"40 20 15 1",
+" c None",
+". c #0000A8",
+"+ c #54FCFC",
+"@ c #00A8A8",
+"# c #FC5454",
+"$ c #000000",
+"% c #A8A8A8",
+"& c #FCFCFC",
+"* c #545454",
+"= c #00FCFC",
+"- c #FCFC00",
+"; c #A80000",
+"> c #0000FC",
+", c #FC0000",
+"' c #00A800",
+"...+...+.+++.@##@@###@#@@@#@##@@##@#@@@#",
+"+.++.+.+..+..@#@#@#@#@##@##@#@#@#@@##@##",
+"+.++.+.+.+.+.@##@@#@#@#@#@#@##@@##@#@#@#",
+"+.++.+.+.+++.@#@#@#@#@#@@@#@#@#@#@@#@@@#",
+"+.++...+.+++.@##@@###@#@@@#@##@@##@#@@@#",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$$%$$$$$$$$$$%$$$",
+"$$$%$$$$$$$&$$$$$$$$$$$$$$$$$$$*$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$%$$$$$$$$$$*$$$$$$$$$$$$&$$$$$$$$$$",
+"$$$$$%%$$$$$$$$$$$$$$$%$$$$$$$$$$$$$=$$$",
+"$-$$$%%%$$$$$$$$$$$$$$$$$$$$$$$$$$$$$=;;",
+"$--->&&&&&&&&>>>$$$$$$$$$$$$$$$$$$$$$=,,",
+"--;,.&;'.'.&&>>>>$$$$$$$$$$$$$$$$$$$=$,,",
+"$--,>&;'.'.&&>>>>>$$$$$$;$$$$$$$$$$$$$,,",
+"$$$-.%%%%%%%%&&&&&&$$$$-%%%%$$$$$$$$$$,,",
+"$$$$$$$$$$$$$$$$$$$$$$$$;$$$$$$$$&$$$$;;",
+"$$$$*$$$$$%$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$&$$$$$$$$$$$$$$$&$$$$$$$$$*$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%$"};
diff --git a/tb_asm/xpm/phobos.xpm b/tb_asm/xpm/phobos.xpm
new file mode 100644
index 0000000..cdf3ef9
--- /dev/null
+++ b/tb_asm/xpm/phobos.xpm
@@ -0,0 +1,33 @@
+/* XPM */
+static char * phobos_xpm[] = {
+"40 20 10 1",
+" c None",
+". c #000000",
+"+ c #FC0000",
+"@ c #FCFCFC",
+"# c #A80000",
+"$ c #A8A8A8",
+"% c #00A8A8",
+"& c #A85400",
+"* c #545454",
+"= c #00FCFC",
+"........................................",
+"..................$.....................",
+"....................................@...",
+"........................................",
+".....$@@@@..............................",
+"....#++++++..............@..............",
+"...#+++++#++............................",
+"...#++++++++............................",
+"...#+++#++++.....*&.....................",
+"...#++++++++.....&......................",
+"...#+++++#++...................@........",
+"....#++++++...............$.............",
+".....$@@@@..............................",
+"........................................",
+"........................................",
+"...@.............$............$.........",
+"........................................",
+".%=%....................................",
+"........................................",
+"........................................"};
diff --git a/tb_asm/xpm/tom.xpm b/tb_asm/xpm/tom.xpm
new file mode 100644
index 0000000..ecb83a7
--- /dev/null
+++ b/tb_asm/xpm/tom.xpm
@@ -0,0 +1,32 @@
+/* XPM */
+static char * tom_xpm[] = {
+"40 20 9 1",
+" c None",
+". c #000000",
+"+ c #0000A8",
+"@ c #0000FC",
+"# c #545454",
+"$ c #00A8A8",
+"% c #00FCFC",
+"& c #A8A8A8",
+"* c #FC0000",
+"...+++@@................................",
+"...+..#@................................",
+"...+..#@................................",
+"...+..#@................................",
+"...+..#@................................",
+"....++@.................................",
+"..++++@@@@..............................",
+"..+@++@*+@..............................",
+"..+@++@@+@..............................",
+"..+@++@@+@..............................",
+"..+@++@@+@..............................",
+"..+@++@@+@..............................",
+"..$%+@+@$%..............................",
+"....+@+@................................",
+"....+@+@................................",
+"....+@+@................................",
+"....$%$%................................",
+"....#&................................",
+"........................................",
+"........................................"};
diff --git a/tb_asm/xpm/vince_minimal.xpm b/tb_asm/xpm/vince_minimal.xpm
new file mode 100644
index 0000000..f0f8632
--- /dev/null
+++ b/tb_asm/xpm/vince_minimal.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static char * vince_minimal_xpm[] = {
+"16 20 5 1",
+" c None",
+". c #000000",
+"+ c #A8A8A8",
+"@ c #545454",
+"# c #FCFCFC",
+"..@########@....",
+".@+####+####++..",
+"@+++++@+#++###+.",
+"+@.@+++########@",
+"+.@############+",
+"@.+#######+#++@@",
+"@@#########@@.@+",
+"@+####+###+.@.@+",
+"+@@+#@.@+#+....@",
+".+.@#..@.@#@...@",
+".+@+#@..+##+...+",
+".#@###++####...+",
+".#+@@+#####@@@++",
+".##@.+####+.+++.",
+".##+@++###+.++@.",
+".++.@..++..#@+..",
+".@##@##+..@++@..",
+"..#+++#++@@#+...",
+"..+####@@.@#@...",
+"...@@.....+#@..."};
diff --git a/tb_asm/xpm/vmwsoft_orig.xpm b/tb_asm/xpm/vmwsoft_orig.xpm
new file mode 100644
index 0000000..a935d3a
--- /dev/null
+++ b/tb_asm/xpm/vmwsoft_orig.xpm
@@ -0,0 +1,40 @@
+/* XPM */
+static char * vmwsoft_xpm[] = {
+"40 20 17 1",
+" c None",
+". c #000000",
+"+ c #0000A8",
+"@ c #00A800",
+"# c #00A8A8",
+"$ c #A80000",
+"% c #A800A8",
+"& c #A85400",
+"* c #A8A8A8",
+"= c #545454",
+"- c #5454FC",
+"; c #54FC54",
+"> c #54FCFC",
+", c #FC5454",
+"' c #FC54FC",
+") c #FCFC54",
+"! c #FCFCFC",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........$$$$$$$@+++++++@+++++++.........",
+"........$$$$$$$@+++++++@+++++++.........",
+".........$$$$$@@@+++++@@@+++++..........",
+".........$$$$$@@@+++++@@@+++++..........",
+"..........$$$@@@@@+++@@@@@+++...........",
+"..........$$$@@@@@+++@@@@@+++...........",
+"...........$@@@@@@@+@@@@@@@+............",
+"...........$@@@@@@@+@@@@@@@+............",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................"};