/*******************************************************************************/ /* The Legend of Zelda: Link's Awakening v1.0 */ /* ------------------------------------------- */ /* By: Jason Ho */ /* AIM: Bravo585 */ /* Email: gtg999g@mail.gatech.edu */ /* */ /* Please read the SOURCE README first. If any of the comments in the code are */ /* unclear, just ask me about it and ill be happy to answer. If any part of */ /* code is uncommented, its probably because i commented a similar routine */ /* above it. */ /* */ /* If you know a better way to code any aspect of this game, dont hesitate to */ /* enlighten me, I'd greatly appreciate it. My email and screenname == above. */ /*******************************************************************************/ #define USE_TI89 //Produce .89z File #define OPTIMIZE_ROM_CALLS //Use ROM Call Optimization #define SAVE_SCREEN //Save/Restore LCD Contents #define MIN_AMS 100 //Compile for AMS 1.00 or higher #include //Include All Header Files #include "intro.h" /*---------------------------------------------------------------------------*/ /* Aliases */ /*---------------------------------------------------------------------------*/ enum {UP, RIGHT, DOWN, LEFT}; //Easier reference to direction enum {TERRAIN, MOB, LINK, OBJECT}; //General Types used in functions like DrawImage, and ShiftImage //----------------------------- // Aliases pertaining to Link //----------------------------- //State when he is just standing #define LINK_NORMAL 0 //State when player pushes the movement keys #define LINK_WALK 1 //State when Link thrusts his sword #define LINK_THRUST 2 #define LINK_THRUST2 3 //State when Link is jumping or falling #define LINK_JUMP 4 #define LINK_JUMP2 5 #define LINK_JUMP3 6 /*---------------------------------------------------------------------------*/ /* Global Variables */ /*---------------------------------------------------------------------------*/ char *light = 0; //Pointer to virtual light plane char *dark = 0; //Pointer to virtual dark plane INT_HANDLER save_int_1; //Save interrupt 1 (replaced with DUMMY_HANDLER) short exited = FALSE; //TRUE if user exited, FALSE otherwise unsigned short image_buffer_light[16]; //Used to store temporarily modified pictures unsigned short image_buffer_dark[16]; //Used to store temporarily modified pictures unsigned short image_buffer_mask[16]; //Used to store temporarily modified pictures short screen_shift = 0; //screen shift is explained in function DrawTerrain() from "terrain.h" short screen_row_gain = 0; //screen_row_gain is explained in function DrawTerrain() from "terrain.h" short key_lock_A = FALSE; //TRUE if the player is holding down 2nd, FALSE otherwise short key_lock_B = FALSE; //TRUE if the player is holding down Shift (the key to the right of 2nd), FALSE otherwise int room_buffer[8][10][2]; //Used to store current room (so original wont be modified) short terrain_animation_list[80][4]; //List of terrain animations to be drawn short mob_list[5][8]; //List used to store current mobs in the room short object_list[50][4]; //List used to store current objects in the room //-------------------------------------- // Global Variables pertaining to Link //-------------------------------------- short link_x = 2*16; //Link's x position on the screen short link_y = 3*16; //Link's y position on the screen short link_map_col = 6; //Link's column room position in the world, starts at 2 short link_map_row = 10; //Link's row room position in the world, starts at 10 short link_speed = 3; //How fast link is walking (in pixels) short link_direction = DOWN; //Direction link is facing short link_picture = LINK_NORMAL; //Stores current picture of Link. short link_state = LINK_NORMAL; //Link's current state, for example: walk, normal, jump, etc. int link_frame = 0; //Keeps track of link's frame #. void LoadRoom(int); /*---------------------------------------------------------------------------*/ /* Prototypes */ /*---------------------------------------------------------------------------*/ void GetInput(void); void DrawScreen(void); void DrawImage(short, short, short, short, short); void ShiftImage(short, short, short, short, short); short CheckAreaCollision(short, short, short, short, short, short, short, short); void DelayGame(long); //--------------------------------- // Prototypes pertaining to Link //--------------------------------- void AnimateLink(void); short GetLinkRow(void); short GetLinkCol(void); /*---------------------------------------------------------------------------*/ /* Pictures */ /*---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------*/ /* link_pic_ [DIRECTION] [STATE] [row] */ /* where DIRECTION is any of the aliases UP, RIGHT, DOWN, LEFT which link is facing, */ /* STATE is the action he is doing (for example: jump, walk, normal, etc.) */ /* row is the pixel row of the picture */ /*--------------------------------------------------------------------------------------*/ static unsigned short link_pic_light[4][7][16] = { //---------------------------------- // Pictures of link when facing UP //---------------------------------- { {0x0380,0x07C0,0x0420,0x1BD8,0x2E74,0x2E74,0x2F74,0x3F7C,0x1FF8,0x1FFC,0x2FFC,0x2FDC,0x1838,0x1FF8,0x1FCC,0x0FF8}, //Normal {0x01C0,0x03E0,0x0420,0x1BD8,0x2E74,0x2E74,0x2EF4,0x3EFC,0x1FF8,0x3FF8,0x3FF4,0x3BF4,0x1C18,0x1FF8,0x33F8,0x1FF0}, //Walk {0x0000,0x17F8,0x2FBC,0x3CDC,0x1FE8,0x1E6E,0x1B39,0x1BA9,0x1FEE,0x0FF8,0x1FF0,0x1D90,0x1E90,0x0FF0,0x0788,0x03F8}, //Thrust {0x0FE0,0x1210,0x1DEC,0x173A,0x173A,0x1F7E,0x0F7C,0x07B8,0x0FFC,0x0DFE,0x0EF9,0x0F39,0x07FE,0x03C8,0x01CC,0x007C}, //Thrust2 }, //------------------------------------- // Pictures of link when facing RIGHT //------------------------------------- { {0x07C0,0x0F70,0x1CC8,0x3F9E,0x7B3C,0x7BF0,0x39AC,0x1924,0x0D18,0x0FF0,0x0FF0,0x1E70,0x1E50,0x1FF0,0x0870,0x1FF8}, //Normal {0x0000,0x07E0,0x1F3A,0x3CE6,0x3FCE,0x3D9C,0x1DF8,0x1CD6,0x0C92,0x068C,0x07F8,0x0F90,0x1790,0x17F8,0x1384,0x3FFC}, //Walk {0x00F8,0x0394,0x064C,0x0CE6,0x39F6,0x7FBF,0x7F9F,0x3F94,0x1FD4,0x0FFC,0x3FFC,0x4FDC,0x4E3E,0x3FF2,0x11E6,0x1FFC}, //Thrust {0x0000,0x07E0,0x3E3A,0x78E6,0x7FCE,0x3D9C,0x1DFC,0x1CD6,0x0C92,0x068C,0x07FE,0x1DF9,0x2E79,0x2FFE,0x2788,0x7FFC}, //Thrust2 }, //------------------------------------ // Pictures of link when facing DOWN //------------------------------------ { {0x03E0,0x0670,0x0FFC,0x161A,0x15EA,0x17FA,0x1FFE,0x0924,0x0D2C,0x1E1E,0x2FFE,0x2FE6,0x1C24,0x0FF8,0x1CFC,0x0FF8}, //Normal {0x03E0,0x0730,0x1FF8,0x2C34,0x2BD4,0x2FF4,0x3FFC,0x1248,0x1A58,0x3C3C,0x3FFA,0x33FA,0x121C,0x0FF8,0x1F9C,0x0FF8}, //Walk {0x01E0,0x0330,0x07F8,0x08FC,0x3E3A,0x1F96,0x0FEE,0x0ABE,0x0CBC,0x0E78,0x13F8,0x13E8,0x0FF8,0x07FC,0x018C,0x00F8}, //Thrust {0x01F0,0x03B8,0x0F3C,0x173A,0x17FA,0x140A,0x3FFE,0x4BF4,0x2D2C,0x1E18,0x0FFC,0x1EFC,0x1F3C,0x0FE4,0x01E6,0x00FC}, //Thrust2 {0x0660,0x0990,0x0FF0,0x0FF0,0x1BD8,0x17E8,0x17E8,0x2E74,0x2E74,0x2E74,0x3FFC,0x17E8,0x0BD0,0x0C30,0x07E0,0x03C0}, //Flip1 {0x0000,0x0660,0x0990,0x1998,0x399C,0x3FFC,0x3FFC,0x3FFC,0x17E8,0x1818,0x1FF8,0x3FFC,0x2FF4,0x2E74,0x17E8,0x03C0}, //Flip2 {0x0000,0x07E0,0x0DB0,0x1BD8,0x2FF4,0x2A54,0x2814,0x399C,0x1818,0x3C3C,0x3FFC,0x399C,0x399C,0x399C,0x1998,0x0FF0}, //Flip3 }, //------------------------------------ // Pictures of link when facing LEFT //------------------------------------ { {0x03E0,0x0EF0,0x1338,0x79FC,0x3CDE,0x0FDE,0x359C,0x2498,0x18B0,0x0FF0,0x0FF0,0x0E78,0x0A78,0x0FF8,0x0E10,0x1FF8}, //Normal {0x0000,0x03F0,0x2E7C,0x339E,0x39FE,0x1CDE,0x0FDC,0x359C,0x2498,0x18B0,0x0FF0,0x04F8,0x04F4,0x0FF4,0x10E4,0x1FFE}, //Walk {0x0F80,0x14E0,0x1930,0x3398,0x37CE,0x7EFF,0x7CFF,0x14FE,0x15FC,0x1FF8,0x1FFE,0x1DF9,0x3E39,0x27FE,0x33C4,0x1FFC}, //Thrust {0x0000,0x07E0,0x5C7C,0x671E,0x73FE,0x39BC,0x3FB8,0x6B38,0x4930,0x3160,0x7FE0,0x9FB8,0x9E74,0x7FF4,0x11E4,0x3FFE}, //Thrust2 } }; static unsigned short link_pic_dark[4][7][16] = { //---------------------------------- // Pictures of link when facing UP //---------------------------------- { {0x0380,0x07C0,0x0420,0x1BD8,0x2C34,0x2814,0x2A14,0x2C14,0x1C38,0x1454,0x2494,0x2B0C,0x1008,0x1838,0x1FCC,0x0FF8}, //Normal {0x01C0,0x03E0,0x0420,0x1BD8,0x2C34,0x2814,0x2854,0x2834,0x1C38,0x2A28,0x2924,0x30D4,0x1008,0x1C18,0x33F8,0x1FF0}, //Walk {0x0000,0x17F8,0x28BC,0x305C,0x13A8,0x166E,0x1239,0x1129,0x10AE,0x09F8,0x1730,0x1110,0x1890,0x0C70,0x0788,0x03F8}, //Thrust {0x0FE0,0x1210,0x1DEC,0x161A,0x140A,0x140A,0x0C2C,0x0618,0x0914,0x0892,0x0871,0x0C09,0x063E,0x03C8,0x01CC,0x007C}, //Thrust2 }, //------------------------------------- // Pictures of link when facing RIGHT //------------------------------------- { {0x07C0,0x0830,0x1048,0x248E,0x4B1C,0x4970,0x29AC,0x1924,0x0908,0x0D10,0x0BF0,0x1250,0x1250,0x1FD0,0x0870,0x1FF8}, //Normal {0x0000,0x07E0,0x181A,0x2026,0x2246,0x258C,0x14B8,0x14D6,0x0C92,0x0484,0x07F8,0x0C90,0x1490,0x1678,0x1384,0x3FFC}, //Walk {0x00F8,0x0394,0x044C,0x0826,0x38E6,0x48B7,0x449F,0x2094,0x1094,0x0E5C,0x33F4,0x420C,0x440E,0x3E12,0x11E6,0x1FFC}, //Thrust {0x0000,0x07E0,0x381A,0x4026,0x4246,0x258C,0x14BC,0x14D6,0x0C92,0x0484,0x07FE,0x1889,0x2849,0x2C7E,0x2788,0x7FFC}, //Thrust2 }, //------------------------------------ // Pictures of link when facing DOWN //------------------------------------ { {0x03E0,0x0410,0x0D8C,0x160A,0x15EA,0x17FA,0x13F2,0x0924,0x0924,0x140A,0x27FA,0x2C22,0x1824,0x0F18,0x18FC,0x0FF8}, //Normal {0x03E0,0x0410,0x18D8,0x2834,0x2BD4,0x2FF4,0x27E4,0x1248,0x1248,0x2814,0x2FF2,0x221A,0x120C,0x0C78,0x1F8C,0x0FF8}, //Walk {0x01E0,0x0210,0x0708,0x08D4,0x3E3A,0x1F92,0x0FE2,0x0AA6,0x08AC,0x0E38,0x11E8,0x1028,0x0C48,0x07FC,0x018C,0x00F8}, //Thrust {0x01F0,0x0308,0x0E1C,0x140A,0x177A,0x140A,0x33F2,0x49E4,0x2924,0x1C08,0x0BF4,0x1C24,0x123C,0x0F24,0x01E6,0x00FC}, //Thrust2 {0x0660,0x0990,0x0E70,0x0990,0x1248,0x1668,0x1428,0x2814,0x2814,0x2814,0x381C,0x1428,0x0BD0,0x0C30,0x07E0,0x03C0}, //Flip1 {0x0000,0x0660,0x0990,0x1998,0x2994,0x2FF4,0x2994,0x27E4,0x1008,0x1008,0x1998,0x2A54,0x2E74,0x2814,0x1428,0x03C0}, //Flip2 {0x0000,0x07E0,0x0990,0x1BD8,0x2E74,0x2A54,0x2814,0x2184,0x1008,0x2814,0x27E4,0x2994,0x399C,0x399C,0x1998,0x0FF0}, //Flip3 }, //------------------------------------ // Pictures of link when facing LEFT //------------------------------------ { {0x03E0,0x0C10,0x1208,0x7124,0x38D2,0x0E92,0x3594,0x2498,0x1090,0x08B0,0x0FD0,0x0A48,0x0A48,0x0BF8,0x0E10,0x1FF8}, //Normal {0x0000,0x03F0,0x2C0C,0x3202,0x3122,0x18D2,0x0E94,0x3594,0x2498,0x1090,0x0FF0,0x0498,0x0494,0x0F34,0x10E4,0x1FFE}, //Walk {0x0F80,0x14E0,0x1910,0x3208,0x338E,0x7689,0x7C91,0x1482,0x1484,0x1D38,0x17E6,0x1821,0x3811,0x243E,0x33C4,0x1FFC}, //Thrust {0x0000,0x07E0,0x581C,0x6402,0x6242,0x31A4,0x3D28,0x6B28,0x4930,0x2120,0x7FE0,0x9118,0x9214,0x7E34,0x11E4,0x3FFE}, //Thrust2 } }; static unsigned short link_pic_mask[4][7][16] = { //---------------------------------- // Pictures of link when facing UP //---------------------------------- { {~0x0380,~0x07C0,~0x07E0,~0x1FF8,~0x3FFC,~0x3FFC,~0x3FFC,~0x3FFC,~0x1FF8,~0x1FFC,~0x3FFC,~0x3FFC,~0x1FF8,~0x1FF8,~0x1FFC,~0x0FF8}, //Normal {~0x01C0,~0x03E0,~0x07E0,~0x1FF8,~0x3FFC,~0x3FFC,~0x3FFC,~0x3FFC,~0x1FF8,~0x3FF8,~0x3FFC,~0x3FFC,~0x1FF8,~0x1FF8,~0x3FF8,~0x1FF0}, //Walk {~0x0000,~0x17F8,~0x3FFC,~0x3FFC,~0x1FF8,~0x1FFE,~0x1FFF,~0x1FFF,~0x1FFE,~0x0FF8,~0x1FF0,~0x1FF0,~0x1FF0,~0x0FF0,~0x07F8,~0x03F8}, //Thrust {~0x0FE0,~0x1FF0,~0x1FFC,~0x1FFE,~0x1FFE,~0x1FFE,~0x0FFC,~0x07F8,~0x0FFC,~0x0FFE,~0x0FFF,~0x0FFF,~0x07FE,~0x03F8,~0x01FC,~0x007C}, //Thrust2 }, //------------------------------------- // Pictures of link when facing RIGHT //------------------------------------- { {~0x07C0,~0x0FF0,~0x1FF8,~0x3FFE,~0x7FFC,~0x7FF0,~0x3FFC,~0x1FFC,~0x0FF8,~0x0FF0,~0x0FF0,~0x1FF0,~0x1FF0,~0x1FF0,~0x0FF0,~0x1FF8}, //Normal {~0x0000,~0x07E0,~0x1FFA,~0x3FFE,~0x3FFE,~0x3FFC,~0x1FF8,~0x1FFE,~0x0FFE,~0x07FC,~0x07F8,~0x0FF0,~0x1FF0,~0x1FF8,~0x1FFC,~0x3FFC}, //Walk {~0x00F8,~0x03FC,~0x07FC,~0x0FFE,~0x3FFE,~0x7FFF,~0x7FFF,~0x3FFC,~0x1FFC,~0x0FFC,~0x3FFC,~0x7FFC,~0x7FFE,~0x3FFE,~0x1FFE,~0x1FFC}, //Thrust {~0x0000,~0x07E0,~0x3FFA,~0x7FFE,~0x7FFE,~0x3FFC,~0x1FFC,~0x1FFE,~0x0FFE,~0x07FC,~0x07FE,~0x1FFF,~0x3FFF,~0x3FFE,~0x3FF8,~0x7FFC}, //Thrust2 }, //------------------------------------ // Pictures of link when facing DOWN //------------------------------------ { {~0x03E0,~0x07F0,~0x0FFC,~0x1FFE,~0x1FFE,~0x1FFE,~0x1FFE,~0x0FFC,~0x0FFC,~0x1FFE,~0x3FFE,~0x3FFE,~0x1FFC,~0x0FF8,~0x1FFC,~0x0FF8}, //Normal {~0x03E0,~0x07F0,~0x1FF8,~0x3FFC,~0x3FFC,~0x3FFC,~0x3FFC,~0x1FFC,~0x1FFC,~0x3FFC,~0x3FFE,~0x3FFE,~0x1FFC,~0x0FF8,~0x1FFC,~0x0FF8}, //Walk {~0x01E0,~0x03F0,~0x07F8,~0x0FFC,~0x3FFE,~0x1FFE,~0x0FFE,~0x0FFE,~0x0FFC,~0x0FF8,~0x1FF8,~0x1FF8,~0x0FF8,~0x07FC,~0x01FC,~0x00F8}, //Thrust {~0x01F0,~0x03F8,~0x0FFC,~0x1FFE,~0x1FFE,~0x1FFE,~0x3FFE,~0x7FFC,~0x3FFC,~0x1FF8,~0x0FFC,~0x1FFC,~0x1FFC,~0x0FFC,~0x01FE,~0x00FC}, //Thrust2 {~0x0660,~0x0FF0,~0x0FF0,~0x0FF0,~0x1FF8,~0x1FF8,~0x1FF8,~0x3FFC,~0x3FFC,~0x3FFC,~0x3FFC,~0x1FF8,~0x0FF0,~0x0FF0,~0x07E0,~0x03C0}, //Flip1 {~0x0000,~0x0660,~0x0FF0,~0x1FF8,~0x3FFC,~0x3FFC,~0x3FFC,~0x3FFC,~0x1FF8,~0x1FF8,~0x1FF8,~0x3FFC,~0x3FFC,~0x3FFC,~0x17E8,~0x03C0}, //Flip2 {~0x0000,~0x07E0,~0x0FF0,~0x1FF8,~0x3FFC,~0x3FFC,~0x3FFC,~0x3FFC,~0x1FF8,~0x3FFC,~0x3FFC,~0x3FFC,~0x3FFC,~0x3FFC,~0x1FF8,~0x0FF0}, //Flip3 }, //------------------------------------ // Pictures of link when facing LEFT //------------------------------------ { {~0x03E0,~0x0FF0,~0x1FF8,~0x7FFC,~0x3FFE,~0x0FFE,~0x3FFC,~0x3FF8,~0x1FF0,~0x0FF0,~0x0FF0,~0x0FF8,~0x0FF8,~0x0FF8,~0x0FF0,~0x1FF8}, //Normal {~0x0000,~0x03F0,~0x2FFC,~0x3FFE,~0x3FFE,~0x1FFE,~0x0FFC,~0x3FFC,~0x3FF8,~0x1FF0,~0x0FF0,~0x07F8,~0x07FC,~0x0FFC,~0x1FFC,~0x1FFE}, //Walk {~0x0F80,~0x1FE0,~0x1FF0,~0x3FF8,~0x3FFE,~0x7FFF,~0x7FFF,~0x1FFE,~0x1FFC,~0x1FF8,~0x1FFE,~0x1FFF,~0x3FFF,~0x3FFE,~0x3FFC,~0x1FFC}, //Thrust {~0x0000,~0x07E0,~0x5FFC,~0x7FFE,~0x7FFE,~0x3FFC,~0x3FF8,~0x7FF8,~0x7FF0,~0x3FE0,~0x7FE0,~0xFFF8,~0xFFFC,~0x7FFC,~0x1FFC,~0x3FFE}, //Thrust2 } }; /*---------------------------------------------------------------------------*/ /* Zelda header files (must be kept in the same order) */ /*---------------------------------------------------------------------------*/ #include "object.h" #include "terrain.h" #include "mob.h" #include "room.h" #include "dialog.h" //Draws the HoSoft Logo //#include "hologo.h" /*===========================================================================*/ /* Main Function */ /*===========================================================================*/ void _main(void) { //This segment of code handles the contrast problem on AMS 2.05+ TI-89s int count1; for (count1=0;count1<30;count1++) OSContrastDn(); for (count1=0;count1<15;count1++) OSContrastUp(); //DrawHoLogo(); //Draws the HoSoft Logo intro(); //---------------------------------------- // Allocate memory for the virtual screen //---------------------------------------- dark = malloc(LCD_SIZE); light = malloc(LCD_SIZE); //------------------------------------------------------------------ // Install DUMMY Interrupt, to use _rowread and grayscale together //------------------------------------------------------------------ save_int_1 = GetIntVec (AUTO_INT_1); SetIntVec(AUTO_INT_1, DUMMY_HANDLER); //----------------------------------------- // Loads the first room into room_buffer //----------------------------------------- LoadRoom(world_map[link_map_row][link_map_col]); //--------------------- // Turns on grayscale //--------------------- if (!GrayOn()) return; //------------------- // Game Loop //------------------- while (!exited) { GetInput(); DrawScreen(); } //---------------------- // Turns off grayscale //---------------------- GrayMode(GRAY_OFF); //--------------------------------- // Restore the original interrupt //--------------------------------- SetIntVec(AUTO_INT_1, save_int_1); //--------------------------------------- // Free the pointers to virtual screens //--------------------------------------- free(light); free(dark); } /*===========================================================================*/ /* Get input from user */ /*===========================================================================*/ void GetInput(void) { //----------------------------------------------------------- // 2nd - Acts as the 'A' button on a gameboy. key_lock_A is // TRUE while the player is holding it down. FALSE otherwise //----------------------------------------------------------- if (_rowread(0xFE)&0x10 && !key_lock_A && link_state != LINK_JUMP) { //-------------------------------------------------- // If Link isnt already thrusting, make him thrust //-------------------------------------------------- if (link_state != LINK_THRUST) { link_frame = 0; link_state = LINK_THRUST; } //------------------------------------------------ // Lock the 2nd key until the player releases it //------------------------------------------------ key_lock_A = TRUE; } //-------------------------------------------------- // When the player releases the 2nd key, unlock it //-------------------------------------------------- else if (!(_rowread(0xFE)&0x10)) { key_lock_A = FALSE; } //--------------------------------------------------------- // UP - moves Link up. He cannot move when he's thrusting //--------------------------------------------------------- if (_rowread(0xFE)&0x1 && link_state != LINK_THRUST && link_state != LINK_JUMP) { //------------------------------------------------------------------------------- // If Link's state is normal, give him a new direction, and make his state walk //------------------------------------------------------------------------------- if (!link_state) { link_direction = UP; link_state = LINK_WALK; } //------------------------------------------------------------- // Go to next room if Link goes beyond the room boundaries // -4 is for more travel leeway. //------------------------------------------------------------- if (link_y-link_speed < 0 -4) { ScrollRoomUp(); return; } //---------------------------- // Set Link's new Y position //---------------------------- link_y-=link_speed; //--------------------------------------------------------- // If the new Y position hits a non-walkable terrain, set // Link's position on the edge of that terrain. //--------------------------------------------------------- if (CheckTerrainCollision(link_x, link_y, 16, 16)) link_y = GetTerrainRow(link_y)*16+16-8; } //------------------------------------------------------ // If link was already walking UP, and player releases // UP button, set Link's state to normal again. //------------------------------------------------------ else if (link_direction == UP && link_state == LINK_WALK) { link_state = LINK_NORMAL; link_frame = 0; } //-------------------------------------------- // DOWN - moves Link down - comments: see UP //-------------------------------------------- if (_rowread(0xFE)&0x4 && link_state != LINK_THRUST && link_state != LINK_JUMP) { if (!link_state) { link_direction = DOWN; link_state = LINK_WALK; } //------------------------------------------------------------- // There are 8 rows in each room, and Link is 16 pixels high. // Therefore, Link goes out of bounds at 8*16-16 +4 for leeway //------------------------------------------------------------- if (link_y+link_speed > 8*16-16 +4) { ScrollRoomDown(); return; } link_y+=link_speed; if (CheckTerrainCollision(link_x, link_y, 16, 16)) link_y = GetTerrainRow(link_y)*16+2; } else if (link_direction == DOWN && link_state == LINK_WALK) { link_state = LINK_NORMAL; link_frame = 0; } //-------------------------------------------- // LEFT - moves Link left - comments: see UP //-------------------------------------------- if (_rowread(0xFE)&0x2 && link_state != LINK_THRUST && link_state != LINK_JUMP) { if (!link_state) { link_direction = LEFT; link_state = LINK_WALK; } if (link_x-link_speed < 0) { ScrollRoomLeft(); return; } link_x-=link_speed; if (CheckTerrainCollision(link_x, link_y, 16, 16)) link_x = GetTerrainCol(link_x)*16+16-6; } else if (link_direction == LEFT && link_state == LINK_WALK) { link_state = LINK_NORMAL; link_frame = 0; } //---------------------------------------------- // RIGHT - moves Link right - comments: see UP //---------------------------------------------- if (_rowread(0xFE)&0x8 && link_state != LINK_THRUST && link_state != LINK_JUMP) { if (!link_state) { link_direction = RIGHT; link_state = LINK_WALK; } //----------------------------------------------------------------- // Maximum link_x is 160 pixels for the TI-89, and Link is 16 // pixels wide, so he goes out of bounds at 160-16 //----------------------------------------------------------------- if (link_x+link_speed > 160-16) { ScrollRoomRight(); return; } link_x+=link_speed; if (CheckTerrainCollision(link_x, link_y, 16, 16)) link_x = GetTerrainCol(link_x)*16+5; } else if (link_direction == RIGHT && link_state == LINK_WALK) { link_state = LINK_NORMAL; link_frame = 0; } //-------------------- // Enterable Terrain //-------------------- if (room_buffer[GetLinkRow()][GetLinkCol()][TERRAIN_PROPERTIES] & ENTERABLE) { EnterTerrain(world_map[link_map_row][link_map_col], GetLinkRow(), GetLinkCol()); } //-------------------- // Fallable Terrain //-------------------- if (room_buffer[GetLinkRow()][GetLinkCol()][TERRAIN_PROPERTIES] & FALLABLE && link_state != LINK_JUMP) { link_state = LINK_JUMP; link_frame = 0; link_y += link_speed; } //------------------------ // Walk slower on stairs //------------------------ if (room_buffer[GetLinkRow()][GetLinkCol()][TERRAIN_PIC] == 43||room_buffer[GetLinkRow()][GetLinkCol()][TERRAIN_PIC] ==184) { link_speed = 1; } else link_speed = 3; //----------------------------------------- // ESC - exits the game //----------------------------------------- if (_rowread(0xBF)&0x1) { exited = 1; } if (PLUS_KEY)//Increases the contrast { OSContrastUp (); } if (MINUS_KEY)//Decreases the contrast { OSContrastDn (); } } /*===========================================================================*/ /* Draws the screen */ /*===========================================================================*/ void DrawScreen(void) { //------------------------------------- // Clears the screen //------------------------------------- memset(light,0,LCD_SIZE); memset(dark,0,LCD_SIZE); //------------------------------- // Animate and Draw terrain //------------------------------- AnimateTerrain(); DrawTerrain(); //------------------------------------------ // Animates 1 frame of mobs and draws them //------------------------------------------ AnimateMob(); //------------------------------- // Animates objects in the room //------------------------------- AnimateObject(); //--------------------------- // Animate and Draw Link //--------------------------- AnimateLink(); DrawImage(LINK, link_picture, link_x, link_y, A_NORMAL); //-------------------------------------- // Copy virtual screens to real screen //-------------------------------------- memcpy(GetPlane(0),light,LCD_SIZE); memcpy(GetPlane(1),dark,LCD_SIZE); } /*=============================================================================*/ /* Draws an image of type LINK, OBJECT, or MOB */ /* The function takes in the type of picture to draw (which points to the */ /* picture list to pick from, done in function ShiftImage), the picture number */ /* in the list, the x,y coordinates to draw the picture, and the draw type */ /* (A_NORMAL, A_REVERSE) */ /*=============================================================================*/ void DrawImage(short pic_type, short pic_num, short pic_x, short pic_y, short draw_type) { int count1; //-------------------------------------------------------------------- // pic_y is modified to take screen_shift into account. screen_shift // is explained in function DrawTerrain of "terrain.h" //-------------------------------------------------------------------- pic_y -= (screen_shift+screen_row_gain*16); //------------------------------------------------------ // If the picture isnt in viewing bounds, dont draw it //------------------------------------------------------ if ((pic_x < 0 && pic_y < 0) || pic_y <= -16 || pic_y > 100 || pic_x <= -16 || pic_x > 160) { return; } //----------------------------------------- // If the picture is too far UP, clip it. //----------------------------------------- else if (pic_y < 0 && pic_y > -16) { ShiftImage(pic_type, pic_num, UP, pic_y*-1, TRUE); pic_y = 0; } //------------------------------------------- // If the picture is too far LEFT, clip it. //------------------------------------------- else if (pic_x < 0 && pic_x > -16) { ShiftImage(pic_type, pic_num, LEFT, pic_x*-1, TRUE); pic_x = 0; } //------------------------------------------------------------------- // Otherwise, draw the unmodified image. I call ShiftImage just // to store the image in the image buffer. // NOTE: if the picture goes slightly too much to the RIGHT or // DOWN, it doesnt need to be clipped, cause its done already. //------------------------------------------------------------------- else { ShiftImage(pic_type, pic_num, UP, 0, TRUE); } switch (draw_type) { //------------------------------ // Draws the picture normally. //------------------------------ case A_NORMAL: //-------------------------------------------------------- // Masking the image: // Clears the image's "filling", while leaving anything // outside the image untouched. //-------------------------------------------------------- Sprite16(pic_x,pic_y,16,image_buffer_mask,light,SPRT_AND); Sprite16(pic_x,pic_y,16,image_buffer_mask,dark,SPRT_AND); //------------------------------------------------------- // Fills the blank space (created by the masking) with // the picture. //------------------------------------------------------- Sprite16(pic_x,pic_y,16,image_buffer_light,light,SPRT_OR); Sprite16(pic_x,pic_y,16,image_buffer_dark,dark,SPRT_OR); break; //-------------------------------------------------------------------- // Draws the picture inverted. Used in animations like the explosion //-------------------------------------------------------------------- case A_REVERSE: //------------------------------------------------------------- // Inverts the picture mask. Result is a black-filled picture //------------------------------------------------------------- for (count1=0;count1<16;count1++) image_buffer_mask[count1] = ~image_buffer_mask[count1]; //------------------------------------------------------- // Fill the spot where the picture is drawn with black. //------------------------------------------------------- Sprite16(pic_x,pic_y,16,image_buffer_mask,light,SPRT_OR); Sprite16(pic_x,pic_y,16,image_buffer_mask,dark,SPRT_OR); //------------------------------------------------- // XOR the normal picture onto the black filling. //------------------------------------------------- Sprite16(pic_x,pic_y,16,image_buffer_light,light,SPRT_XOR); Sprite16(pic_x,pic_y,16,image_buffer_dark,dark,SPRT_XOR); } } /*==============================================================================*/ /* Shifts an image pixels in a given direction. */ /* Takes in the type of picture to shift, the picture number in that list, */ /* the direction to shift it, how many pixels to shift in that direction, */ /* and whether or not the image has a mask. This shifted image is stored in */ /* the global pic image_buffer_light, image_buffer_dark, and image_buffer_mask. */ /*==============================================================================*/ void ShiftImage(short pic_type, short pic_num, short direction, short shift, short masked) { int count1, count2; //--------------------------------------------------------------------- // Stores the given picture into an image buffer so the originals wont // be modified. Specifying the pic_type basically just points which // list of pictures to pick from. //--------------------------------------------------------------------- for (count1=0;count1<16;count1++) { switch (pic_type) { case TERRAIN: image_buffer_light[count1] = img_map_light[pic_num][count1]; image_buffer_dark[count1] = img_map_dark[pic_num][count1]; break; case MOB: image_buffer_light[count1] = mob_pic_light[pic_num][count1]; image_buffer_dark[count1] = mob_pic_dark[pic_num][count1]; image_buffer_mask[count1] = mob_pic_mask[pic_num][count1]; break; case OBJECT: image_buffer_light[count1] = object_pic_light[pic_num][count1]; image_buffer_dark[count1] = object_pic_dark[pic_num][count1]; image_buffer_mask[count1] = object_pic_mask[pic_num][count1]; break; case LINK: image_buffer_light[count1] = link_pic_light[link_direction][pic_num][count1]; image_buffer_dark[count1] = link_pic_dark[link_direction][pic_num][count1]; image_buffer_mask[count1] = link_pic_mask[link_direction][pic_num][count1]; break; } } //------------------------------------------------------------------------- // Occasionally ShiftImage will be used just to transfer a picture // to the image buffer. If a shift of 0 is given, just exit the function. //------------------------------------------------------------------------- if (shift == 0) return; switch(direction) { case UP: //------------------------------------------------------------------- // This routine shifts the image buffer a amount up, // and fills the rest of the picture with space blank. //------------------------------------------------------------------- for (count1=0;count1<16;count1++) { if(count1+shift < 16) { image_buffer_light[count1] = image_buffer_light[count1+shift]; image_buffer_dark[count1] = image_buffer_dark[count1+shift]; //----------------------------------------------------- // If the picture has a mask, shift it's mask as well //----------------------------------------------------- if (masked) image_buffer_mask[count1] = image_buffer_mask[count1+shift]; } //-------------------------------------------------- // Fills the rest of the picture with blank space. //-------------------------------------------------- else { image_buffer_light[count1] = 0x0000; image_buffer_dark[count1] = 0x0000; //--------------------------------------------------------------- // If the picture has a mask, fill the rest of the space black. //--------------------------------------------------------------- if (masked) image_buffer_mask[count1] = ~0x0000; } } break; case LEFT: //------------------------------------------------------------------- // This routine shifts the image buffer a amount left. //------------------------------------------------------------------- for (count1=0;count1<16;count1++) { image_buffer_light[count1] <<= shift; image_buffer_dark[count1] <<= shift; //----------------------------------------------------- // If the picture has a mask, shift the mask as well. //----------------------------------------------------- if (masked) { //--------------------------------------------------- // Invert the picture, shift the bits of the picture // left, then invert the picture back. //--------------------------------------------------- for (count2=0;count2<16;count2++) image_buffer_mask[count2] = ~image_buffer_mask[count2]; image_buffer_mask[count1] <<= shift; for (count2=0;count2<16;count2++) image_buffer_mask[count2] = ~image_buffer_mask[count2]; } } } } /*==========================================================================*/ /* Checks if 2 areas intersect. If they do, return 1. Otherwise, return 0. */ /* Takes in the first area's x,y position, and its width and height. Then */ /* takes in the second area's x,y position, and its width and height. */ /*==========================================================================*/ short CheckAreaCollision(short area1_x, short area1_y, short area1_width, short area1_height, short area2_x, short area2_y, short area2_width, short area2_height) { //Checks if the X coordinates of area2 intersect with area1 if ( (((area1_x <= area2_x && area1_x+area1_width >= area2_x) || (area1_x <= area2_x+area2_width && area1_x+area1_width >= area2_x+area2_width)) || //Checks if the X coordinates of area1 intersect with area2 ((area2_x <= area1_x && area2_x+area2_width >= area1_x) || (area2_x <= area1_x+area1_width && area2_x+area2_width >= area1_x+area1_width))) && //Checks if the Y coordinates of area2 intersect with area1 (((area1_y <= area2_y && area1_y+area1_height >= area2_y) || (area1_y <= area2_y+area2_height && area1_y+area1_height >= area2_y+area2_height)) || //Checks if the Y coordinates of area1 intersect with area2 ((area2_y <= area1_y && area2_y+area2_height >= area1_y) || (area2_y <= area1_y+area1_height && area2_y+area2_height >= area1_y+area1_height))) ) return 1; else return 0; } /*===========================================================================*/ /* Animates Link according to his direction and state. */ /* This function is pretty simple, so i wont comment too much on it. */ /*===========================================================================*/ void AnimateLink(void) { switch (link_state) { case LINK_NORMAL: link_picture = LINK_NORMAL; link_frame = 0; break; //-------------------------------------------------------------------------- // LINK_WALK scrolls through 6 frames - the first 3 showing Link walking, // the other 3 showing Link normal. This creates the illusion of walking //-------------------------------------------------------------------------- case LINK_WALK: switch (link_frame) { case 0 ... 2: link_picture = LINK_WALK; break; case 3 ... 5: link_picture = LINK_NORMAL; break; default: //Reset frame link_picture = LINK_WALK; link_frame = 0; } link_frame++; break; //------------------------------ // When Link Jumps or falls //------------------------------ case LINK_JUMP: link_direction = DOWN; switch (link_frame) { case 0 ... 2: link_picture = LINK_JUMP; break; case 3 ... 5: link_picture = LINK_JUMP2; break; case 6 ... 8: link_picture = LINK_JUMP3; break; } if (link_y+3 > 8*16-16 +4) ScrollRoomDown(); if (CheckTerrainCollision(link_x, link_y, 16, 16)) link_y += 3; else { link_state = LINK_NORMAL; link_frame = 0; } link_frame++; break; //-------------------------------------------------------------------------- // NOTE: each direction link is facing has a different LINK_THRUST picture //-------------------------------------------------------------------------- case LINK_THRUST: switch (link_frame) { case 0: link_picture = LINK_THRUST; //------------------------------------------------------ // Draws the sword swinging. The random pixels off // link_x and link_y are just for display adjustments. //------------------------------------------------------ switch (link_direction) { case UP: DrawImage(OBJECT, SWORD1, link_x+16, link_y - 5, A_NORMAL); break; case RIGHT: DrawImage(OBJECT, SWORD3, link_x+2, link_y - 16, A_NORMAL); break; case DOWN: DrawImage(OBJECT, SWORD5, link_x-16, link_y, A_NORMAL); break; case LEFT: DrawImage(OBJECT, SWORD3, link_x-2, link_y - 16, A_NORMAL); break; } break; case 1: link_picture = LINK_THRUST2; //--------------------------------------------- // At this stage, the routine checks if Link // slashed any terrain or mobs. //--------------------------------------------- switch (link_direction) { case UP: SlashTerrain(GetLinkRow()-1, GetLinkCol()); SlashMob(link_x+1, link_y-18, 22, 19); DrawImage(OBJECT, SWORD2, link_x+12, link_y - 14, A_NORMAL); break; case RIGHT: SlashTerrain(GetLinkRow(), GetLinkCol()+1); SlashMob(link_x+12, link_y-12, 20, 27); link_x += 1; DrawImage(OBJECT, SWORD2, link_x+13, link_y - 13, A_NORMAL); break; case DOWN: SlashTerrain(GetLinkRow()+1, GetLinkCol()); SlashMob(link_x-11, link_y+13, 24, 20); link_y += 1; DrawImage(OBJECT, SWORD6, link_x-12, link_y + 13, A_NORMAL); break; case LEFT: SlashTerrain(GetLinkRow(), GetLinkCol()-1); SlashMob(link_x-20, link_y-12, 20, 26); link_x -= 3; DrawImage(OBJECT, SWORD4, link_x-13, link_y - 13, A_NORMAL); break; } break; case 2: link_picture = LINK_THRUST2; //-------------------------------------------- // Link's position is slightly modified when // he as fully extended his sword. //-------------------------------------------- switch (link_direction) { case UP: link_y -= 3; DrawImage(OBJECT, SWORD3, link_x-2, link_y - 16, A_NORMAL); break; case RIGHT: link_x += 3; DrawImage(OBJECT, SWORD1, link_x+16, link_y, A_NORMAL); break; case DOWN: link_y += 3; DrawImage(OBJECT, SWORD7, link_x-1, link_y + 16, A_NORMAL); break; case LEFT: link_x -= 3; DrawImage(OBJECT, SWORD5, link_x-16, link_y, A_NORMAL); break; } break; //---------------------------------------------------------- // Very short pause when Link has his sword fully extended //---------------------------------------------------------- case 3: break; default: //Reset frame link_state = LINK_NORMAL; link_frame = 0; //-------------------------------------------- --------------- // Reset Link's position back to where he originally stood. //----------------------------------------------------------- switch (link_direction) { case UP: link_y += 3; break; case RIGHT: link_x -= 4; break; case DOWN: link_y -= 4; break; case LEFT: link_x += 6; break; } } link_frame++; break; } } short GetLinkRow(void) { if (link_y%16 >= 8) return (int)((link_y/16)+1); else return (int)(link_y/16); } short GetLinkCol(void) { if (link_x%16 >= 8) return (int)((link_x/16)+1); else return (int)(link_x/16); } void DelayGame(long time) { long count1; for (count1=0;count1