TIGCC Programming Lessons
The following is part of a series of lessons designed to help teach
people to program in C for the TI-89, 92+, and V200 calculators
using the TIGCC development environment.
If you wish, you can download the program source code, project
files, and binaries
here.
Review 3: Intro to Graduate Programming, part 1
Step 1 - Background and Introduction
Welcome to graduate programming, part 1. This lesson will mark your
conclusion from beginning programming and allow you to basically code
nearly anything you want, so long as you put a little effort into it.
After you finish this lesson (provided you have finished or understand
all the previous lessons), you will have the necessary skills to do any
kind of programming for this platform that you wish. Furthermore, you
will be able to use most of these skills to program for other platforms,
so, good luck to you first off.
This is a very special lesson, for the reason I mentioned above, and for
one more. It marks the completion of my goal with Techno-Plaza. From
roughly September 1998, I have worked to build a web site geared towards
the TI-89, and later, towards teaching people to program with the TI-89.
My idea at first seemed simple: take all the confusing or non-existent
crap out there on the various TI sites regarding 68k programming and
condense it into a useful, complete resource for people that wanted to
learn how to program their calculator. I never imagined that task would
take so long.
Although I will try to digress, I want to mark this occasion. I didn't
have the benefit of a beginner's programming site, or TIGCC library
docs, or even a GUI IDE to program in. None of those things existed in
1998. But, I did have a few things. A TI-89, plusshell (the first kernel
for TI-89, which made assembly programming possible), the Fargo docs
(from the TI-92 kernel Fargo, which essentially served as a template for
programming on the TI-89/92+), and a very well designed, if badly
commented source code to a simple game, Nibbles. Before my TI-89, I had
a TI-92. Since not many people had a TI-92, there were not a lot of
games written for the platform. There were a few, but only a few good
ones. Nibbles was one of these. I thought about programming my TI-92. It
looked interesting, and might even be fun. So I tried to learn how to do
it. I realized there were no docs for such things. Aside from a few tech
manuals which assumed a lot about your knowledge, there were few
resources to learn. I decided to put off this project. Too much work.
Learning an entire language with next to no documentation. Nevermind.
However, after I got my TI-89, TI promised they would have built-in
assembly language program support. We wouldn't be forced to hack into
the OS to see how it works to get programs we wanted to run. TI lied.
Well, maybe that's too harsh, they simply postponed their work for so
long by the time it was out, we already developed our own stuff. A few
months after the TI-89 was released, and we all realized TI didn't have
any plans for rolling out assembly support, someone named Rusty Wagner
(author of the venerable albeit now defunt Virtual TI) released a
program called PlusShel. PlusShel, based on the Fargo sources since the
TI-89 was basically an enhanced TI-92 with a smaller screen. At last,
assembly program support was realized. Just one problem. There were no
programs to be run. Great. We have a way to run programs, but no
programs to run. Ah, (and I'll wrap this up soon I promise), here is
where I come in. :-) (I know you all can't wait for this. :-)
My mission: to bring the first TI-89 game to the public! Only one
problem, I still only had a basic idea of how to program the TI-92.
Luckily, I didn't need much knowledge for what I had to do; be first!
That was the only important thing (at the time). So, I grabbed Jimmy
Mardell's guide to 68000 programming and started looking at what the
Nibbles source code could mean. Due to a very handy fact of the program,
I only had to change the level definitions, and the arrow key keycodes
to get the program to run on the TI-89. Success! Nibbles 68k was the
first assembly program released for the TI-89! I checked ticalc.org and
the ti-files (which was once another large archive site before it
disappeared). Nobody got anything on before I did, so I'm calling it the
first.
Now, here comes Techno-Plaza. Knowing as little as I did about 68k
programming, I decided what was needed was to learn more about it. Using
the source code to Nibbles (which was later heavily modified to work
better, and rewritten a few times) to learn, and Jimmy Mardell's guide
(along with some other sources including the PlusShel docs and some docs
by Mathieu Lacage), I learned to program 68k fairly decent in about a
month.
But that month sucked. It was hard to figure out what all these things
meant. The docs I was reading were so poor. They basically assumed that
anyone reading them knew as much as they did. And, via trial and error,
you eventually did. That's not my idea of a good thing though. My idea
was to use the Nibbles source code (fully commented) to teach others how
to program in 68k assembly.
Unfortunately, the Nibbles source code was large. There were many parts,
and it would take a long time to explain everything so that people (and
my target audience is ANYONE who wants to program) would understand the
way I do (and NOT doing what the other authors had done, by
oversimplifying things, or glazing over things that seem trivial, but
are actually important). I quickly realized that a Nibbles programming
lesson would be very advanced.
So, not much left to digress from, but nonetheless I do, the founding
and developing of Techno-Plaza. And, after nearly 4 years, I am finally
ready to teach my first idea, programming using the Nibbles source code.
Although, the source bears no resemblance to the original source, the
idea is still good in principal.
My 'improved' version of Nibbles is written in C, not 68k assembly, and
has many features that did not exist in the original game: difficulty
levels, score, um, okay, I guess it's just the two things, but they're
important things. So, now that I am finally ending this long intro,
let's begin examining the source code to Nibbles 68k v4.2.
Step 2 - The Nibbles Project Source Code
Start TIGCC and begin a new project. We will be creating four source
files and 2 header files. This is a large project. Name the source files
nibbles, hiscore, gfx, and gameplay. Name the two header files nibbles
and gfx. Here is the code for the files.
nibbles.c
/*
* Nibbles 68k v. 4.2 -- Nibbles Snake Game Clone
* Copyright (C) 2000-2002,2007 John David Ratliff
* Based on Stilgar's Nibbles for Fargo
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "nibbles.h"
#include <graph.h>
#include <kbd.h>
#include <stdlib.h>
INT_HANDLER autoint1, autoint5;
// doIntro - display the game intro and wait for menu selections
// returns FALSE if user selects exit, TRUE otherwise
short int doIntro(short int *gamespeed, short int *gamedifficulty) {
short int selector = MENUSTART, done = FALSE, key, options = FALSE, selection = 0;
short int speed = *gamespeed, difficulty = *gamedifficulty;
// clear the screen
ClrScr();
// draw the intro screen
drawBorder();
drawLogo();
drawMenu();
drawCopyright();
drawSelector(selector);
while (!done) {
// wait for keypress
while ((key = getKey()) == 0);
if (key == KUP) {
// move up the menu
drawSelector(selector);
if (selector == MENUSTART) {
selector = MENUEND;
} else {
selector -= MENUSTEP;
}
drawSelector(selector);
} else if (key == KDOWN) {
// move down the menu
drawSelector(selector);
if (selector == MENUEND) {
selector = MENUSTART;
} else {
selector += MENUSTEP;
}
drawSelector(selector);
} else if (key == KLEFT) {
if (options) {
// if we are in the options menu
selection = (selector - MENUSTART) / MENUSTEP;
// set the speed option
if (selection == START) {
// same as speed option -- option 1 == SPEED
drawSpeedOption(speed);
if (speed == VERYSLOW) {
speed = VERYFAST;
} else {
speed--;
}
drawSpeedOption(speed);
// set the difficulty option
} else if (selection == OPTIONS) {
// same as difficulty option -- option 2 == DIFFICULTY
drawDifficultyOption(difficulty);
if (difficulty == EASY) {
difficulty = HARD;
} else {
difficulty--;
}
drawDifficultyOption(difficulty);
}
}
} else if (key == KENTER || key == KRIGHT) {
// select menu option
selection = (selector - MENUSTART) / MENUSTEP;
if (options) {
// if we're in the options menu
// exit the options menu
if (selection == QUIT) {
// close options menu
options = FALSE;
// switch the options and main menus
drawOptionsMenu(speed,difficulty);
drawMenu();
// reset the selector
drawSelector(selector);
selector = MENUSTART;
drawSelector(selector);
} else if (selection == START) {
// same as speed option -- option 1 == SPEED
drawSpeedOption(speed);
if (speed == VERYFAST) {
speed = VERYSLOW;
} else {
speed++;
}
drawSpeedOption(speed);
} else if (selection == OPTIONS) {
// same as difficulty option -- option 2 == DIFFICULTY
drawDifficultyOption(difficulty);
if (difficulty == HARD) {
difficulty = EASY;
} else {
difficulty++;
}
drawDifficultyOption(difficulty);
}
} else {
// if we chose to start or exit, end the loop
if (selection == START || selection == QUIT) {
done = TRUE;
} else {
// enter the options menu
options = TRUE;
// switch the main and options menus
drawMenu();
drawOptionsMenu(speed,difficulty);
// reset the selector
drawSelector(selector);
selector = MENUSTART;
drawSelector(selector);
}
}
} else if (key == KESC) {
// exit the options menu
if (options) {
// close options menu
options = FALSE;
// switch the options and main menus
drawOptionsMenu(speed,difficulty);
drawMenu();
// reset the selector
drawSelector(selector);
selector = MENUSTART;
drawSelector(selector);
} else {
selection = QUIT;
done = TRUE;
}
}
// wait for keypress to dissipate
delay(KEYDELAY);
}
// set the game options
*gamespeed = speed;
*gamedifficulty = difficulty;
return (selection == START) ? TRUE : FALSE;
}
void _main(void) {
short int font = FontGetSys(), speed = AVERAGE, difficulty = NORMAL;
// Save the auto-interrupts
autoint1 = GetIntVec(AUTO_INT_1);
autoint5 = GetIntVec(AUTO_INT_5);
// create the hiscore file, if it doesn't exist
if (needScoreFile()) {
createHiScoreTable();
}
// Make sure there are no keystrokes left in the buffer
GKeyFlush();
// setup medium size font
FontSetSys(F_6x8);
// seed the random number generator
randomize();
// redirect auto-interrupts 1 and 5
SetIntVec(AUTO_INT_1,DUMMY_HANDLER);
SetIntVec(AUTO_INT_5,DUMMY_HANDLER);
// keep playing until doIntro returns FALSE (exit)
while (doIntro(&speed,&difficulty)) {
play(speed,difficulty);
}
// restore auto-interrupts
SetIntVec(AUTO_INT_1,autoint1);
SetIntVec(AUTO_INT_5,autoint5);
// restore the standard font
FontSetSys(font);
}
hiscore.c
/*
* Nibbles 68k v. 4.2 -- Nibbles Snake Game Clone
* Copyright (C) 2000-2002,2007 John David Ratliff
* Based on Stilgar's Nibbles for Fargo
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "nibbles.h"
#include <args.h>
#include <stdio.h>
#include <string.h>
// the high score file data
static const char *scorefile = "nibblehi";
// loadHiScores - loads the hiscores from file into the hiscore table
// returns TRUE if hiscores were read, FALSE otherwise
short int loadHiScores(SCORE *hiscores) {
short int success = TRUE;
FILE *f;
// open file for reading and check for errors
if ((f = fopen(scorefile,"rb")) == NULL) {
success = FALSE;
} else {
// read the hiscore table and check for I/O errors
if (fread(hiscores,sizeof(SCORE),MAX_HISCORES,f) != MAX_HISCORES) {
success = FALSE;
}
fclose(f);
}
return success;
}
// saveHiScores - saves the hiscore table to the hiscore file
// returns TRUE if the scores were saved to file, FALSE otherwise
short int saveHiScores(SCORE *hiscores) {
const char *filetype = "N68K";
short int success = TRUE;
FILE *f;
// delete any old scorefile before recreating
unlink(scorefile);
// open the hiscore file
if ((f = fopen(scorefile,"wb")) == NULL) {
success = FALSE;
} else {
// write the hiscore table to disk - check for I/O errors
if (fwrite(hiscores,sizeof(SCORE),MAX_HISCORES,f) != MAX_HISCORES) {
success = FALSE;
}
// write the file tag
fputc(0,f);
fputs(filetype,f);
fputc(0,f);
fputc(OTH_TAG,f);
fclose(f);
}
return success;
}
// createHiScoreTable - create a blank hiscore table and write it to file
// return the result of the disk save
short int createHiScoreTable(void) {
SCORE board[MAX_HISCORES];
// set all the entries in the table to blank
memset(board,0,sizeof(SCORE) * MAX_HISCORES);
return (saveHiScores(board));
}
// needScoreFile - checks whether a hiscore file already exists
// returns TRUE if there is no hiscore file, FALSE otherwise
short int needScoreFile(void) {
FILE *f = fopen(scorefile,"rb");
short int needed = FALSE;
// if we cannot open the file, we must need to create it
if (f == NULL) {
needed = TRUE;
} else {
fclose(f);
}
return needed;
}
gfx.c
/*
* Nibbles 68k v. 4.2 -- Nibbles Snake Game Clone
* Copyright (C) 2000-2002,2007 John David Ratliff
* Based on Stilgar's Nibbles for Fargo
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "nibbles.h"
#include "gfx.h"
#include <alloc.h>
#include <dialogs.h>
#include <graph.h>
#include <kbd.h>
#include <sprites.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// centerText - draws a string at the horizontal center of line y
inline void centerText(const char *str, short int y) {
short int len = (short int)strlen(str), x = ((160 - (len * 6)) / 2);
DrawStr(x,y,(char *)str,A_XOR);
}
// drawBorder - draws four lines making a box around the screen
inline void drawBorder(void) {
DrawLine(X1,Y1,X2,Y2,A_NORMAL);
DrawLine(X3,Y3,X4,Y4,A_NORMAL);
DrawLine(X5,Y5,X6,Y6,A_NORMAL);
DrawLine(X7,Y7,X8,Y8,A_NORMAL);
}
// drawLogo - draws the Nibbles 68k logo across the top of the screen
void drawLogo(void) {
short int loop, offset = 0;
// draw the logo pieces
for (loop = 0; loop < (LOGOTILES * LOGOWIDTH); loop+=LOGOWIDTH) {
Sprite32(loop,0,LOGOHEIGHT,logo+offset,LCD_MEM,SPRT_XOR);
offset += LOGOHEIGHT;
}
}
// drawSelector - draws the menu selector bar over the menu options
void drawSelector(short int y) {
short int loop, offset = 0;
// draw the selector pieces
for (loop = 0; loop < (SELECTORTILES * SELECTORWIDTH); loop+=SELECTORWIDTH) {
Sprite32(loop,y,SELECTORHEIGHT,selector+offset,LCD_MEM,SPRT_XOR);
offset += SELECTORHEIGHT;
}
}
// drawCopyright - prints the copyright notice at the bottom of the screen
inline void drawCopyright(void) {
FontSetSys(F_4x6);
DrawStr(COPYX,COPYY,(char *)intro[COPYRIGHT],A_XOR);
DrawStr(URLX,URLY,(char *)intro[URL],A_XOR);
FontSetSys(F_6x8);
}
// drawMenu - displays the game menu
void drawMenu(void) {
short int loop;
// draw the three menu selections
for (loop = START; loop <= QUIT; loop++) {
centerText(intro[loop],MENUSTART+(loop*MENUSTEP));
}
}
// drawSpeedOption - draws the speed setting (i.e. slow, fast, average)
void drawSpeedOption(short int speed) {
char speedStr[25];
// truncate to 0-length
speedStr[0] = 0;
// create the speed string
strcat(speedStr,intro[SPEED]);
strcat(speedStr,speeds[speed]);
// display the string
centerText((const char *)speedStr,MENUSTART);
}
// drawDifficultyOption - draws the difficulty setting (i.e. easy, hard, medium)
void drawDifficultyOption(short int difficulty) {
char difficultyStr[25];
// truncate to 0-length
difficultyStr[0] = 0;
// create the difficulty string
strcat(difficultyStr,intro[DIFFICULTY]);
strcat(difficultyStr,difficulties[difficulty]);
// display the string
centerText((const char *)difficultyStr,MENUSTART+MENUSTEP);
}
// drawOptionsMenu - draws the options menu items
inline void drawOptionsMenu(short int speed, short int difficulty) {
drawSpeedOption(speed);
drawDifficultyOption(difficulty);
centerText(intro[QUITOPTIONS],MENUSTART+(2*MENUSTEP));
}
// drawBlock - draws a block on the screen (all nibble graphics are composed of blocks)
inline void drawBlock(short int x, short int y, unsigned char *sprite, short int mode) {
Sprite8(x,y,HEIGHT,sprite,LCD_MEM,mode);
}
// drawToken - draws a life or apple token at (x,y)
inline void drawToken(short int x, short int y, unsigned char *sprite) {
Sprite8(x,y,TOKEN_HEIGHT,sprite,LCD_MEM,SPRT_XOR);
}
// drawScore - draws the current player score at the lower-left
inline void drawScore(unsigned long int score) {
printf_xy(SCOREX,SCOREY,"%lu",score);
}
// drawEndMessage - draws the message at games end (i.e. winner, loser, quitter)
void drawEndMessage(short int ending) {
short int x, offset = 0;
unsigned short int *sprite = endings[--ending];
for (x = 8; x < 152; x += 16) {
Sprite16(x,38,25,sprite+offset,LCD_MEM,SPRT_AND);
Sprite16(x,38,25,sprite+offset,LCD_MEM,SPRT_OR);
offset += 25;
}
}
// drawCrash - draws the crash message across the screen
void drawCrash(void) {
short int x, offset = 0;
for (x = 0; x < CRASHWIDTH; x += 32) {
Sprite32(CRASHX+x,CRASHY,CRASHHEIGHT,crash+offset,LCD_MEM,SPRT_AND);
Sprite32(CRASHX+x,CRASHY,CRASHHEIGHT,crash+offset,LCD_MEM,SPRT_OR);
offset+=CRASHHEIGHT;
}
// wait for keypress
delay(KEYDELAY);
while (!getKey());
delay(KEYDELAY);
}
// drawLives - displays the life indicator using life tokens
void drawLives(short int lives) {
short int loop, x = 76, max = lives;
if (max > MAX_LIVES) {
max = MAX_LIVES;
}
// draw a life token for each remaining life
for (loop = 0; loop < max; loop++) {
x+=4;
drawToken(x,97,lifeToken);
x++;
}
}
// drawApples - displays remaining apples using apple tokens
void drawApples(short int apples) {
short int loop, x = 76;
// draw one apple token for each remaining apple
for (loop = 0; loop < apples; loop++) {
x+=4;
drawToken(x,94,appleToken);
x++;
}
}
// drawApple - draws an apple on screen at a randomly selected location
// returns - the position of the newly drawn apple
POSITION drawApple(short int level, SNAKE *snake) {
POSITION pos = {0,0};
// find a suitable random position for the apple
while (hasHitWall(pos,level) || hasHitSnake(pos,snake,SNAKE_HIT_APPLE)) {
pos.x = random(XTILES);
pos.y = random(YTILES);
}
// draw the apple sprite
drawBlock(pos.x * WIDTH, pos.y * HEIGHT, apple, SPRT_XOR);
// return the apple's position
return pos;
}
// eraseApple - erases an apple token indicating an apple has just been eaten
inline void eraseApple(short int apples) {
drawToken(76+4+apples*4+apples,94,appleToken);
}
// drawSnake - draws the snake on the LCD
void drawSnake(SNAKE *snake) {
POSITION pos;
short int loop;
// draw the snake segments
for (loop = 0; loop < snake->length; loop++) {
pos = snake->location[loop];
drawBlock(pos.x * WIDTH, pos.y * HEIGHT, block, SPRT_OR);
}
// remove the last segment to create the illusion of movement
pos = snake->location[snake->length];
if (pos.x != 0 && pos.y != 0) {
drawBlock(pos.x * WIDTH, pos.y * HEIGHT, empty, SPRT_AND);
}
}
// clearDisplayLine - removes the bottom 3 lines of the bottom border
// for extra indicator display room
void clearDisplayLine(void) {
short int loop;
for (loop = 92; loop < 95; loop++) {
DrawLine(0,loop,160,loop,A_REVERSE);
}
}
// drawLevel - draws one of the maze levels
void drawLevel(short int level) {
short int yLoop,xLoop;
long int area, mask;
// clear the screen first
ClrScr();
for (yLoop = 0; yLoop < YTILES; yLoop++) {
area = levels[level][yLoop];
mask = 0x100000;
// start the x loop
for (xLoop = 0; xLoop < XTILES; xLoop++) {
// shift the mask index
mask >>= 1;
// if the level data says to put a block here, then do it
if (area & mask) {
drawBlock(xLoop * WIDTH, yLoop * HEIGHT, block, SPRT_OR);
}
}
}
// share the bottom line of the maze
clearDisplayLine();
}
// drawHiScoreBoard - draws the hiscore board, and updates it with the hiscore from the latest game
void drawHiScoreBoard(unsigned long int newscore) {
SCORE scores[MAX_HISCORES];
short int loop, pos = -1;
char name[10], str[50];
const char *error = "File I/O Error";
HANDLE dlg;
// restore auto-interrupts
SetIntVec(AUTO_INT_1,autoint1);
SetIntVec(AUTO_INT_5,autoint5);
if (!loadHiScores(scores)) {
// cannot open hiscore file -- display error
DlgMessage(error,"Unable to Load HiScore Data",BT_OK,BT_NONE);
return;
}
// check if latest score is a highscore
for (loop = (MAX_HISCORES - 1); loop >= 0; loop--) {
if (newscore > scores[loop].score) {
// new HiScore!!
pos = loop;
}
}
if (pos != -1) {
// if we found a new hiscore
if ((dlg = DialogNewSimple(DLGWIDTH,DLGHEIGHT)) == H_NULL) {
DlgMessage("Memory Allocation Error","Not Enough Free Memory!",BT_OK,BT_NONE);
} else {
DialogAddTitle(dlg,"New Hiscore!",BT_OK,BT_NONE);
DialogAddRequest(dlg,5,25,"Your Name:",0,9,11);
sprintf(str,"You earned the #%hd hiscore position!",pos+1);
DialogAddText(dlg,5,15,str);
do {
// truncate name variable
name[0] = 0;
} while (DialogDo(dlg,CENTER,CENTER,name,NULL) != KEY_ENTER);
// free the dialog box memory
HeapFree(dlg);
// move the hiscore list down
if (pos < (MAX_HISCORES - 1)) {
for (loop = (MAX_HISCORES - 1); loop > pos; loop--) {
scores[loop].score = scores[loop - 1].score;
scores[loop].name[0] = 0;
strcpy(scores[loop].name,scores[loop - 1].name);
}
}
// fill in the new hiscore
scores[pos].score = newscore;
scores[pos].name[0] = 0;
strcpy(scores[pos].name,name);
if (!saveHiScores(scores)) {
DlgMessage(error,"Unable to save HiScore Board",BT_OK,BT_NONE);
}
}
}
// display the hiscore board
// clear the screen
ClrScr();
// draw the screen borders
drawBorder();
// draw the game logo
drawLogo();
FontSetSys(F_8x10);
DrawStr(25,35,"Hiscore Board",A_NORMAL);
FontSetSys(F_6x8);
for (loop = 0; loop < 5; loop++) {
printf_xy(20,50+loop*10,"#%hd %-9s %lu",loop+1,scores[loop].name,scores[loop].score);
}
ngetchx();
// redirect auto-interrupts 1 and 5
SetIntVec(AUTO_INT_1,DUMMY_HANDLER);
SetIntVec(AUTO_INT_5,DUMMY_HANDLER);
// wait for keypresses to dissipate
delay(KEYDELAY);
}
gameplay.c
/*
* Nibbles 68k v. 4.2 -- Nibbles Snake Game Clone
* Copyright (C) 2000-2002,2007 John David Ratliff
* Based on Stilgar's Nibbles for Fargo
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "nibbles.h"
#include <kbd.h>
#include <stdlib.h>
// delay - slows the program down
void delay(short int value) {
value <<= 3;
while (value-- > 0) {
rand();
}
}
// getKey - checks for keypresses
// returns - non-standard keycode of the key pressed, or 0 if no key was pressed
inline short int getKey(void) {
if (_rowread(ARROWROW) & UPKEY) {
return KUP;
} else if (_rowread(ARROWROW) & DOWNKEY) {
return KDOWN;
} else if (_rowread(ARROWROW) & LEFTKEY) {
return KLEFT;
} else if (_rowread(ARROWROW) & RIGHTKEY) {
return KRIGHT;
} else if (_rowread(ESCROW) & ESCKEY) {
return KESC;
} else if (_rowread(ENTERROW) & ENTERKEY) {
return KENTER;
} else if (_rowread(CHEATROW) & CHEATKEY) {
return KCHEAT;
}
return 0;
}
// hasHitApple - checks to see whether the snake ate an apple
// returns - TRUE if they hit the apple, FALSE otherwise
short int hasHitApple(POSITION apple, POSITION *snake) {
short int snagged = FALSE;
// if the position and the apple position match, we snagged it
if ((apple.x == snake[0].x) && (apple.y == snake[0].y)) {
snagged = TRUE;
}
// otherwise, we didn't
return snagged;
}
// hasHitWall - checks to see whether the snake hit a wall
// returns - TRUE if snake hit wall, FALSE otherwise
short int hasHitWall(POSITION pos, short int level) {
long int mask = 0x80000, area;
short int crash = FALSE;
// find the search area
area = levels[level][pos.y];
mask = mask >> pos.x;
// if we have a match, we crashed
if (area & mask) {
crash = TRUE;
}
return crash;
}
// hasHitSnake - checks to see if the snake hit itself
// returns - TRUE if the snake hit itself, FALSE otherwise
short int hasHitSnake(POSITION pos, SNAKE *snake, short int start) {
short int loop;
// loop through the body of the snake
for (loop = start; loop < snake->length; loop++) {
// if the position and the snake match, we hit the snake
if ((snake->location[loop].x == pos.x) && (snake->location[loop].y == pos.y)) {
return TRUE;
}
}
return FALSE;
}
// getApplePoints - calculates the number of points the apple is worth
// returns - points apple is worth
short int getApplePoints(short int level, short int speed, short int difficulty) {
short int speedBonus;
// determine speed bonus
if (speed <= MEDIUM) {
speedBonus = 0;
} else if (speed > MEDIUM && speed < QUICK) {
speedBonus = 25;
} else if (speed > AVERAGEPLUS && speed < VERYFAST) {
speedBonus = 50;
} else { // speed = VERYFAST
speedBonus = 100;
}
// calculate and return bonus
return (((level * 5) + 10 + (speedBonus)) * (++difficulty));
}
// initSnake - sets up the snake parameters
void initSnake(SNAKE *snake) {
short int loop;
// reset the snake to standard
snake->dead = FALSE;
snake->length = 3;
snake->direction = RIGHT;
// setup the initial position
for (loop = 0; loop < 4; loop++) {
snake->location[loop].x = 5 - loop;
snake->location[loop].y = 3;
}
// clear all the excess positions
for (loop = 3; loop < 28; loop++) {
snake->location[loop].x = 0;
snake->location[loop].y = 0;
}
}
// growSnake - makes the snake grow
void growSnake(SNAKE *snake) {
short int loop;
// add snake positions for growth
for (loop = snake->length; loop < (snake->length+SNAKE_GROW); loop++) {
snake->location[loop].x = snake->location[snake->length].x;
snake->location[loop].y = snake->location[snake->length].y;
}
// adjust the snakes length
snake->length += SNAKE_GROW;
}
// moveSnake - moves the snake across the screen
void moveSnake(SNAKE *snake) {
short int loop;
// relocate the positions
for (loop = snake->length; loop >= 0; loop--) {
snake->location[loop] = snake->location[loop-1];
}
// grab the second position
snake->location[0].x = snake->location[1].x;
snake->location[0].y = snake->location[1].y;
// adjust the snake based on the direction
if (snake->direction == UP) {
snake->location[0].y--;
} else if (snake->direction == DOWN) {
snake->location[0].y++;
} else if (snake->direction == LEFT) {
snake->location[0].x--;
} else if (snake->direction == RIGHT) {
snake->location[0].x++;
}
// re-draw the snake at the new position
drawSnake(snake);
}
// play - the main game loop
void play(short int speed, short int difficulty) {
SNAKE snake, *snakeptr = &snake;
short int totalApples, levels, speedDelay, done = FALSE, applePoints, level = 0, apples;
short int key = 0, cheater = FALSE, begin, loop, keyDelay, ending = NONE;
unsigned long int score = 0;
POSITION currentApple;
// difficulty level values
const short int startLives[3] = {6, 4, 2};
const short int startApples[3] = {5, 8, 12};
const short int startLevels[3] = {5, 8, 10};
// speed delay
const short int startDelay[10] = {750,650,600,550,425,375,325,250,175,100};
// setup the game options
snake.lives = startLives[difficulty];
totalApples = startApples[difficulty];
levels = startLevels[difficulty];
speedDelay = startDelay[speed];
// the main game loop
while (!done) {
// setup game play
drawLevel(level);
initSnake(snakeptr);
drawSnake(snakeptr);
drawScore(score);
currentApple = drawApple(level, snakeptr);
applePoints = getApplePoints(level, speed, difficulty);
apples = totalApples;
drawApples(apples);
drawLives(snake.lives);
begin = FALSE;
while (!begin) {
while ((key = getKey()) == 0);
if (key == KESC) {
snake.dead = TRUE;
begin = TRUE;
done = TRUE;
ending = QUITTER;
} else if (key == KENTER) {
begin = TRUE;
}
// wait for keypresses to dissipate
delay(KEYDELAY);
}
while (!snake.dead && apples > 0) {
for (loop = 0; loop < speedDelay; loop++) {
if ((key = getKey()) != 0) {
if (speed < MEDIUM) {
keyDelay = (6 * KEYDELAY) / 7;
} else if (speed < AVERAGEPLUS) {
keyDelay = (2 * KEYDELAY) / 3;
} else if (speed < FAST) {
keyDelay = (53 * KEYDELAY) / 100;
} else {
keyDelay = KEYDELAY / 2;
}
delay(keyDelay);
break;
}
}
switch (key) {
case KLEFT:
if (snake.direction != RIGHT) {
snake.direction = LEFT;
}
break;
case KUP:
if (snake.direction != DOWN) {
snake.direction = UP;
}
break;
case KDOWN:
if (snake.direction != UP) {
snake.direction = DOWN;
}
break;
case KRIGHT:
if (snake.direction != LEFT) {
snake.direction = RIGHT;
}
break;
case KCHEAT:
if (cheater == TRUE) {
if (level < levels) {
level++;
}
apples = -1;
}
cheater = TRUE;
break;
case KESC:
done = TRUE;
snake.dead = TRUE;
ending = QUITTER;
break;
case KENTER:
// pause game
delay(KEYDELAY);
while (getKey() != KENTER);
delay(KEYDELAY);
break;
}
// move the snake
moveSnake(snakeptr);
// check for snake hitting things
if (hasHitWall(snake.location[0], level)) {
// hit wall
drawCrash();
snake.dead = TRUE;
} else if (hasHitSnake(snake.location[0], snakeptr, SNAKE_HIT_SELF)) {
// hit self
drawCrash();
snake.dead = TRUE;
} else if (hasHitApple(currentApple,snake.location)) {
// ate apple
growSnake(snakeptr);
currentApple = drawApple(level,snakeptr);
score += applePoints;
drawScore(score);
apples--;
eraseApple(apples);
if (apples == 0) {
// next level, add point and life bonuses
level++;
score+=500*difficulty+10*snake.lives;
snake.lives++;
if (level > levels) {
ending = WINNER;
done = TRUE;
score += difficulty*10000;
}
}
}
}
if (snake.dead && !cheater) {
// cheaters get infinite lives, but they pay for it
if (--(snake.lives) < 0) {
done = TRUE;
ending = LOSER;
}
}
}
if (cheater) {
score = 0;
ending = CHEATER;
}
// display ending message
drawEndMessage(ending);
// wait for keypress before continuing
delay(KEYDELAY);
while (!getKey());
delay(KEYDELAY);
// display the hiscore board
drawHiScoreBoard(score);
}
nibbles.h
/*
* Nibbles 68k v. 4.2 -- Nibbles Snake Game Clone
* Copyright (C) 2000-2002,2007 John David Ratliff
* Based on Stilgar's Nibbles for Fargo
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _NIBBLES_H
#define _NIBBLES_H
// Compile for specific Calc
// Comment out the next line to compile for TI-92+/V200
#define USE_TI89
#ifndef USE_TI89
#define USE_TI92PLUS
#define USE_V200
#endif
#include <intr.h>
/* Structures */
typedef struct {
char name[10]; // player's name
unsigned long int score; // their score
} SCORE;
typedef struct {
unsigned short int x:8, y:8;
} POSITION;
typedef struct {
POSITION location[28];
signed short int lives;
unsigned short int dead:1, direction:2, length:13;
} SNAKE;
/* Constants */
#define MAX_HISCORES 5
#define MAX_LIVES 16
#ifdef USE_TI89
#define DLGWIDTH 140
#define DLGHEIGHT 45
enum KeyMatrix {
ESCROW = ~0x0040, ESCKEY = 0x0001, CHEATROW = ~0x0020, CHEATKEY = 0x0010,
ENTERROW = ~0x0002, ENTERKEY = 0x0001, ARROWROW = ~0x0001,
UPKEY = 0x0001, LEFTKEY = 0x0002, DOWNKEY = 0x0004, RIGHTKEY = 0x0008,
};
#else
#define DLGWIDTH 225
#define DLGHEIGHT 55
enum KeyMatrix {
ESCROW = ~0x0100, ESCKEY = 0x0040, CHEATROW = ~0x0080, CHEATKEY = 0x0001,
ENTERROW = ~0x0200, ENTERKEY = 0x0002, ARROWROW = ~0x0001, UPKEY = 0x0020,
LEFTKEY = 0x0010, DOWNKEY = 0x0080, RIGHTKEY = 0x0040
};
#endif
enum Intro {START,OPTIONS,QUIT,COPYRIGHT,URL,SPEED,DIFFICULTY,QUITOPTIONS};
enum Speeds {VERYSLOW,SLOW,MEDSLOW,LEISURELY,MEDIUM,AVERAGE,AVERAGEPLUS,QUICK,FAST,VERYFAST};
enum Difficulty {EASY,NORMAL,HARD};
enum Logo {LOGOWIDTH = 32, LOGOHEIGHT = 20, LOGOTILES = 5};
enum Selector {SELECTORWIDTH = 32, SELECTORHEIGHT = 8, SELECTORTILES = 5};
enum Menu {MENUSTART = 35, MENUEND = 55, MENUSTEP = 10};
enum Copyright {COPYX = 15, COPYY = 85, URLX = 25, URLY = 92};
enum WaitKey {NOWAIT, WAIT};
enum Delay {KEYDELAY = 415};
enum Keys {KUP = 1,KDOWN,KLEFT,KRIGHT,KESC,KENTER,KCHEAT};
enum Directions {UP,LEFT,DOWN,RIGHT};
enum Dimensions {WIDTH = 8, HEIGHT = 5, TOKEN_HEIGHT = 2, XTILES = 20, YTILES = 19};
enum Score {SCOREX = 10, SCOREY = 93};
enum Snake {SNAKE_HIT_APPLE, SNAKE_HIT_SELF, SNAKE_GROW};
enum Crash {CRASHX = 32, CRASHY = 40, CRASHHEIGHT = 20, CRASHWIDTH = 88};
enum Endings {NONE,QUITTER,LOSER,CHEATER,WINNER,ENDY = 45};
enum Borders {X1 = 0, X2 = 0, X3 = 0, X4 = 159, X5 = 0, X6 = 159, X7 = 159, X8 = 159,
Y1 = 0, Y2 = 99, Y3 = 0, Y4 = 0, Y5 = 99, Y6 = 99, Y7 = 0, Y8 = 99};
/* External Variable Declarations */
extern INT_HANDLER autoint1, autoint5;
extern unsigned long int levels[10][19];
/* Function proto-types */
/* nibbles.c */
short int doIntro(short int *, short int *);
void _main(void);
/* hiscore.c */
short int loadHiScores(SCORE *);
short int saveHiScores(SCORE *);
short int createHiScoreTable(void);
short int needScoreFile(void);
/* gfx.c */
inline void centerText(const char *, short int);
inline void drawBorder(void);
void drawLogo(void);
void drawSelector(short int);
inline void drawCopyright(void);
void drawMenu(void);
void drawSpeedOption(short int);
void drawDifficultyOption(short int);
inline void drawOptionsMenu(short int, short int);
inline void drawBlock(short int, short int, unsigned char *, short int);
inline void drawToken(short int, short int, unsigned char *);
inline void drawScore(unsigned long int);
void drawEndMessage(short int);
void drawCrash(void);
void drawLives(short int);
void drawApples(short int);
POSITION drawApple(short int, SNAKE *);
inline void eraseApple(short int);
void drawSnake(SNAKE *);
void clearDisplayLine(void);
void drawLevel(short int);
void drawHiScoreBoard(unsigned long int);
/* gameplay.c */
void delay(short int);
inline short int getKey(void);
short int hasHitApple(POSITION, POSITION *);
short int hasHitWall(POSITION, short int);
short int hasHitSnake(POSITION, SNAKE *, short int);
void initSnake(SNAKE *);
void growSnake(SNAKE *);
void moveSnake(SNAKE *);
void play(short int, short int);
#endif
gfx.h
/*
* Nibbles 68k v. 4.2 -- Nibbles Snake Game Clone
* Copyright (C) 2000-2002,2007 John David Ratliff
* Based on Stilgar's Nibbles for Fargo
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _GFX_H
#define _GFX_H
// game sprites
static unsigned char block[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0x00};
static unsigned char empty[] = {0x00,0x00,0x00,0x00,0x00,0x00};
static unsigned char apple[] = {0x18,0x3C,0x7E,0x7E,0x3C,0x00};
// game info sprites
static unsigned char lifeToken[] = {0xF0, 0xF0};
static unsigned char appleToken[] = {0xA0, 0x50};
// level data
unsigned long int levels[10][19] = {
{0xFFFFF,0x80001,0x80001,0x80001,0x80001,0x80001,0x80001,0x80001,
0x80001,0x80001,0x80001,0x80001,0x80001,0x80001,0x80001,0x80001,
0x80001,0x80001,0xFFFFF}, // level 1
{0xFFFFF,0x80001,0x80001,0x80001,0x80001,0x80001,0x80001,0x80001,
0x80001,0x87FE1,0x80001,0x80001,0x80001,0x80001,0x80001,0x80001,
0x80001,0x80001,0xFFFFF}, // level 2
{0xFFFFF,0x80001,0x80001,0x80001,0x80001,0x87FE1,0x80001,0x80001,
0x80001,0x87FE1,0x80001,0x80001,0x80001,0x87FE1,0x80001,0x80001,
0x80001,0x80001,0xFFFFF}, // level 3
{0xFFFFF,0x80001,0x80001,0x80001,0x80001,0x84001,0x82001,0x81001,
0x80801,0x80401,0x80201,0x80101,0x80081,0x80041,0x80021,0x80001,
0x80001,0x80001,0xFFFFF}, // level 4
{0xFFFFF,0x80001,0x80001,0x80001,0x80401,0x80401,0x80401,0x80401,
0x80401,0x87FC1,0x80401,0x80401,0x80401,0x80401,0x80401,0x80001,
0x80001,0x80001,0xFFFFF}, // level 5
{0xFFFFF,0x80101,0x80101,0x80101,0x80101,0x80001,0x80001,0x80001,
0xF8001,0x80001,0x80001,0x8001F,0x80001,0x80001,0x80801,0x80801,
0x80801,0x80801,0xFFFFF}, // level 6
{0xFFFFF,0x80001,0x80001,0x80001,0x81F81,0x80001,0x80001,0x90009,
0x90009,0x90009,0x90009,0x90009,0x80001,0x80001,0x81F81,0x80001,
0x80001,0x80001,0xFFFFF}, // level 7
{0xFFFFF,0x80001,0x80001,0x80001,0x80001,0xFFF01,0x80001,0x80001,
0x80001,0x80FFF,0x80001,0x80001,0x80001,0xFFF01,0x80001,0x80001,
0x80001,0x80001,0xFFFFF}, // level 8
{0xFFFFF,0x80001,0x80F81,0x80001,0x84011,0x84011,0x84211,0x84211,
0x80201,0x80001,0x84011,0x84011,0x84011,0x84211,0x80201,0x84211,
0x84011,0x80001,0xFFFFF}, // level 9
{0xFFFFF,0x80001,0x80001,0x80001,0x9FC11,0x90411,0x90411,0x90411,
0x90411,0x90631,0x80001,0x90631,0x90411,0x90411,0x9FC11,0x80001,
0x80001,0x80001,0xFFFFF}, // level 10 (last level)
};
// game logo
static unsigned long int logo[100] = {
0x00000000,0x00000000,0x00000000,0x000e000f,0x01ff3f9f,
0x007f3f1f,0x007f9f0f,0x007f9f3f,0x007fdf1f,0x007fdf0f,
0x007ffe0f,0x00fdfe0f,0x00fcfe1f,0x00fefe1f,0x00fe7e1f,
0x00fe3e1f,0x01ff1f1f,0x001f883f,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x87c03e00,0xcf807c01,
0xc7803c03,0x87803c01,0xe7b83dc1,0x877e3bf1,0x87fe3ff1,
0x87ff3ff9,0x87bf3df9,0x87bf3df9,0x87ff3ff9,0x87fe3ff1,
0x87fc3fe1,0xc7f83fc1,0xef807c03,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x18000000,0xf8000000,
0xf8000000,0xf8000000,0xf83f03f2,0xf87f87fc,0xf8efc7fc,
0xf9cfef88,0xf1ffc7fc,0xf1ffc3fe,0xf1ffa07f,0xf1fe667f,
0xf0ffefff,0xf07feffe,0xf81e28f8,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x0000f080,0x0003ff01,
0x0007fe03,0x000f8603,0x001f0001,0x001f7e01,0x003fff87,
0x003fffcf,0x003f9fcf,0x003f9fdf,0x001fffdf,0x001fff8f,
0x000fff0f,0x0007fe07,0x0000f000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0xfc0ff000,0xff07e000,
0x9f07c000,0xff07c800,0xff07df80,0xff07de00,0xffc7fc00,
0xffe7f800,0xfce7fc00,0xfce7fe00,0xffe7ff00,0xffe7df80,
0xffc7cf80,0xff87e780,0xfc0fee00,0x00000000,0x00000000
};
// menu selector block
static unsigned long int selector[40] = {
0x03ffffff,0x03ffffff,0x03ffffff,0x03ffffff,0x03ffffff,0x03ffffff,0x03ffffff,0x03ffffff,
0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,
0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,
0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,
0xffffffc0,0xffffffc0,0xffffffc0,0xffffffc0,0xffffffc0,0xffffffc0,0xffffffc0,0xffffffc0
};
// crash logo
static unsigned long int crash[60] = {
0x00000000,0x00000000,0x01ff6000,0x01ff6000,0x07807800,
0x07807800,0x00000000,0x078000f1,0x078000f1,0x078000fe,
0x078000fe,0x00000000,0x078000f0,0x078000f0,0x078078f0,
0x078078f0,0x01ff60f0,0x01ff60f0,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0xe0ffb03f,0xe0ffb03f,0x00003cf0,
0x00003cf0,0x00000000,0x00ffbc3f,0x00c03c00,0x03c03c00,
0x03c03c00,0x00ffbc3f,0x00ffbc3f,0x00000000,0x00000000,
0x00000000,0x00000000,0x001e0000,0x001e0000,0x001e0000,
0x001e0000,0x00000000,0xec1ffd80,0xec1ffd80,0x001e01e0,
0x001e01e0,0x00000000,0xec1e01e0,0x0c1e01e0,0x0f1e01e0,
0x0f1e01e0,0xec1e01e0,0xec1e01e0,0x00000000,0x00000000
};
static unsigned short int endings[4][225] = {
{0x0000,0x0000,0x069c,0x0fff,0x1fff,
0x3fff,0x3fbf,0x7f97,0x7e03,0x7e03,
0x7c01,0xf801,0xf801,0xfc05,0xfe05,
0xfe3f,0x7f1f,0x7f9f,0x3fff,0x1fff,
0x1fff,0x0dff,0x0067,0x0002,0x0000,
0x0000,0x0007,0x002f,0x803e,0xc0be,
0xe0fc,0xe07c,0xf07e,0xf87e,0xf8fe,
0xf8fe,0xf8fe,0xf07e,0xf87e,0xf87f,
0xf0ff,0xf07f,0xe07f,0xc03f,0x803f,
0xc01f,0xf017,0x8001,0x0000,0x0000,
0x0000,0x0000,0x02d1,0x0fd1,0x0ff1,
0x07f1,0x0ff1,0x0fe1,0x07e3,0x07d3,
0x0ff3,0x07f3,0x07e1,0x07e1,0x07f2,
0x03f3,0x07e1,0x03e1,0x87e1,0xffe3,
0xff43,0xfec3,0x6c00,0x0000,0x0000,
0x0000,0x1c09,0xfc3f,0xfc3f,0xf87f,
0xf879,0xfc01,0xf801,0xf800,0xf800,
0xfc00,0xfc00,0xfc00,0xfc00,0xf800,
0xf000,0xf800,0xf800,0xf000,0xf800,
0xfc00,0xfc00,0x2000,0x0000,0x0000,
0x0000,0xc788,0xfff8,0xfff0,0xfff8,
0xfff8,0xfe18,0x7e00,0x7f00,0x7f00,
0x7f00,0x7e00,0xfe00,0x7e00,0x7e00,
0xfe00,0xfe00,0x7e00,0x7e00,0xfc00,
0xfe00,0xfe00,0xb600,0x0000,0x0000,
0x0000,0x138f,0x7fff,0x7fff,0xffff,
0xf3ff,0x03fc,0x02fc,0x00fe,0x00fe,
0x00fe,0x00fc,0x01fc,0x00fc,0x00fc,
0x01fc,0x01fc,0x00fc,0x00fc,0x01f8,
0x01fc,0x01fc,0x016c,0x0000,0x0000,
0x0000,0x1000,0xf0bf,0xe07f,0xf07f,
0xf07f,0x307e,0x00ff,0x00fe,0x00fc,
0x00fe,0x007f,0x007f,0x01ff,0x00fe,
0x00fe,0x00fe,0x00fc,0x007f,0x00ff,
0x00ff,0x00ff,0x000f,0x0000,0x0000,
0x0000,0x0000,0xff08,0xfe0f,0xfe0f,
0xfe0f,0x000f,0x000f,0x000f,0x0007,
0x0e1f,0xfe0f,0xfe0f,0xfe0f,0x180f,
0x000f,0x001f,0x001f,0x3a0f,0xfe0f,
0xff0f,0xff1b,0x0e01,0x0000,0x0000,
0x0000,0x0600,0xfee0,0xffe0,0xfffc,
0xfffc,0xedfe,0xc4fe,0xc0fc,0xf2fc,
0xe7f8,0xfffc,0xfff8,0xfff0,0xfff0,
0xfdf8,0xc5f8,0xc1fc,0xc1f8,0xc1fc,
0xc0fc,0xe0fe,0x60de,0x0000,0x0000}, // quitter
{0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x1020,0x3fc0,0x7fc0,
0x7f80,0x3fc0,0x3fc0,0x3fc0,0x3fc0,
0x7fc0,0x3f80,0x3f40,0x3fc0,0x3f80,
0x3fc0,0x1f80,0x7f80,0x3fde,0x3fff,
0x3fff,0x3fff,0x3fff,0x701c,0x0000,
0x0000,0x0000,0x0000,0x000f,0x001f,
0x003f,0x003f,0x017f,0x01fc,0x01f8,
0x03f8,0x03f4,0x03f8,0x01f8,0x01f8,
0x01f8,0x01fc,0x01fc,0xe1ff,0xe0ff,
0xc03f,0xc017,0xc003,0x2000,0x0000,
0x0000,0x0000,0xe000,0xe400,0xfe00,
0xff01,0xff01,0xffc3,0x1fc3,0x0fe3,
0x07e3,0x03e1,0x03e0,0x03e1,0x03e0,
0x03e0,0x03e0,0x87c0,0xc7c2,0xff03,
0xff03,0xfe03,0xfe03,0x3800,0x0000,
0x0000,0x0000,0x0030,0x1ff8,0x3fff,
0xffff,0xffff,0xff9f,0xfb01,0xf800,
0xfc00,0xfec0,0xfffc,0xfffe,0x7fff,
0x07ff,0x07ff,0x001f,0xc01f,0xfe1f,
0xffff,0xfff9,0xfff8,0x4cfc,0x0000,
0x0000,0x0000,0x0002,0x017f,0x81ff,
0xc1ff,0x81ff,0x81fc,0x83fc,0x01f8,
0x01f0,0x01fc,0x01ff,0x01ff,0xc3ff,
0xe3fc,0x83fc,0xc1f8,0xc1f8,0x81fc,
0x83ff,0x81ff,0x01ff,0x001c,0x0000,
0x0000,0x0000,0x0000,0xfc23,0xfc3f,
0xfc3f,0xfc3f,0x003f,0x003f,0x003f,
0x001f,0x3c7f,0xfc3f,0xf83f,0xfc3f,
0x203f,0x003f,0x007f,0x007f,0x643f,
0xfc3f,0xfc3f,0xfc6f,0x3c05,0x0000,
0x0000,0x0000,0x1800,0xfb80,0xff80,
0xfff0,0xfff0,0xb7f8,0x13f8,0x03f0,
0xcbf0,0x9fe0,0xfff0,0xffe0,0xffc0,
0xffc0,0xf7e0,0x17e0,0x07f0,0x07e0,
0x07f0,0x03f0,0x83f8,0x8378,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000}, // loser
{0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0001,0x0001,0x0001,
0x0001,0x0003,0x0003,0x0003,0x0003,
0x0003,0x0003,0x0001,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0ba0,
0x7fe3,0xffe3,0xfee3,0xf023,0xe007,
0xf007,0xf003,0xf003,0xf005,0xe003,
0xf863,0xffc3,0xffc3,0x7fe7,0x2d61,
0x0800,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x80c0,
0xf0f8,0xe0f8,0xe1f8,0xf0f8,0xe0f8,
0xfef8,0xfff8,0xfff8,0xfcf9,0xe0f1,
0xe1f8,0xe0f8,0xe0f8,0xe0f8,0xd0a0,
0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x5cf0,
0xffe0,0xffe0,0xf980,0xfc00,0xf800,
0xf040,0xffe0,0xffe0,0xfbe0,0xf801,
0xf801,0xf801,0xffe3,0xffe3,0xffe3,
0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x2aa0,
0x3fe0,0x3fe0,0x3fe0,0x7ff0,0x7df0,
0xf9f0,0xf9f0,0xf8f0,0xfdf8,0xfff8,
0xfff8,0xfffc,0xf2fc,0xe07e,0xa068,
0x0040,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0010,0x7ffe,
0x7ffe,0xfffe,0x47e6,0x07e0,0x03e0,
0x03e0,0x03e0,0x03e0,0x03e0,0x07e0,
0x03e0,0x03e0,0x03c0,0x03e0,0x0560,
0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0b9c,
0x1ffc,0x1ffc,0x1f20,0x1f00,0x1e00,
0x1e08,0x1ffc,0x1ffc,0x3f70,0x3f00,
0x3e00,0x1e00,0x3ffc,0x3ffc,0x1ffc,
0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x4390,
0x7ff0,0x7ffc,0x7ffe,0x7cbe,0x7c3e,
0x7efc,0x7ffe,0x7ffc,0x7ff8,0x7ffc,
0x7c3c,0x7c3c,0x7c3c,0x7c3e,0x1c3f,
0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000}, // cheater
{0x0000,0x0027,0x007f,0x007f,0x007e,
0x003f,0x003f,0x001f,0x003f,0x001f,
0x001f,0x001f,0x001f,0x000f,0x000f,
0x001f,0x000f,0x000f,0x000f,0x000f,
0x000f,0x000f,0x000c,0x0000,0x0000,
0x0000,0x0080,0x0184,0x0787,0x0f07,
0x1f07,0x1f0f,0x1f8f,0x1f8f,0x9f8f,
0x9f87,0x9f87,0xfff7,0xffff,0xffff,
0xfdff,0xfdff,0xf8ff,0xf1ff,0xf1ff,
0xf0ff,0x70f7,0x1071,0x0010,0x0000,
0x0000,0x401c,0xd1fc,0xf1fc,0xe1f8,
0xe1f8,0xe1fc,0xc1f8,0xc3f8,0xc3f8,
0xc3fc,0xc3fc,0xc1fc,0x81fc,0x82f8,
0x83f0,0x01f8,0x01f8,0x01f0,0x03f8,
0x03fc,0x03fc,0x0020,0x0000,0x0000,
0x0000,0x0000,0x7bc3,0x7fc3,0x3fc3,
0x3fc3,0x1fe1,0x3ff3,0x3ffb,0x3ffb,
0x3ffb,0x1fff,0x1f7f,0x1f3f,0x3f9f,
0x3f9f,0x3f8f,0x3f8f,0x7f83,0x3f87,
0x3f85,0x3f81,0x1201,0x0000,0x0000,
0x0000,0x0000,0xd8f7,0xf8ff,0xf87f,
0xf87f,0xf03f,0xf87f,0xf87f,0xf87f,
0xf07f,0xf83f,0xf03e,0xf83e,0xf87f,
0xf87f,0xf87f,0xf07f,0xf0ff,0xf07f,
0xf07f,0xd87f,0x5824,0x0000,0x0000,
0x0000,0x0000,0x87b0,0x87f0,0x87f0,
0x87f0,0xc3e0,0xe7f0,0xf7f0,0xf7f0,
0xf7e0,0xfff0,0xffe0,0x7ff1,0x3ff0,
0x3ff0,0x1ff0,0x1fe0,0x07e0,0x0fe0,
0x0be0,0x03b0,0x02b0,0x0000,0x0000,
0x0000,0x0000,0xbfff,0x7ffe,0x7ffe,
0x7ffe,0x7e00,0xff00,0xfe00,0xfc00,
0xfe0e,0x7ffe,0x7ffe,0xfffe,0xfe18,
0xfe00,0xfe00,0xfc00,0x7f3a,0xfffe,
0xffff,0xffff,0x0f0e,0x0000,0x0000,
0x0000,0x0006,0x08fe,0x0fff,0x0fff,
0x0fff,0x0fed,0x0fc4,0x0fc0,0x07f2,
0x1fe7,0x0fff,0x0fff,0x0fff,0x0fff,
0x0ffd,0x1fc5,0x1fc1,0x0fc1,0x0fc1,
0x0fc0,0x1be0,0x0160,0x0000,0x0000,
0x0000,0x0000,0xe000,0xe000,0xfc00,
0xfc00,0xfe00,0xfe00,0xfc00,0xfc00,
0xf800,0xfc00,0xf800,0xf000,0xf000,
0xf800,0xf800,0xfc00,0xf800,0xfc00,
0xfc00,0xfe00,0xde00,0x0000,0x0000} // winner
};
/* Display String Literals */
static const char *intro[] = {
"Start New Game",
"Setup Game Options",
"Exit the Game",
"Copyright (C) 2001 John David Ratliff",
"http://www.technoplaza.net",
"Speed: ",
"Level: ",
"Return to the Main Menu"
};
static const char *speeds[] = {
"Very Slow","Slow","Medium Slow","Leisurely","Medium",
"Average","Average Plus","Quick","Fast","Very Fast"
};
static const char *difficulties[] = {"Easy","Normal","Hard"};
#endif
As we have seen in some other programs, we need to make slightly
different versions for the TI-89 and TI-92+/V200. So we first need to
turn off the calculators in the Project, Options, Compilation Tab,
Program Options, Calculators Tab. Uncheck all three.
Now, if you are compiling for the TI-92+/V200, comment out the USE_TI89
definition at the top of nibbles.h. If you are building for the TI-89,
no change is necessary. Build the project and send it to TiEmu. It
will look something like this:
Continue with the Program Analysis in Part II
|