main.cJ]P:I1=Fmain.c"@ 0 R`TEXTCWIE@J]:I1=Fa// Time Slip // David Johnston - Programming, Level design, Concept // Mike Goatly - Graphics // ARM'd & Dangerous // 18/11/98 // v1.0 #include #include #include #include #include #include "pad.h" #include "asssert.h" #include "dump.h" #define MAINSPRS_ADDRESS 0x80090000 #define SNAILSPRS_ADDRESS 0x800AB000 #define BACKGRSPR_ADDRESS 0x800AD000 #define SWIRLSPR_ADDRESS 0x800B8000 #define PLATFORMSPRS_ADDRESS 0x800C9000 #define BALLSPRS_ADDRESS 0x800CA000 #define CLOCKSPR_ADDRESS 0x800CB000 #define TITLESPR_ADDRESS 0x800CC000 #define NUMSPRS_ADDRESS 0x800CE000 #define DIGITSPRS_ADDRESS 0x800D1000 #define COINSPRS_ADDRESS 0x800D2000 #define FONTSPRS_ADDRESS 0x800D4000 #define GOBLINSPRS_ADDRESS 0x800D6000 #define BLOODSPRS_ADDRESS 0x800D7000 #define ELECSPRS_ADDRESS 0x800D8000 #define STINGERSPRS_ADDRESS 0x800D9000 #define SPIKESPR_ADDRESS 0x800DB000 #define ROBOTSPRS_ADDRESS 0x800DC000 #define BOUNCERSPRS_ADDRESS 0x800E4000 #define RADARSPRS_ADDRESS 0x800EC000 #define STARSPR_ADDRESS 0x800ED000 #define DUSTSPRS_ADDRESS 0x800EE000 #define CRADLESPRS_ADDRESS 0x800F0000 #define PLASMASPRS_ADDRESS 0x8014C000 #define NYTITLE_ADDRESS 0x80156000 #define INFOSPRS_ADDRESS 0x8017C000 #define Vag_Header 0x80120000 #define Vag_Body 0x80122000 GsIMAGE MainSprsInfo; GsIMAGE SnailSprsInfo; GsIMAGE BackgrSprInfo; GsIMAGE SwirlInfo; GsIMAGE PlatformSprsInfo; GsIMAGE BallSprsInfo; GsIMAGE ClockSprInfo; GsIMAGE TitleSprInfo; GsIMAGE NumSprsInfo; GsIMAGE DigitSprsInfo; GsIMAGE CoinSprsInfo; GsIMAGE FontSprsInfo; GsIMAGE GoblinSprsInfo; GsIMAGE BloodSprsInfo; GsIMAGE ElecSprsInfo; GsIMAGE StingerSprsInfo; GsIMAGE SpikeSprInfo; GsIMAGE RobotSprsInfo; GsIMAGE BouncerSprsInfo; GsIMAGE RadarSprsInfo; GsIMAGE StarSprInfo; GsIMAGE DustSprsInfo; GsIMAGE CradleSprsInfo; GsIMAGE PlasmaSprsInfo; GsIMAGE NYTitleInfo; GsIMAGE InfoSprsInfo; #define PAL 0 // 0 - NTSC mode, 1 - PAL mode #define PACKETMAX 2048 /* Max GPU packets */ #define PACKETMAX2 (PACKETMAX*24) #define OT_LENGTH 5 static GsOT Wot[2]; /* Handler of OT */ static GsOT_TAG wtags[2][1<>1) & 8128),(cy) & 7936); \ sprite.u = ((cx) % 128); \ sprite.v = ((cy) % 256) #define CalcSprPos2(sprite,cx,cy) \ sprite->tpage = GetTPage(1,0,(((cx)>>1) & 8128),(cy) & 7936); \ sprite->u = ((cx) % 128); \ sprite->v = ((cy) % 256) typedef struct { u_char x,y; long xdis,ydis,xspeed,yspeed,framedel; u_char dirn,finaldirn,frame,firedel; } snail; snail cursnail; //you typedef struct { u_char x,y,xdis,ydis,sprite; } pastsnail; pastsnail snails[18][slipsize]; //Each version of yourself typedef struct { int x,y,z; } star; star stars[256]; // Everything that needs to be // known about a moving platform typedef struct { u_char x,y,sections,type; long xdist,ydist,xangle,yangle,xspeed,yspeed; } platform; platform platforms[8]; platform platlist[no_levs][8]; typedef struct { u_char x,y,dirn; char xdis,ydis; u_char sprite,sprdirn; } ball; ball balls[noballs]; int nextball; typedef struct { u_char x,y,state,opening,type; } door; door doors[9]; typedef struct { u_char x,y,collected,sprite; } coin; coin coins[64]; u_char coinbounce,coindelay; int coinheight,coinspeed; // The stars that appear when you collect a coin typedef struct { u_char x,y,lifespan; long angle,xdis,ydis,xspeed,yspeed; } star2; star2 stars2[128]; u_char stars2ptr; // The dust for when you hit the ground typedef struct { u_char sprite; long x,y,xspeed,yspeed; } dust; dust dusts[8]; u_char dustptr; typedef struct { u_char x,y,sprite,delay; int xdis,ydis,xspeed,yspeed; } bloodbit; bloodbit blood[64]; int nextblood; typedef struct { int x,y,angle; long size; u_char r,g,b; } hex; hex hexs[32]; int nexthex; u_char doorlists[no_levs][9][3] = { {{0,0,0},{0,0,0},{49,24,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{35,27,0},{0,0,0}}, {{18,11,0},{0,0,0},{52,29,0},{0,0,0},{44,29,1},{21,55,0},{0,0,0},{0,0,0},{0,0,0}}, {{0,0,0},{0,0,0},{0,0,0},{8,55,0},{0,0,0},{0,0,0},{39,37,3},{0,0,0},{39,42,3}}, {{43,39,0},{56,44,2},{0,0,0},{6,38,0},{0,0,0},{0,0,0},{13,38,0},{0,0,0},{57,43,1}}, {{37,41,1},{0,0,0},{0,0,0},{0,0,0},{57,13,0},{56,30,0},{0,0,0},{20,30,0},{0,0,0}}, {{59,22,0},{0,0,0},{26,26,0},{59,10,0},{0,0,0},{0,0,0},{7,23,2},{40,58,0},{36,20,0}}, {{52,41,0},{37,13,1},{9,23,0},{13,27,0},{0,0,0},{26,27,0},{28,51,0},{17,4,0},{0,0,0}}, {{55,35,3},{0,0,0},{41,58,0},{0,0,0},{50,31,0},{0,0,0},{10,36,2},{0,0,0},{7,45,0}}, {{48,49,0},{0,0,0},{37,39,1},{0,0,0},{49,33,1},{43,33,0},{0,0,0},{19,24,0},{0,0,0}}, {{6,3,2},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}}, {{42,19,0},{46,19,0},{44,56,2},{0,0,0},{35,46,1},{42,11,0},{46,11,0},{0,0,0},{6,51,2}}, {{34,33,0},{50,58,0},{0,0,0},{33,20,1},{40,40,0},{0,0,0},{53,53,1},{33,22,1},{34,44,1}}, {{0,0,0},{40,37,0},{13,49,0},{57,57,0},{0,0,0},{15,43,0},{0,0,0},{0,0,0},{52,51,0}}, {{14,54,0},{12,40,0},{21,14,0},{14,40,0},{13,40,0},{0,0,0},{25,5,1},{55,43,0},{25,14,0}}, {{39,50,0},{8,4,0},{15,41,1},{0,0,0},{0,0,0},{4,23,0},{27,29,0},{0,0,0},{48,46,0}}, {{18,41,2},{34,51,2},{57,49,3},{53,43,2},{6,15,2},{0,0,0},{0,0,0},{24,50,3},{36,41,2}}, {{20,26,2},{56,50,0},{14,14,2},{32,26,2},{15,36,2},{14,57,0},{29,57,0},{56,35,1},{17,5,2}}, {{6,48,0},{7,53,0},{8,58,0},{6,19,0},{58,14,0},{57,19,0},{56,53,0},{55,58,0},{27,42,1}}, {{0,0,0},{0,0,0},{0,0,0},{25,4,2},{0,0,0},{5,14,2},{0,0,0},{0,0,0},{21,4,2}}, {{0,0,0},{10,9,0},{0,0,0},{38,10,0},{9,33,0},{10,3,0},{28,25,0},{0,0,0},{51,4,0}}, {{9,34,0},{0,0,0},{37,27,2},{0,0,0},{0,0,0},{13,43,0},{0,0,0},{39,43,2},{0,0,0}}, {{53,51,0},{14,25,0},{0,0,0},{7,2,2},{18,8,2},{0,0,0},{26,8,2},{3,8,2},{22,5,2}}, {{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}} }; u_char startpos[no_levs][2] = { //List of start positions for each level {6,57},{10,9},{5,53},{8,41},{4,8}, {4,29},{6,10},{42,32},{34,36},{9,7}, {58,18},{35,19},{33,55},{2,10},{17,57}, {27,46},{34,60},{18,53},{58,60},{40,7}, {32,59},{6,9},{7,58}}; u_char exitlist[no_levs][2] = { {9,18},{27,60},{5,33},{53,45},{2,39}, {61,23},{25,58},{57,39},{51,50},{3,5}, {3,52},{47,41},{53,29},{59,44},{2,24}, {3,48},{25,58},{60,20},{4,5},{57,5}, {60,3},{57,52},{0,0}}; u_char secretexits[no_levs][2] = { {0,0},{0,0},{0,0},{0,0},{0,0}, {0,0},{24,28},{0,0},{0,0},{0,0}, {0,0},{45,59},{0,0},{0,0},{5,5}, {0,0},{0,0},{0,0},{0,0},{0,0}, {0,0},{0,0},{0,0}}; u_char passcodes[no_levs-1][8] = { {6,4,6,9,2,1,7,9},{7,2,2,1,9,4,5,2}, {2,1,8,8,8,4,9,0},{4,0,2,0,1,9,6,5}, {5,1,0,2,5,1,0,6},{0,4,1,8,6,3,3,3}, {4,9,9,1,0,2,6,2},{5,3,0,6,9,0,0,1}, {1,3,8,2,0,6,0,7},{8,2,3,0,0,6,9,2}, {0,6,1,9,5,5,5,0},{5,9,0,4,2,7,1,8}, {3,3,0,1,8,9,2,7},{2,8,7,0,1,2,4,8}, {9,2,1,6,0,3,0,2},{3,1,0,0,8,9,2,3}, {0,6,7,3,1,9,1,0},{8,0,6,5,0,4,9,2}, {7,3,2,0,9,4,6,8},{0,6,3,2,5,0,9,1}, {2,8,4,5,2,1,2,7},{5,1,8,3,0,7,7,2}}; long leveladdresses[no_levs] = { //Where each level is in memory 0x80100000,0x80101000,0x80102000,0x80103000,0x80104000, 0x80105000,0x80106000,0x80107000,0x80108000,0x80109000, 0x8010A000,0x8010B000,0x8010C000,0x8010D000,0x8010E000, 0x8010F000,0x80110000,0x80111000,0x80112000,0x80113000, 0x80114000,0x80115000,0x80116000}; char * messages[26][3]; //All the messages that get used in the game short messlet[3][20][2]; //Angle and radius for each letter in //the currently displayed message u_char cointarget[no_levs] = {5,15,30,24,15,20,16,12,16,24, //Target number of coins 16,4,28,20,32,28,35,35,52,32, 25,62,0}; u_char animtable[no_tiles]; //What tile each tile animates to u_char nastylist[no_levs][32][6]; //List of the nasties in each level //0 Type of nasty (see below) //1-2 Map x,y starting position //3 Starting information dependent on type of nasty int nasties[64][12]; //List of the nasties in the level (maximum of 32) //0 Type of nasty (0-goblin, 255-none) //1-2 Map x,y position //3-4 The x,y displacement<<16 within tile //5 Hit points //6-11 Depends on the nasty int nastyflash[64]; /* Indicates how long a nasty should be black for * After being hit. This isn't part of nasties[][] * because it got added in later. */ u_short mapsprs[no_tiles][3]; // Collision data for each tile // Each tile is a 5x5 grid with each entry being either: // 0 - Empty // 1 - Solid u_char coldata[no_tiles][5][5] = { {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,1},{0,0,1,1,1},{1,1,1,1,1}}, {{0,0,0,1,1},{0,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,0,0,0},{1,1,1,1,0},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{0,0,0,0,0},{0,0,0,0,0},{1,0,0,0,0},{1,1,1,0,0},{1,1,1,1,1}}, {{0,0,0,0,1},{0,0,0,1,1},{0,0,1,1,1},{0,1,1,1,1},{1,1,1,1,1}}, {{1,0,0,0,0},{1,1,0,0,0},{1,1,1,0,0},{1,1,1,1,0},{1,1,1,1,1}}, {{0,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{0,1,1,1,1}}, //10 {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,0},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,0}}, {{0,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,0},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, //20 {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, //30 {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{0,0,0,0,0}}, //40 {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{0,0,0,0,0},{0,0,0,0,0}}, {{1,1,1,1,1},{1,1,1,1,1},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{1,1,1,1,1},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, //50 {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,1,1,1,0},{1,1,1,1,0},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,1,0,0},{0,1,1,1,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, //60 {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, //70 {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{0,0,0,0,0},{0,0,0,0,0}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{0,0,0,0,0},{0,0,0,0,0}}, {{0,1,1,1,1},{0,1,1,1,1},{0,0,1,1,1},{0,0,0,0,0},{0,0,0,0,0}}, {{1,1,1,1,0},{1,1,1,1,0},{1,1,1,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, //80 {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, //90 {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, //100 {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}, {{1,1,1,1,0},{1,1,1,1,0},{1,1,1,1,0},{1,1,1,1,0},{1,1,1,1,0}}, {{1,1,1,0,0},{1,1,1,0,0},{1,1,1,0,0},{1,1,1,0,0},{1,1,1,0,0}}, {{1,1,0,0,0},{1,1,0,0,0},{1,1,0,0,0},{1,1,0,0,0},{1,1,0,0,0}}, {{1,0,0,0,0},{1,0,0,0,0},{1,0,0,0,0},{1,0,0,0,0},{1,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, //110 {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{1,1,1,1,0},{1,1,1,1,0},{1,1,1,1,0},{1,1,1,1,0},{1,1,1,1,0}}, {{1,1,1,0,0},{1,1,1,0,0},{1,1,1,0,0},{1,1,1,0,0},{1,1,1,0,0}}, {{1,1,0,0,0},{1,1,0,0,0},{1,1,0,0,0},{1,1,0,0,0},{1,1,0,0,0}}, //120 {{1,0,0,0,0},{1,0,0,0,0},{1,0,0,0,0},{1,0,0,0,0},{1,0,0,0,0}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{0,0,0,0,0}}, {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{0,0,0,0,0},{0,0,0,0,0}}, {{1,1,1,1,1},{1,1,1,1,1},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{1,1,1,1,1},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,0,1,0,0},{0,1,1,1,0},{1,1,1,1,1},{0,1,1,1,0},{0,0,1,0,0}}, {{0,0,1,0,0},{0,1,1,1,0},{1,1,1,1,1},{0,1,1,1,0},{0,0,1,0,0}}, {{0,0,1,0,0},{0,1,1,1,0},{1,1,1,1,1},{0,1,1,1,0},{0,0,1,0,0}}, {{0,0,1,0,0},{0,1,1,1,0},{1,1,1,1,1},{0,1,1,1,0},{0,0,1,0,0}} }; // The collision information for tile that most monsters // use because they don't need to be that accurate. // Initialised by using the CheckSolid procedure u_char coldata2[no_tiles]; // Global vars extern DISPENV GsDISPENV; short vabno; short seqno; u_int randomseed; /* The random numbers generated for the time * period need to be the same each time. */ int side; int invuln=0; //Is player invulnerable int lotsablood=0; //More blood sir? int sfxvol=256; //Volume (0-256) int musicvol=96; //Volume (0-127) u_char ingame = 0; u_char quit, start,reachedexit,completed; int paradox; u_char reason; //Why there was a paradox //0 - Collided with an earlier version of yourself //1 - You got shot by an earlier version of yourself //2 - An earlier version of you got shot u_char map[64][64]; //The current map u_char mapx,mapy,mapxdis,mapydis; //Stores what pixel should be at //the top-left of screen int slipno; //How many times you have travelled back int time; //Current time within slip int maplookahead; int levno; short slipping; //If greater than zero than you are going back in time short exit = 0; //State of the exit short exitframe = 0; u_char animdelay = 0; u_char doanim = 0; u_char nocoins, totalcoins; //How many coins you have collected/there are in total u_char coinsprite = 0; long radarpos = 0; //What radar sprite is on screen u_char nastycount; //No. of nasties in level long pad; u_char message; //Message currently displayed (255 for none) u_char inout; //Message coming in/going out (0/1) u_char no_targs; //How many targets you have shot u_char trigmess; //Whether a trigger message as already been shown u_char secret; //Did you find a secret exit? // End level stuff int dobuzz; //Delay to making next buzzing noise, //for the end boss regenerating int nextbbslot; //The next slot that a bouncy ball //can be generated into int theend; int scrx, scry; //Position of the screen for when it's moving //between the different snail int targscrx, targscry; //Position the screen is heading for int timetochange; //Delay to moving to next snail int bossdeath; //Time when end boss was killed int bossdying; // Menu stuff int clocks[noclocks][6]; //Data about each clock in the BG x,y,xspeed,yspeed,angle,anglespeed int hand0, hand1; //Angle of each "Time Slip" short codeangle = 0; int putincheatdel = 0; u_char handsdirn = 0; //What way round the hands are going int digit; //What digit in the code is selected u_char passcode[8] = {0,0,0,0,0,0,0,0}; //The digits of the code u_char changedcode = 0; int starx,stary,nextstardel; //Star creators' x and y position u_char waitingforCD = 0; /**************************************************************************** prototypes ****************************************************************************/ void main (void); void PlotMenuMess(); void SetClipArea(int size); void Credits (void); void PlotCredits (void); void EndSequence (void); void PlotNYTitle (int bright); void PlotPlasmaEnergy(void); void SnapScreen (void); void MoveDust(void); void PlotDust(void); void MoveStars2(void); void PlotStars2(void); void PlotSnailDetector (void); void MoveBlood (void); void PlotBlood (void); void MoveNasties (void); void HitNasties (void); void HitNastyTune(int distance); void SplatBlood(int x, int y); int EnemyxSize(u_char type); int EnemyySize(u_char type); u_char CheckSolid (u_char tile); void PlotNasties (void); void PlotLineStar (int x, int y, int size, int angle, u_char r, u_char g, u_char b); void MoveMessage (void); void PlotMessage (void); void StartMessage (int id); void PlotLetter (u_char let, short x, short y, int angle, short radius); void MoveCoins (void); void CollectCoins (void); void GotAllCoins (void); void GotCoinTune(int distance); void AddStar(u_char snailno); void MenuCreateStars(); void PlotCoins (void); void PlotNumber (int no, short x, short y, u_short depth); int CheckCode (void); void PlotCode (void); void CheckExit (void); void PlotExit (void); void TimeSlipLogo (void); void MenuClocks (void); void PlotClock (short x, short y, int T); void MoveDoors (void); void UpdateDoor (door* D); void MoveBalls (void); void DeadSound (void); void PlotBalls (void); void MovePlatforms (void); u_char HitPlatform (snail* S, platform* P); void PlotPlatforms (void); long platformxpos (platform* P); long platformypos (platform* P); void PlotWhirl (void); void PlotStars (void); void ResetStars (void); void PlotBackgr (void); void PlotSnails (void); void MoveSnails (void); void MoveSnail(snail* you); void AddDust(snail* snptr); void OnSwitch (u_char x, u_char y); void LaunchBall (pastsnail* S); u_char CheckHitWall (snail* S); void TimeSlip (void); void ResetPositions (void); void MoveMap (void); void PlotMap (void); void StartNewLev (void); void SetupMap (void); void DealWithControllerPad(void); void MenuControlPad (void); void InitGsSprite (GsSPRITE* sprite); void InitialiseAll (void); void SetupNasties (void); void AddNasty (int lev, int id, u_char type, u_char x, u_char y, u_char mode1, u_char mode2, u_char mode3); void SetupPlatforms (void); void AddPlat (int lev, int id, u_char x, u_char y, u_char size, u_char type, int xdist, int ydist, int xang, int yang, int xsp, int ysp); /**************************************************************************** functions ****************************************************************************/ void main (void) { int hsync; int i; int nytitledel = 320; int scrsize = 0; InitialiseAll(); side = GsGetActiveBuff(); while(nytitledel>0) { GsSetWorkBase((PACKET*)packetArea[side]); GsClearOt(0,0,&Wot[side]); if (nytitledel>32) PlotNYTitle(128); else PlotNYTitle(nytitledel*4); nytitledel--; hsync = VSync(0); ResetGraph(1); GsSwapDispBuff(); GsSortClear(0,0,4,&Wot[side]); GsDrawOt(&Wot[side]); side ^= 1; FntFlush(-1); } while(quit != 2) { start = 0; quit = 0; digit = 0; ingame = 0; scrsize=160; // Title screen loop hsync = VSync(0); for (i=0;i<32;i++) stars2[i].lifespan = 0; mapx=mapy=20; mapxdis=mapydis=nextstardel=0; while((start==0 || scrsize>0) && quit==0) { GsSetWorkBase((PACKET*)packetArea[side]); GsClearOt(0,0,&Wot[side]); if (start!=0) { SetClipArea(scrsize); scrsize-=8; } if (start==0) MenuControlPad(); if (start==1 && levno>=100) { if (levno==100) invuln=1; if (levno==101) lotsablood=1; SsUtKeyOn(vabno,AllCoinsSnd,0,48,0,(sfxvol*52)>>8,(sfxvol*52)>>8); handsdirn=1-handsdirn; start=0; putincheatdel=1; } MenuClocks(); TimeSlipLogo(); PlotCode(); MenuCreateStars(); MoveStars2(); PlotStars2(); PlotMenuMess(); hsync = VSync(0); ResetGraph(1); GsSwapDispBuff(); GsSortClear(0,0,4,&Wot[side]); GsDrawOt(&Wot[side]); side ^= 1; FntFlush(-1); } while ((pad & PADstart) || (pad & PADRdown)) pad = PadRead(); StartNewLev(); ingame = 1; randomseed = rand(); theend = 0; completed = 0; // Main game loop hsync = VSync(0); while(quit==0 && reachedexit!=1 && paradox!=1 && !completed) { GsSetWorkBase((PACKET*)packetArea[side]); GsClearOt(0,0,&Wot[side]); if (scrsize<160) { scrsize+=8; SetClipArea(scrsize); } if (slipping==0) { DealWithControllerPad(); MovePlatforms(); if (!theend || !bossdying) MoveSnails(); if (theend==0 || time!=(bossdeath-2)) MoveNasties(); MoveBlood(); if (theend==1 && time==(bossdeath-2)) EndSequence(); if (levno==endlev && nasties[4][0]==255 && theend==0) { bossdeath = time; bossdying = 0; slipping=128; invuln=1; ResetStars(); SsUtKeyOn(vabno,SlipSnd,0,56,0,(sfxvol*64)>>8,(sfxvol*64)>>8); SsUtKeyOn(vabno,SlipSnd,0,53,0,(sfxvol*64)>>8,(sfxvol*64)>>8); SsUtKeyOn(vabno,SlipSnd,0,50,0,(sfxvol*64)>>8,(sfxvol*64)>>8); theend=1; } MoveBalls(); MoveMap(); MoveDoors(); CheckExit(); MoveCoins(); MoveStars2(); MoveDust(); if (message<255) MoveMessage(); } if (message<255) PlotMessage(); PlotMap(); if (levno!=10 && levno!=16) PlotBackgr(); PlotSnails(); PlotBalls(); PlotSnailDetector(); PlotNasties(); PlotBlood(); PlotStars2(); PlotDust(); PlotClock(160,16,(time*2048)/slipsize); if (levno==endlev) { PlotPlasmaEnergy(); } else { PlotPlatforms(); PlotCoins(); PlotExit(); } if (paradox==300) SsUtKeyOn(vabno,DyingSnd,0,46,0,(sfxvol*64)>>8,(sfxvol*64)>>8); if (paradox==270) SsUtKeyOn(vabno,DyingSnd,0,44,0,(sfxvol*64)>>8,(sfxvol*64)>>8); if (paradox==240) SsUtKeyOn(vabno,DyingSnd,0,42,0,(sfxvol*64)>>8,(sfxvol*64)>>8); if (paradox==210) SsUtKeyOn(vabno,DyingSnd,0,40,0,(sfxvol*64)>>8,(sfxvol*64)>>8); if (paradox==180) SsUtKeyOn(vabno,DyingSnd,0,38,0,(sfxvol*64)>>8,(sfxvol*64)>>8); if (paradox==150) SsUtKeyOn(vabno,DyingSnd,0,36,0,(sfxvol*64)>>8,(sfxvol*64)>>8); if (paradox==120) SsUtKeyOn(vabno,DyingSnd,0,34,0,(sfxvol*64)>>8,(sfxvol*64)>>8); if (slipping == 0) { if (theend==0 || time!=(bossdeath-2)) { if (++time == slipsize) { time = slipsize-1; slipping=128; ResetStars(); SsUtKeyOn(vabno,SlipSnd,0,56,0,(sfxvol*64)>>8,(sfxvol*64)>>8); SsUtKeyOn(vabno,SlipSnd,0,53,0,(sfxvol*64)>>8,(sfxvol*64)>>8); SsUtKeyOn(vabno,SlipSnd,0,50,0,(sfxvol*64)>>8,(sfxvol*64)>>8); } } } else { if (paradox == 0) { PlotWhirl(); PlotStars(); } else slipping = 1; if (--slipping == 0) TimeSlip(); } hsync = VSync(0); /* if (hsync > 312) { if (slipping==0) { DealWithControllerPad(); MovePlatforms(); MoveSnails(); MoveNasties(); MoveBalls(); MoveMap(); MoveDoors(); CheckExit(); MoveCoins(); MoveStars2(); MoveDust(); if (message<255) MoveMessage(); if (++time == slipsize) {time = slipsize-1; slipping=128; ResetStars();} } else if (--slipping == 0) TimeSlip(); } */ ResetGraph(1); GsSwapDispBuff(); GsSortClear(0,0,4,&Wot[side]); GsDrawOt(&Wot[side]); side ^= 1; FntFlush(-1); } if (scrsize<160) { scrsize=160; SetClipArea(scrsize); } if (theend) Credits(); //SnapScreen(); if (reachedexit == 1) { if (levno == no_levs) for (i=0;i<8;i++) passcode[i] = 0; else { if (levno==9) levno=10; if (levno==17) levno=21; if (levno==20) levno=16; if (levno==7 && secret==1) levno=9; if (levno==12 && secret==1) levno=17; if (levno==15 && secret==1) levno=20; for (i=0;i<8;i++) passcode[i] = passcodes[levno-1][i]; } } } SsVabClose(vabno); ResetGraph(3); } char* menumes[6] = { " use the direction ", " buttons to change ", " the level code ", " press x to start ", " press o to play ", " a music cd "}; char* menumes2[5] = { "please insert music ", " cd into drive ", " press x to play ", " press o to cancel ", " "}; void PlotMenuMess() { GsSPRITE letter; int x,y; char let; InitGsSprite (&letter); letter.x = 0; letter.y = 16; letter.w = 16; letter.h = 16; for (y=0;y<6;y++) { for (x=0;x<20;x++) { if (!waitingforCD) let = menumes[y][x]; else let = menumes2[y][x]; if (let==47) { CalcSprPos (letter, (320<<1) + 160, 184); GsSortFastSprite( &letter, &Wot[side], 0); } if (let>47 && let<58) { CalcSprPos (letter, (320<<1) + ((let-48)<<4), 184); GsSortFastSprite( &letter, &Wot[side], 0); } if (let>96 && let<123) { CalcSprPos (letter, (384<<1) + (((let-97) % 13)<<4), 100 + (((let-97)/13)<<4)); GsSortFastSprite( &letter, &Wot[side], 0); } if ((letter.x+=16) == 320) { letter.x = 0; letter.y+=16; if (y==2 && PAL) letter.y=208; if (y==2 && !PAL) letter.y=184; } } } } void SetClipArea(int size) { RECT scr; scr.x = 160-size; scr.w = size*2; if (PAL) { if (size<128) scr.y = 128-size; else scr.y = 0; if (size<128) scr.h = size*2; else scr.h = 256; } else { if (size<120) scr.y = 120-size; else scr.y = 0; if (size<120) scr.h = size*2; else scr.h = 240; } GsSetClip2D(&scr); GsSetDrawBuffClip(); } #define creditlines 133 char* credits[creditlines] = { " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "congratulations you ", " have restored the ", " time line back to ", " normal and can now ", " return to a normal ", " peaceful life ", " ", " ", " ", " ", " ", " or at least until ", " the next universe ", " threatening hazard ", " comes your way ", " ", " ", " ", " ", " ", " ", " ", " ", " this game was made ", " by ", " ", " ", " david johnston ", " programming ", " game concept ", " level design ", " everything except ", " the graphics ", " ", " ", " mike goatly ", " graphics ", " ", " ", " ", " ", " ", " ", " ", " ", " thanks to ", " ", " ", " my mum and dad ", " ", " ", " james shaughnessy ", " for converting the ", " sound ", " ", " ", " stephen mcnally ", "for playtesting the ", " game ", " ", " ", " kenneth may ", "for playtesting the ", " game ", " ", " ", " ", " ", " ", " ", " ", " ", " general mentions ", " ", " ", " group for my team ", " project at uni ", " ", " paul radziwonik ", " kenneth ritch ", " robert japp ", "ioannis giannopolous", " ", " ", " for giving me ", " discounts on games ", " ben wooldridge ", " ", " ", " everyone who did ", " level 3 computing ", " science at glasgow ", " uni in 98/99 ", " ", " ", " ", " ", " ", " ", " ", " ", " the end ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "}; int curline, linedisp; void Credits() { int hsync; int finish=0; curline = 0; linedisp = 0; invuln=0; while (!(PadRead() & PADselect) && finish<480) { GsSetWorkBase((PACKET*)packetArea[side]); GsClearOt(0,0,&Wot[side]); PlotMap(); PlotBackgr(); PlotSnailDetector(); PlotPlasmaEnergy(); PlotClock(160,16,(time*2048)/slipsize); PlotCredits(); if (curline<113) { if ((++linedisp) == 32) { linedisp=0; curline++; } } else finish++; hsync = VSync(0); ResetGraph(1); GsSwapDispBuff(); GsSortClear(0,0,4,&Wot[side]); GsDrawOt(&Wot[side]); side ^= 1; FntFlush(-1); } while (PadRead() & PADselect) ; } void PlotCredits () { GsSPRITE letter; int x,y; char let; InitGsSprite (&letter); letter.x = 0; letter.y = -(linedisp>>1); letter.w = 16; letter.h = 16; for (y=0;y<16;y++) { for (x=0;x<20;x++) { let = credits[curline+y][x]; if (let==47) { CalcSprPos (letter, (320<<1) + 160, 184); GsSortFastSprite( &letter, &Wot[side], 14); } if (let>47 && let<58) { CalcSprPos (letter, (320<<1) + ((let-48)<<4), 184); GsSortFastSprite( &letter, &Wot[side], 14); } if (let>96 && let<123) { CalcSprPos (letter, (384<<1) + (((let-97) % 13)<<4), 100 + (((let-97)/13)<<4)); GsSortFastSprite( &letter, &Wot[side], 14); } if ((letter.x+=16) == 320) { letter.x = 0; letter.y+=16; } } } } void EndSequence () { int i; if ((++bossdying) == 512) { for (i=0;i<64;i++) nasties[i][0] = 255; for (i=0;i<=slipno;i++) snails[slipno][time].x = 0; } if (bossdying==580) { completed=1; SsUtKeyOn(vabno,AllCoinsSnd,0,48,0,(sfxvol*80)>>8,(sfxvol*80)>>8); } if (bossdying<512) { if ((bossdying % 8) == 0) HitNastyTune(64); if ((bossdying % 2) == 0) { if ((stars2ptr--) == 0) stars2ptr = 31; stars2[stars2ptr].x = 33; stars2[stars2ptr].y = 53 + (rand() % 4); stars2[stars2ptr].xdis = ((rand() % 20)<<16); stars2[stars2ptr].ydis = ((rand() % 20)<<16); stars2[stars2ptr].angle = rand() % 4096; stars2[stars2ptr].lifespan = 96; stars2[stars2ptr].xspeed = ((rand() - 16384)<<2); stars2[stars2ptr].yspeed = -((32768+rand())<<2); } SplatBlood((33*20)+(rand() % 20), (53*20)+(rand() % 80)); if (bossdying>128 && (bossdying % 2) == 0) { if ((nexthex--) == 0) nexthex = 31; hexs[nexthex].x = 160+(rand() % 40); hexs[nexthex].y = 80+(rand() % 110); hexs[nexthex].angle = rand() % 4096; hexs[nexthex].size = 10<<8; hexs[nexthex].r = rand() % 255; hexs[nexthex].g = rand() % 255; hexs[nexthex].b = rand() % 255; } } for (i=0;i<32;i++) { if (hexs[nexthex].angle!=-1) { PlotLineStar(hexs[i].x, hexs[i].y, hexs[i].size>>8, hexs[i].angle, hexs[i].r, hexs[i].g, hexs[i].b); if ((hexs[i].angle+=32)>=4096) hexs[i].angle-=4096; hexs[i].size+=(hexs[i].size>>3); if (hexs[i].size>(512<<8)) hexs[i].size=(512<<8); } } } void PlotNYTitle(int bright) { GsSPRITE titlespr, info; int offset; if (PAL) offset=8; else offset=0; InitGsSprite (&titlespr); titlespr.attribute = 1<<25; titlespr.r = titlespr.g = titlespr.b = bright; titlespr.x = 0; titlespr.y = offset; titlespr.w = 160; titlespr.h = 240; CalcSprPos (titlespr, (320*2), 256); GsSortFastSprite( &titlespr, &Wot[side], 1); titlespr.x = 160; CalcSprPos (titlespr, (464*2), 256); GsSortFastSprite( &titlespr, &Wot[side], 1); InitGsSprite(&info); info.r = info.g = info.b = bright; info.x = 32; info.y = 136+offset; info.w = 256; info.h = 16; CalcSprPos (info, (640*2), 256); GsSortSprite( &info, &Wot[side], 0); info.y = 166+offset; CalcSprPos (info, (640*2), 272); GsSortSprite( &info, &Wot[side], 0); info.y = 200+offset; CalcSprPos (info, (640*2), 288); GsSortSprite( &info, &Wot[side], 0); } void PlotPlasmaEnergy() { GsBOXF EnergyBar; GsLINE Box; int height, totheight, ypos, base; height = (3*nasties[4][5])>>1; if (PAL) { ypos = 256-height; totheight = (255-192); base = 255; } else { ypos = 240-height; totheight = (239-192); base = 239; } Box.attribute = 0; Box.x0 = 10; Box.y0 = totheight; Box.x1 = 10; Box.y1 = base; Box.r = 0; Box.g = 160; Box.b = 0; GsSortLine(&Box, &Wot[side], 2); Box.x1 = 18; Box.y1 = totheight; GsSortLine(&Box, &Wot[side], 2); Box.x0 = 18; Box.y0 = base; Box.x1 = 10; Box.y1 = base; GsSortLine(&Box, &Wot[side], 2); Box.x1 = 18; Box.y1 = totheight; GsSortLine(&Box, &Wot[side], 2); EnergyBar.attribute = 0; EnergyBar.x = 10; EnergyBar.y = ypos; EnergyBar.w = 8; EnergyBar.h = height; EnergyBar.r = 0; EnergyBar.g = 120; EnergyBar.b = 0; GsSortBoxFill(&EnergyBar, &Wot[side], 2); } void SnapScreen () { RECT screen; u_long writeaddr; screen.x = screen.y = 0; screen.w = 320; screen.h = 256; writeaddr = MAINSPRS_ADDRESS; StoreImage(&screen, &writeaddr); DrawSync(0); } void MoveDust (void) { register long i; for (i=0;i<8;i++) { if (dusts[i].sprite > 0) { dusts[i].sprite--; dusts[i].x+=dusts[i].xspeed; dusts[i].y+=dusts[i].yspeed; dusts[i].yspeed+=32; } } } void PlotDust (void) { register long i; register GsSPRITE* dustspr = (GsSPRITE*)getScratchAddr(sizeof(GsSPRITE)); u_char sprno; InitGsSprite (dustspr); dustspr->w = dustspr->h = 8; for (i=0;i<8;i++) { if (dusts[i].sprite > 0) { sprno = 7-(dusts[i].sprite/4); if (sprno < 4) {CalcSprPos2 (dustspr, 848+sprno*8, 200);} else {CalcSprPos2 (dustspr, 848+(sprno-4)*8, 208);} dustspr->x = (dusts[i].x>>8)-((mapx*20)+mapxdis); dustspr->y = (dusts[i].y>>8)-((mapy*20)+mapydis); GsSortFastSprite( dustspr, &Wot[side], 9); } } } void MoveStars2 (void) { register long i; int maxcoins; if (ingame) maxcoins = 32; else maxcoins = 128; for (i=0;i 0) { stars2[i].lifespan--; stars2[i].xdis+=stars2[i].xspeed; stars2[i].ydis+=stars2[i].yspeed; stars2[i].yspeed+=12288; if ((stars2[i].angle+=128) >= 4096) stars2[i].angle-=4096; if (stars2[i].xdis<0) { stars2[i].xdis+=(20<<16); stars2[i].x--; } if (stars2[i].xdis>=(20<<16)) { stars2[i].xdis-=(20<<16); stars2[i].x++; } if (stars2[i].ydis<0) { stars2[i].ydis+=(20<<16); stars2[i].y--; } if (stars2[i].ydis>=(20<<16)) { stars2[i].ydis-=(20<<16); stars2[i].y++; } } } } void PlotStars2 (void) { register long i; register GsSPRITE* starspr = (GsSPRITE*)getScratchAddr(sizeof(GsSPRITE)); int maxcoins; if (ingame) maxcoins = 32; else maxcoins = 128; InitGsSprite (starspr); starspr->w = starspr->h = 16; CalcSprPos2 (starspr, 832, 200); for (i=0;i 0) { starspr->x = (((stars2[i].x-mapx)*20)-mapxdis)+(stars2[i].xdis>>16)+8; starspr->y = (((stars2[i].y-mapy)*20)-mapydis)+(stars2[i].ydis>>16)+8; starspr->rotate = (360*(stars2[i].angle+512)); if (starspr->rotate>=(4096*360)) starspr->rotate-=(4096*360); starspr->x += (34*DJsin(stars2[i].angle))/12288; starspr->y -= (34*DJcos(stars2[i].angle))/12288; GsSortSprite( starspr, &Wot[side], 6); } } } void PlotSnailDetector (void) { // Plot radar telling you where past echoes are near register GsSPRITE* snailspr = (GsSPRITE*)getScratchAddr(sizeof(GsSPRITE)); GsSPRITE radarspr; register long i; GsGLINE line; long nearest = -1; long dx,dy,worldposx1,worldposy1,worldposx2,worldposy2,yscrpos; long dist; InitGsSprite (snailspr); snailspr->attribute = (snailspr->attribute | (1<<30)); snailspr->cy = 510; InitGsSprite (&radarspr); radarspr.w = radarspr.h = 16; //radarspr.attribute = (radarspr.attribute | (1<<30)); //radarspr.cy = 510; if ((radarpos+=2) == (12*8)) radarpos = 0; CalcSprPos(radarspr, 640+((radarpos>>3)<<4), 200); if (PAL) { radarspr.x = 152; radarspr.y = 192; yscrpos = 200; } else { radarspr.x = 152; radarspr.y = 186; yscrpos = 194; } line.attribute = (1<<30); line.x0 = 160; line.y0 = yscrpos; line.r0 = line.g0 = line.b0 = 0; line.r1 = line.g1 = line.b1 = 255; if (slipno>0) { worldposx1 = (20*snails[slipno][time].x) + snails[slipno][time].xdis; worldposy1 = (20*snails[slipno][time].y) + snails[slipno][time].ydis; for (i=0;iscalex = snailspr->scaley = (1024-dist)*4; snailspr->x = (160+((worldposx2-worldposx1)>>4))-((10*(1024-dist))>>10); snailspr->y = (yscrpos+((worldposy2-worldposy1)>>4))-((10*(1024-dist))>>10); line.x1 = 160+((worldposx2-worldposx1)>>4); line.y1 = yscrpos+((worldposy2-worldposy1)>>4); GsSortGLine( &line, &Wot[side], 6); GsSortSprite( snailspr, &Wot[side], 6); } } } GsSortSprite(&radarspr, &Wot[side], 6); } void MoveBlood (void) { register long i; for (i=0;i<64;i++) { if (blood[i].x != 255) { blood[i].yspeed+=16384; blood[i].xdis+=blood[i].xspeed; blood[i].ydis+=blood[i].yspeed; if (blood[i].xdis<0) {blood[i].xdis+=(20<<16); blood[i].x--;} if (blood[i].xdis>(20<<16)) {blood[i].xdis-=(20<<16); blood[i].x++;} if (blood[i].ydis<0) {blood[i].ydis+=(20<<16); blood[i].y--;} if (blood[i].ydis>(20<<16)) {blood[i].ydis-=(20<<16); blood[i].y++;} if (++blood[i].delay == 6) { blood[i].delay = 0; if (++blood[i].sprite == 8) blood[i].x = 255; } } } } void PlotBlood (void) { register long i; GsSPRITE bloodspr; InitGsSprite(&bloodspr); bloodspr.w = bloodspr.h = 16; for (i=0;i<64;i++) { if (blood[i].x != 255) { bloodspr.x = (((blood[i].x-mapx)*20)-mapxdis)+(blood[i].xdis>>16); bloodspr.y = (((blood[i].y-mapy)*20)-mapydis)+(blood[i].ydis>>16); CalcSprPos (bloodspr, 408*2 + blood[i].sprite*16, 184); GsSortFastSprite( &bloodspr, &Wot[side], 6); } } } void MoveNasties (void) { register long i; int j,x1,y1,xsize,ysize,x2,y2; int temp1,temp2,temp3,vol; int rnd[4]; srand(time*randomseed); for (i=0;i<4;i++) rnd[i] = rand(); for (i=0;i0) nastyflash[i]--; xsize = EnemyxSize(nasties[i][0]); ysize = EnemyySize(nasties[i][0]); // Move the nasty switch (nasties[i][0]) { case 0 : // Goblin // Check if the goblin got squished by something if (nasties[i][3] == 0) { if (coldata2[map[nasties[i][1]][nasties[i][2]]] != 0) { x1 = nasties[i][1]*20 + (nasties[i][3]>>16); y1 = nasties[i][2]*20 + (nasties[i][4]>>16); SplatBlood(x1 + 8, y1 + 8); SplatBlood((x1 + xsize) - 8, y1 + 8); SplatBlood(x1 + 8, (y1 + ysize) - 8); SplatBlood((x1 + xsize) - 8, (y1 + ysize) - 8); nasties[i][0] = 255; } } if (nasties[i][3] != 0) { if (coldata2[map[nasties[i][1]][nasties[i][2]]] != 0 || coldata2[map[nasties[i][1]+1][nasties[i][2]]] != 0) { x1 = nasties[i][1]*20 + (nasties[i][3]>>16); y1 = nasties[i][2]*20 + (nasties[i][4]>>16); SplatBlood(x1 + 8, y1 + 8); SplatBlood((x1 + xsize) - 8, y1 + 8); SplatBlood(x1 + 8, (y1 + ysize) - 8); SplatBlood((x1 + xsize) - 8, (y1 + ysize) - 8); nasties[i][0] = 255; } } // Move right or left if (nasties[i][6] == 0) { if ((nasties[i][3]+=(2<<16)) == (20<<16)) { nasties[i][3] = 0; nasties[i][1]++; } if (nasties[i][3] == 0) { if (coldata2[map[nasties[i][1]+1][nasties[i][2]]] != 0) nasties[i][6]=1; if (coldata2[map[nasties[i][1]+1][nasties[i][2]+1]] != 2) nasties[i][6]=1; } } else { if ((nasties[i][3]-=(2<<16)) < 0) { nasties[i][3]+=(20<<16); nasties[i][1]--; } if (nasties[i][3] == 0) { if (coldata2[map[nasties[i][1]-1][nasties[i][2]]] != 0) nasties[i][6]=0; if (coldata2[map[nasties[i][1]-1][nasties[i][2]+1]] != 2) nasties[i][6]=0; } } // Waggle feet if (++nasties[i][8] == 4) {nasties[i][7]=1-nasties[i][7]; nasties[i][8] = 0;} break; case 1 : //Electric sphere nasties[i][1] = nastylist[levno-1][i][1]; nasties[i][2] = nastylist[levno-1][i][2]; x2 = (((nasties[i][7]*DJsin(nasties[i][8]))/4096)*DJsin(nasties[i][6]))/4096; y2 = (((nasties[i][7]*DJsin(nasties[i][8]))/4096)*DJcos(nasties[i][6]))/4096; while (x2>=20) {x2-=20; nasties[i][1]++;} while (x2<0) {x2+=20; nasties[i][1]--;} while (y2>=20) {y2-=20; nasties[i][2]++;} while (y2<0) {y2+=20; nasties[i][2]--;} nasties[i][3] = (x2<<16); nasties[i][4] = (y2<<16); if ((nasties[i][8]+=2) >= 4096) nasties[i][8]-=4096; if ((nasties[i][6]+=nasties[i][9]) >= 4096) nasties[i][6]-=4096; break; case 2 : //Stinger nasties[i][2] = nastylist[levno-1][i][2]; y2 = (nasties[i][6]*DJsin(nasties[i][7]))/4096; while (y2>=20) {y2-=20; nasties[i][2]++;} while (y2<0) {y2+=20; nasties[i][2]--;} nasties[i][4] = (y2<<16); if ((nasties[i][7]+=nasties[i][8]) >= 4096) nasties[i][7]-=4096; if (++nasties[i][9] == 16) nasties[i][9] = 0; break; case 3 : //Spike ball if (nasties[i][6]!=0) { temp1 = nasties[i][1]; temp2 = nasties[i][3]; if (nasties[i][6]>0) nasties[i][6]-=8192; if (nasties[i][6]<0) nasties[i][6]+=8192; nasties[i][3]+=nasties[i][6]; if (nasties[i][3]>(20<<16)) { nasties[i][3]-=(20<<16); nasties[i][1]++; } if (nasties[i][3]<0) { nasties[i][3]+=(20<<16); nasties[i][1]--; } if (coldata2[map[nasties[i][1]][nasties[i][2]]] != 0 || coldata2[map[nasties[i][1]+1][nasties[i][2]]] != 0) { nasties[i][1] = temp1; nasties[i][3] = temp2; nasties[i][6] = -nasties[i][6]; } } break; case 4 : //Robot switch (nasties[i][7]) { case 0: // Standing if ((--nasties[i][9]) == 0) { // Turn around every now and then nasties[i][7] = 1; nasties[i][9] = 1; if (nasties[i][6]==1) nasties[i][8] = 4; } for (j=0;j<=slipno;j++) { temp2 = (20*snails[j][time].y) + (snails[j][time].ydis>>16); temp2 = temp2 - ((20*nasties[i][2]) + (nasties[i][4]>>16)); if (temp2 > -40 && temp2 < 40) { temp2 = (20*snails[j][time].x) + (snails[j][time].xdis>>16); temp2 = temp2 - ((20*nasties[i][1]) + (nasties[i][3]>>16)); if ((nasties[i][6]==0 && temp2>20 && temp2<160) || (nasties[i][6]==1 && temp2<-20 && temp2>-160)) { nasties[i][7] = 2; nasties[i][8] = 0; nasties[i][9] = 2; nasties[i][10] = 0; nasties[i][11] = 256; } } } break; case 1: // Turning around if ((--nasties[i][9]) == 0) { nasties[i][9] = 4; // Change sprite depending on direction if (nasties[i][6] == 0) { if ((++nasties[i][8]) == 5) { // Go back to just standing nasties[i][6] = 1; nasties[i][7] = 0; nasties[i][8] = 0; nasties[i][9] = 192; } } else { if ((--nasties[i][8]) < 0) { // Go back to just standing nasties[i][6] = 0; nasties[i][7] = 0; nasties[i][8] = 0; nasties[i][9] = 192; } } } break; case 2: // Moving forwards // Turn the wheel if ((--nasties[i][9]) == 0) { nasties[i][9] = 2; if (nasties[i][10]<=16384) nasties[i][8] = 0; else if (nasties[i][10]<=32768) nasties[i][8] = 1; else if (nasties[i][10]<=49152) nasties[i][8] = 2; else if (nasties[i][10]<=65536) nasties[i][8] = 3; else if ((++nasties[i][8]) == 11) nasties[i][8] = 3; } if (nasties[i][11]-- == 0) { nasties[i][11] = 0; if (nasties[i][10] == 0) { // Go back to just standing nasties[i][7] = 0; nasties[i][8] = 0; nasties[i][9] = 192; } } if (nasties[i][6] == 0) { if (nasties[i][11] > 0) { if ((nasties[i][10]+=2048) > (4<<16)) nasties[i][10] = (4<<16); } else nasties[i][10]-=2048; if ((nasties[i][3]+=nasties[i][10]) > (20<<16)) { nasties[i][1]++; nasties[i][3]-=(20<<16); } temp1 = map[nasties[i][1]][nasties[i][2]]; temp2 = map[nasties[i][1]][nasties[i][2]+1]; temp3 = map[nasties[i][1]][nasties[i][2]+2]; if (coldata2[temp1]!=0 || coldata2[temp2]!=0 || coldata2[temp3]!=2) { nasties[i][1]--; nasties[i][3] = 0; nasties[i][6] = 1; } } else { if (nasties[i][11] > 0) { if ((nasties[i][10]+=2048) > (4<<16)) nasties[i][10] = (4<<16); } else nasties[i][10]-=2048; if ((nasties[i][3]-=nasties[i][10]) < 0) { nasties[i][1]--; nasties[i][3]+=(20<<16); } temp1 = map[nasties[i][1]][nasties[i][2]]; temp2 = map[nasties[i][1]][nasties[i][2]+1]; temp3 = map[nasties[i][1]][nasties[i][2]+2]; if (coldata2[temp1]!=0 || coldata2[temp2]!=0 || coldata2[temp3]!=2) { nasties[i][1]++; nasties[i][3] = 0; nasties[i][6] = 0; } } break; } break; case 5: nasties[i][6]+=8192; nasties[i][4]+=nasties[i][6]; if (nasties[i][4]>(20<<16)) { nasties[i][4]-=(20<<16); nasties[i][2]++; } if (nasties[i][4]<0) { nasties[i][4]+=(20<<16); nasties[i][2]--; } if (nasties[i][6] == (4<<16)) nasties[i][6]=-((4<<16)+8192); break; case 6: temp1 = (32*20)+10+(240*DJsin(nasties[i][6]))/4096; temp2 = (45*20)+(240*DJcos(nasties[i][6]))/4096; nasties[i][1] = temp1/20; nasties[i][2] = temp2/20; nasties[i][3] = (temp1 % 20)<<16; nasties[i][4] = (temp2 % 20)<<16; // Check to see if it should launch a bouncy ball if (rnd[i]<48 && nextbbslot<64) { nasties[nextbbslot][0] = 8; nasties[nextbbslot][1] = nasties[i][1]+1; nasties[nextbbslot][2] = nasties[i][2]; nasties[nextbbslot][3] = nasties[i][3]; nasties[nextbbslot][4] = nasties[i][4]; nasties[nextbbslot][5] = 8; nasties[nextbbslot][6] = rnd[i] % 4; nextbbslot++; nastycount++; } if (nasties[i][1] >= 30 && nasties[i][1] <= 34 && nasties[i][2]>45) { // Regenerate the plasma wotsit if (nasties[4][5]<128) nasties[4][5]+=2; if ((dobuzz--) == 0) { dobuzz = 5; x1 = (20*cursnail.x) + (cursnail.xdis>>16); y1 = (20*cursnail.y) + (cursnail.ydis>>16); x1 = x1 - temp1; if (x1<0) x1=-x1; y1 = y1 - temp2; if (y1<0) y1=-y1; vol = 80-((x1+y1)>>3); if (vol>0) SsUtKeyOn(vabno,BuzzSnd,0,48,0,(sfxvol*vol)>>8,(sfxvol*vol)>>8); if ((stars2ptr--) == 0) stars2ptr = 31; stars2[stars2ptr].x = nasties[i][1]+1; stars2[stars2ptr].y = nasties[i][2]; stars2[stars2ptr].xdis = nasties[i][3]; stars2[stars2ptr].ydis = nasties[i][4]; stars2[stars2ptr].angle = rand() % 4096; stars2[stars2ptr].lifespan = 96; stars2[stars2ptr].xspeed = ((rand() - 16384)<<2); stars2[stars2ptr].yspeed = -((32768+rand())<<2); } } if ((nasties[i][6]+=8) >= 4096) nasties[i][6]-=4096; if (--nasties[i][8] < 0) { nasties[i][7] = rand() % 4; nasties[i][8] = 2+(rand() % 4); } break; case 7: if ((nasties[i][7]--) == 0) { nasties[i][7] = 3; if (nasties[i][8]) { if ((--nasties[i][6]) == 0) nasties[i][8] = 0; } else { if ((++nasties[i][6]) == 5) nasties[i][8] = 1; } } break; case 8: x1 = nasties[i][1]; y1 = nasties[i][2]; temp1 = nasties[i][3]; temp2 = nasties[i][4]; if (nasties[i][6]==0 || nasties[i][6]==3) { if ((nasties[i][4]-=(2<<16)) < 0) { nasties[i][2]--; nasties[i][4]+=(20<<16); } } else { if ((nasties[i][4]+=(2<<16)) > (20<<16)) { nasties[i][2]++; nasties[i][4]-=(20<<16); } } if (coldata2[map[nasties[i][1]][nasties[i][2]]] != 0 || coldata2[map[nasties[i][1]+1][nasties[i][2]]] != 0 || coldata2[map[nasties[i][1]][nasties[i][2]+1]] != 0 || coldata2[map[nasties[i][1]+1][nasties[i][2]+1]] != 0) { if (nasties[i][6]<2) nasties[i][6]=1-nasties[i][6]; else nasties[i][6]=5-nasties[i][6]; nasties[i][2] = y1; nasties[i][4] = temp2; } if (nasties[i][6]==2 || nasties[i][6]==3) { if ((nasties[i][3]-=(2<<16)) < 0) { nasties[i][1]--; nasties[i][3]+=(20<<16); } } else { if ((nasties[i][3]+=(2<<16)) > (20<<16)) { nasties[i][1]++; nasties[i][3]-=(20<<16); } } if (coldata2[map[nasties[i][1]][nasties[i][2]]] != 0 || coldata2[map[nasties[i][1]+1][nasties[i][2]]] != 0 || coldata2[map[nasties[i][1]][nasties[i][2]+1]] != 0 || coldata2[map[nasties[i][1]+1][nasties[i][2]+1]] != 0) { nasties[i][6]=3-nasties[i][6]; nasties[i][1] = x1; nasties[i][3] = temp1; } break; } if (nasties[i][0] != 255) { // Check if you have been killed by the nasty x1 = nasties[i][1]*20 + (nasties[i][3]>>16); y1 = nasties[i][2]*20 + (nasties[i][4]>>16); if (paradox == 0 && reachedexit == 0 && !invuln) { for (j=0;j<=slipno;j++) { x2 = snails[j][time].x*20 + snails[j][time].xdis; y2 = snails[j][time].y*20 + snails[j][time].ydis; if (x2>x1-20 && x2y1-20 && y2x1-8 && x2y1-8 && y2(4<<16)) nasties[i][6]=(4<<16); if (nasties[i][6]<-(4<<16)) nasties[i][6]=-(4<<16); } else { SplatBlood(x2 + 4, y2 + 4); balls[j].x = 255; if (--nasties[i][5] == 0) { nasties[i][0] = 255; SplatBlood(x1 + 8, y1 + 8); SplatBlood((x1 + xsize) - 8, y1 + 8); SplatBlood(x1 + 8, (y1 + ysize) - 8); SplatBlood((x1 + xsize) - 8, (y1 + ysize) - 8); } } } } */ } } // This asm procedure takes the place // of the commented out C code above HitNasties(); } asm void HitNasties() { // s0 - nasty ptr, s1 - ballptr, s2 - nasty xpos, s3 - nasty ypos // s4 - x size, s5 - y size, s6 - nastyflash ptr .set reorder addiu sp,sp,-32 sw s0,4(sp) sw s1,8(sp) sw s2,12(sp) sw s3,16(sp) sw s4,20(sp) sw s5,24(sp) sw s6,28(sp) sw ra,32(sp) la s0,nasties add s0,s0,32*12*4 la s6,nastyflash add s6,s6,32*4 hitnastylp2: sub s0,s0,12*4 sub s6,s6,4 lw a0,0(s0) // type of nasty beq a0,255,skiphitnasty2 lw s2,4(s0) // nasty.x lw s3,8(s0) // nasty.y sll t0,s2,2 // nasty.x*20 add s2,s2,t0 sll s2,s2,2 sll t0,s3,2 // nasty.y*20 add s3,s3,t0 sll s3,s3,2 lw t0,12(s0) // nasty.xdis lw t1,16(s0) // nasty.ydis srl t0,t0,16 srl t1,t1,16 add s2,s2,t0 // x*20 + xdis add s3,s3,t1 // y*20 + ydis jal EnemyxSize move s4,v0 lw a0,0(s0) jal EnemyySize move s5,v0 la s1,balls add s1,s1,noballs*sizeof(ball) hitnastylp1: sub s1,s1,sizeof(ball) lbu t0,0(s1) // ball.x beq t0,255,skiphitnasty1 lbu t1,1(s1) // ball.y lb t2,3(s1) // ball.xdis lb t3,4(s1) // ball.ydis sll t4,t0,2 // ball.x*20 + xdis add t0,t0,t4 sll t0,t0,2 add t0,t0,t2 sll t4,t1,2 // ball.y*20 + ydis add t1,t1,t4 sll t1,t1,2 add t1,t1,t3 //if (x2>x1-8 && x2y1-8 && y2>8,(sfxvol*distance)>>8); } void SplatBlood(int x, int y) { x-=8; y-=8; blood[nextblood].x = x/20; blood[nextblood].y = y/20; blood[nextblood].xdis = x % 20; blood[nextblood].ydis = y % 20; blood[nextblood].xspeed = (8*rand()) - (2<<16); blood[nextblood].yspeed = -(8*rand()); blood[nextblood].sprite = 0; blood[nextblood].delay = 0; if (++nextblood == 64) nextblood = 0; if (lotsablood) { blood[nextblood].x = x/20; blood[nextblood].y = y/20; blood[nextblood].xdis = x % 20; blood[nextblood].ydis = y % 20; blood[nextblood].xspeed = (8*rand()) - (2<<16); blood[nextblood].yspeed = -(8*rand()); blood[nextblood].sprite = 0; blood[nextblood].delay = 0; if (++nextblood == 64) nextblood = 0; blood[nextblood].x = x/20; blood[nextblood].y = y/20; blood[nextblood].xdis = x % 20; blood[nextblood].ydis = y % 20; blood[nextblood].xspeed = (8*rand()) - (2<<16); blood[nextblood].yspeed = -(8*rand()); blood[nextblood].sprite = 0; blood[nextblood].delay = 0; if (++nextblood == 64) nextblood = 0; } } asm int EnemyxSize(u_char) { .set reorder beq a0,2,x32size beq a0,6,x60size beq a0,7,x40size li v0,20 jr ra x32size: li v0,32 jr ra x40size: li v0,40 jr ra x60size: li v0,60 jr ra } asm int EnemyySize(u_char) { .set reorder beq a0,2,y32size beq a0,4,y32size beq a0,5,y32size beq a0,6,y40size beq a0,7,y160size li v0,20 jr ra y32size: li v0,32 jr ra y40size: li v0,40 jr ra y160size: li v0,160 jr ra } /* int EnemyxSize(u_char type) { u_char size = 0; switch (type) { case 0 : case 1 : case 3 : case 4 : case 5 : size = 20; break; case 2 : size = 32; break; } return(size); } int EnemyySize(u_char type) { u_char size = 0; switch (type) { case 0 : case 1 : case 3 : size = 20; break; case 2 : case 4 : case 5 : size = 32; break; } return(size); } */ u_char CheckSolid (u_char tile) { // Returns: 0 if the tile is completely empty // 1 if the tile has some solid parts // 2 if the tile is completely solid u_char x,y; u_char count = 0; if (tile != 255) { for (y=0;y<5;y++) { for (x=0;x<5;x++) { if (coldata[tile][x][y] == 1) count++; } } if (count==0) return (0); if (count==25) return (2); if (count>0 && count<25) return (1); } else return (0); } void PlotNasties (void) { register long i; int temp; register GsSPRITE* nastyspr = (GsSPRITE*)getScratchAddr(sizeof(GsSPRITE)); GsSPRITE slipspr; InitGsSprite(nastyspr); InitGsSprite(&slipspr); CalcSprPos (slipspr, 928*2, 480); slipspr.w = 32; slipspr.h = 32; for (i=0;ix = (((nasties[i][1]-mapx)*20)-mapxdis)+(nasties[i][3]>>16); nastyspr->y = (((nasties[i][2]-mapy)*20)-mapydis)+(nasties[i][4]>>16); if (nastyflash[i]==0 || (theend==1 && time==(bossdeath-2))) nastyspr->cy = 511; else nastyspr->cy = 509; switch (nasties[i][0]) { case 0 : CalcSprPos2 (nastyspr, (440<<1) + nasties[i][6]*40 + nasties[i][7]*20, 80); nastyspr->w = nastyspr->h = 20; GsSortFastSprite( nastyspr, &Wot[side], 7); break; case 1 : temp = (nasties[i][8]/8) % 3; if (temp == 3) temp = 1; CalcSprPos2 (nastyspr, (480<<1) + temp*20, 80); nastyspr->w = nastyspr->h = 20; GsSortFastSprite( nastyspr, &Wot[side], 7); break; case 2 : temp = (nasties[i][9]/4); if (temp == 3) temp = 1; if (nastylist[levno-1][i][5] == 1) temp+=3; CalcSprPos2 (nastyspr, (480<<1) + (temp<<5), 132); nastyspr->w = nastyspr->h = 32; GsSortFastSprite( nastyspr, &Wot[side], 7); break; case 3 : CalcSprPos2 (nastyspr, (510<<1), 80); nastyspr->w = nastyspr->h = 20; GsSortFastSprite( nastyspr, &Wot[side], 7); break; case 4 : if (nasties[i][6]==0) temp = 0; else temp = 1; if (nasties[i][7]==1) temp = 2; CalcSprPos2 (nastyspr, (870<<1) + (nasties[i][8]*28), 80 + (temp<<5)); nastyspr->w = 28; nastyspr->h = 32; if (nasties[i][6]==1 && nasties[i][7]!=1) nastyspr->x -= 8; GsSortFastSprite( nastyspr, &Wot[side], 7); break; case 5 : temp = 5-(nasties[i][6]/24576); if (temp>9) temp = 9; if (temp<0) temp = 0; CalcSprPos2 (nastyspr, (488<<1) + (temp<<5), 100); nastyspr->w = 32; nastyspr->h = 32; nastyspr->x -= 6; GsSortFastSprite( nastyspr, &Wot[side], 7); break; case 6 : CalcSprPos2 (nastyspr, (320<<1) + (nasties[i][7]*60), 216); nastyspr->w = 60; nastyspr->h = 40; GsSortFastSprite( nastyspr, &Wot[side], 7); break; case 7 : CalcSprPos2 (nastyspr, (648<<1) + (nasties[i][6]*40), 80); nastyspr->w = 40; nastyspr->h = 160; GsSortFastSprite( nastyspr, &Wot[side], 7); break; case 8 : CalcSprPos2 (nastyspr, (480<<1), 80); nastyspr->w = nastyspr->h = 20; GsSortFastSprite( nastyspr, &Wot[side], 7); break; } if (time>(slipsize-320) && (time & 16) == 0 && !theend) { slipspr.x = ((nastylist[levno-1][i][1]-mapx)*20)-mapxdis; slipspr.y = ((nastylist[levno-1][i][2]-mapy)*20)-mapydis; if (nastylist[levno-1][i][0]==4 || nastylist[levno-1][i][0]==5) slipspr.y+=8; slipspr.scalex = (EnemyxSize(nastylist[levno-1][i][0])<<7); slipspr.scaley = (EnemyySize(nastylist[levno-1][i][0])<<7); GsSortSprite( &slipspr, &Wot[side], 7); } } } void PlotLineStar (int x, int y, int size, int angle, u_char r, u_char g, u_char b) { GsLINE line; int firstx,firsty; line.attribute = 0; line.r = r; line.g = g; line.b = b; firstx = x+((size*DJsin(angle))>>12); firsty = y+((size*DJcos(angle))>>12); line.x0 = firstx; line.y0 = firsty; if ((angle+=1365) >= 4096) angle-=4096; line.x1 = x+((size*DJsin(angle))>>12); line.y1 = y+((size*DJcos(angle))>>12); GsSortLine(&line, &Wot[side], 2); if ((angle+=1365) >= 4096) angle-=4096; line.x0 = x+((size*DJsin(angle))>>12); line.y0 = y+((size*DJcos(angle))>>12); GsSortLine(&line, &Wot[side], 2); line.x1 = firstx; line.y1 = firsty; GsSortLine(&line, &Wot[side], 2); if ((angle+=683) >= 4096) angle-=4096; firstx = x+((size*DJsin(angle))>>12); firsty = y+((size*DJcos(angle))>>12); line.x0 = firstx; line.y0 = firsty; if ((angle+=1365) >= 4096) angle-=4096; line.x1 = x+((size*DJsin(angle))>>12); line.y1 = y+((size*DJcos(angle))>>12); GsSortLine(&line, &Wot[side], 2); if ((angle+=1365) >= 4096) angle-=4096; line.x0 = x+((size*DJsin(angle))>>12); line.y0 = y+((size*DJcos(angle))>>12); GsSortLine(&line, &Wot[side], 2); line.x1 = firstx; line.y1 = firsty; GsSortLine(&line, &Wot[side], 2); } void MoveMessage (void) { register long row; register long x; if (inout == 0) { for (row=0;row<3;row++) { for (x=0;x<20;x++) { if (messlet[row][x][1] != 255 && messlet[row][x][1]>0) { if ((messlet[row][x][0]-=100) < 0) messlet[row][x][0]+=4096; if ((messlet[row][x][1]-=5) == 130 && (row!=2 || x!=19)) { if (x==19) {messlet[row+1][0][0] = 0; messlet[row+1][0][1] = 160;} else {messlet[row][x+1][0] = 0; messlet[row][x+1][1] = 160;} } } } } if (messlet[2][19][1]==0) { inout = 1; messlet[0][0][0] = 1024; messlet[0][0][1] = 5; } } else { for (row=0;row<3;row++) { for (x=0;x<20;x++) { if (messlet[row][x][1]>0 && messlet[row][x][1]<160) { if ((messlet[row][x][0]-=100) < 0) messlet[row][x][0]+=4096; if ((messlet[row][x][1]+=5) == 30 && (row!=2 || x!=19)) { if (x==19) {messlet[row+1][0][0] = 1024; messlet[row+1][0][1] = 5;} else {messlet[row][x+1][0] = 1024; messlet[row][x+1][1] = 5;} } } } } if (messlet[2][19][1]==160) message = 255; } } void PlotMessage (void) { int row,let; register long x; for (row=0;row<3;row++) { for (x=0;x<20;x++) { if (messlet[row][x][1] != 255) { let = messages[message][row][x]; if (let>47 && let<58) { PlotLetter(let-22, x*16, 160+row*16, messlet[row][x][0], messlet[row][x][1]); } if (let>96 && let<123) { PlotLetter(let-97, x*16, 160+row*16, messlet[row][x][0], messlet[row][x][1]); } } } } } void StartMessage (int id) { int row,x; message = id; inout = 0; for (row=0;row<3;row++) { for (x=0;x<20;x++) { messlet[row][x][1] = 255; } } messlet[0][0][0] = 0; messlet[0][0][1] = 160; } void PlotLetter (u_char let, short x, short y, int angle, short radius) { // Plot character let (0-25=a-Z, 26-35=0-9) at the angle and radius given // from the point on the screen given by (x,y) GsSPRITE charspr; InitGsSprite (&charspr); if (let<26) {CalcSprPos (charspr, (384<<1) + ((let % 13)<<4), 100 + ((let/13)<<4));} else {CalcSprPos (charspr, (320<<1) + ((let-26)<<4), 184);} charspr.x = x + ((radius*(DJsin(angle)))>>12); charspr.y = y - ((radius*(DJcos(angle)))>>12); charspr.w = charspr.h = 16; GsSortFastSprite( &charspr, &Wot[side], 2); } void MoveCoins (void) { // Do all movements regarding coins // Make all the coins bounce up and down coinspeed-=128; if ((coinheight+=coinspeed) < 0) { coinheight = 0; if (++coinbounce == 4) coinbounce = 0; switch (coinbounce) { case 0: coinspeed = 1024; break; case 2: coinspeed = 2048; break; default: coinspeed = 1536; break; } } if (++coindelay == 4) { coindelay = 0; if (++coinsprite == 8) coinsprite = 0; } CollectCoins(); /* The above asm function "CollectCoins" checks each snail against each * coin to see if it has been collected. It does the same thing as the * C code below, only quicker. for (i=0;i<64;i++) { if ((coins[i].collected & 1) == 0 && coins[i].x != 255) { // Make the coin spin around or vanish if it has been collected if (coindelay == 0) { if (coins[i].sprite >= 8) { if (++coins[i].sprite == 12) coins[i].collected = (coins[i].collected | 1); } } // Check if a snail is picking up the coin if (coins[i].sprite < 8) { for (j=0;j<=slipno;j++) { disx = ((snails[j][time].x*20)+snails[j][time].xdis) - (coins[i].x*20); disy = ((snails[j][time].y*20)+snails[j][time].ydis) - (coins[i].y*20 - (coinheight>>8)); if (disx>-20 && disx<20 && disy>-20 && disy<20) { coins[i].sprite = 8; AddStar(j); AddStar(j); AddStar(j); AddStar(j); if ((coins[i].collected & 2) == 0) { coins[i].collected = (coins[i].collected | 2); nocoins++; } } } } } } */ } asm void CollectCoins() { // s0 - coin ptr, s1 - slip no. ref., s2 - time // s3,s4 - global coin pos .set reorder addiu sp,sp,-24 sw s0,4(sp) sw s1,8(sp) sw s2,12(sp) sw s3,16(sp) sw s4,20(sp) sw ra,24(sp) la s0,coins add s0,s0,64*sizeof(coin) lh s2,time coinpickuplp: sub s0,s0,sizeof(coin) lb t0,2(s0) // coin.collected andi t1,t0,1 beq t1,1,skippickup lb s3,0(s0) // coin.x beq s3,255,skippickup lb t5,3(s0) // coin.sprite lb t1,coindelay bnez t1,dontmovecoin blt t5,8,dontmovecoin add t5,t5,1 // coin.sprite++ sb t5,3(s0) blt t5,12,dontmovecoin ori t0,t0,1 // coin.collect | 1 sb t0,2(s0) dontmovecoin: bge t5,8,skippickup // Calc global position of coin lb s4,1(s0) // coin.y sll t0,s3,2 // coin.x*20 add s3,s3,t0 sll s3,s3,2 sll t0,s4,2 // (coin.y*20 add s4,s4,t0 sll s4,s4,2 lh t0,coinheight // -coinheight>>8) srl t0,t0,8 sub s4,s4,t0 lh s1,slipno coinpickuplp2: la t0,snails // t0 = snails[j][time] muli t1,s1,slipsize*sizeof(pastsnail) muli t2,s2,sizeof(pastsnail) add t0,t0,t1 add t0,t0,t2 lb t1,0(t0) // snail.x lb t2,1(t0) // snail.y sll t3,t1,2 // t1 = snail.x*20 add t1,t1,t3 sll t3,t2,2 // t2 = snail.y*20 add t2,t2,t3 sll t1,t1,2 sll t2,t2,2 lb t4,2(t0) // snail.xdis lb t5,3(t0) // snail.ydis add t1,t1,t4 add t2,t2,t5 sub t1,t1,s3 // t1 = snail global x - coin global x sub t2,t2,s4 // t2 = snail global y - coin global y ble t1,-20,skippickup2 ble t2,-20,skippickup2 bge t1,20,skippickup2 bge t2,20,skippickup2 // Picked up coin // Work out distance from current snail la t1,snails lh t2,slipno muli t2,t2,slipsize*sizeof(pastsnail) add t1,t1,t2 muli t2,s2,sizeof(pastsnail) add t6,t1,t2 lb t1,0(t6) // snail.x lb t2,1(t6) // snail.y sll t3,t1,2 // t1 = snail.x*20 add t1,t1,t3 sll t3,t2,2 // t2 = snail.y*20 add t2,t2,t3 sll t1,t1,2 sll t2,t2,2 lb t4,2(t6) // snail.xdis lb t5,3(t6) // snail.ydis add t1,t1,t4 add t2,t2,t5 sub t1,t1,s3 sub t2,t2,s4 li t3,0 bgez t1,dontabsxval sub t1,t3,t1 dontabsxval: bgez t2,dontabsyval sub t2,t3,t2 dontabsyval: add t1,t1,t2 srl t1,t1,3 li t2,80 sub a0,t2,t1 blez a0,canthearcoin jal GotCoinTune canthearcoin: li t1,8 sb t1,3(s0) // coin.sprite = 8 move a0,s1 jal AddStar move a0,s1 jal AddStar move a0,s1 jal AddStar move a0,s1 jal AddStar lb t0,2(s0) // coin.collected andi t1,t0,2 bnez t1,skippickup2 ori t0,t0,2 // coin.collected | 2 sb t0,2(s0) lb t0,nocoins // nocoins++ add t0,t0,1 sb t0,nocoins jal GotAllCoins skippickup2: sub s1,s1,1 bgez s1,coinpickuplp2 skippickup: la t0,coins bne t0,s0,coinpickuplp lw s0,4(sp) lw s1,8(sp) lw s2,12(sp) lw s3,16(sp) lw s4,20(sp) lw ra,24(sp) addiu sp,sp,24 jr ra } /* All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. */ void GotAllCoins() { if (nocoins==cointarget[levno-1]) SsUtKeyOn(vabno,AllCoinsSnd,0,48,0,(sfxvol*80)>>8,(sfxvol*80)>>8); } void GotCoinTune(int distance) { SsUtKeyOn(vabno,CoinSnd,0,48,0,(sfxvol*distance)>>8,(sfxvol*distance)>>8); } void AddStar(u_char snailno) { if ((stars2ptr--) == 0) stars2ptr = 31; stars2[stars2ptr].x = snails[snailno][time].x; stars2[stars2ptr].y = snails[snailno][time].y; stars2[stars2ptr].xdis = (snails[snailno][time].xdis<<16); stars2[stars2ptr].ydis = (snails[snailno][time].ydis<<16); stars2[stars2ptr].angle = rand() % 4096; stars2[stars2ptr].lifespan = 96; stars2[stars2ptr].xspeed = ((rand() - 16384)<<2); stars2[stars2ptr].yspeed = -((32768+rand())<<2); } void MenuCreateStars() { int scrxpos,scrypos; if (++nextstardel == 1) { nextstardel = 0; if ((stars2ptr--) == 0) stars2ptr = 127; if ((starx+=204)>=65536) starx-=65536; if ((stary+=341)>=65536) stary-=65536; scrxpos = 152+(DJsin(starx>>4)>>5); scrypos = 120+(DJsin(stary>>4)>>5); stars2[stars2ptr].x = 20+(scrxpos/20); stars2[stars2ptr].y = 20+(scrypos/20); stars2[stars2ptr].xdis = scrxpos % 20; stars2[stars2ptr].ydis = scrypos % 20; stars2[stars2ptr].angle = rand() % 4096; stars2[stars2ptr].lifespan = 96; stars2[stars2ptr].xspeed = ((rand() - 16384)<<2); stars2[stars2ptr].yspeed = -((32768+rand())<<2); if ((stars2ptr--) == 0) stars2ptr = 127; scrxpos = 304-scrxpos; stars2[stars2ptr].x = 20+(scrxpos/20); stars2[stars2ptr].y = 20+(scrypos/20); stars2[stars2ptr].xdis = scrxpos % 20; stars2[stars2ptr].ydis = scrypos % 20; stars2[stars2ptr].angle = rand() % 4096; stars2[stars2ptr].lifespan = 96; stars2[stars2ptr].xspeed = ((rand() - 16384)<<2); stars2[stars2ptr].yspeed = -((32768+rand())<<2); } } void PlotCoins (void) { // Plot coin counter and any coins that haven't been collected. register GsSPRITE* coinspr = (GsSPRITE*)getScratchAddr(sizeof(GsSPRITE)); GsSPRITE slashspr; register long i; // Plot coin counter at top-left of screen InitGsSprite (coinspr); // Spin coin counter if you have the required amount of coins if (nocoins>=cointarget[levno-1]) {CalcSprPos2 (coinspr, (320<<1) + (coinsprite*20), 164);} else {CalcSprPos2 (coinspr, (320<<1), 164);} coinspr->x = 0; coinspr->y = 0; GsSortFastSprite( coinspr, &Wot[side], 2); // Plot how many coins you have PlotNumber (nocoins, 20, 2, 2); InitGsSprite (&slashspr); CalcSprPos (slashspr, (320<<1) + 160, 184); slashspr.w = 16; slashspr.h = 16; slashspr.x = 52; slashspr.y = 2; GsSortFastSprite( &slashspr, &Wot[side], 2); // Plot total number of coins in the level PlotNumber (totalcoins, 68, 2, 2); CalcSprPos2 (coinspr, (320<<1) + coinsprite*20, 164); for (i=0;i<64;i++) { // If coin hasn't been collected then plot it if ((coins[i].collected & 1) == 0 && coins[i].x != 255) { coinspr->x = ((coins[i].x-mapx)*20 - mapxdis); coinspr->y = ((coins[i].y-mapy)*20 - mapydis) - (coinheight>>8); if (coins[i].sprite>=8) {CalcSprPos2 (coinspr, (320<<1) + coins[i].sprite*20, 164);} if (coinspr->x>-16 && coinspr->x<320 && coinspr->y>-16 && coinspr->y<256) { GsSortFastSprite( coinspr, &Wot[side], 10); } if (coins[i].sprite>=8) {CalcSprPos2 (coinspr, (320<<1) + coinsprite*20, 164);} } } } void PlotNumber (int no, short x, short y, u_short depth) { // Plot 2 digit number no at position (x,y) on the screen at // point depth in the ordering table. GsSPRITE digitspr; InitGsSprite (&digitspr); digitspr.x = x; digitspr.y = y; digitspr.w = 16; digitspr.h = 16; CalcSprPos (digitspr, (320<<1) + ((no/10)<<4), 184); GsSortFastSprite( &digitspr, &Wot[side], depth); digitspr.x+=16; CalcSprPos (digitspr, (320<<1) + ((no % 10)<<4), 184); GsSortFastSprite( &digitspr, &Wot[side], depth); } int CheckCode (void) { // Returns the level number for the passcode currently // entered. Returns 1 if code is invalid. // 100 for invulnerability cheat. // 101 for lots of blood cheat. int i,j,matches; int lev = 1; for (i=0;i<(no_levs-1);i++) { matches = 0; for (j=0;j<8;j++) { if (passcode[j] == passcodes[i][j]) matches++; } if (matches == 8) lev = i+2; } if (passcode[0]==1 && passcode[1]==0 && passcode[2]==1 && passcode[3]==0 && passcode[4]==1 && passcode[5]==0 && passcode[6]==1 && passcode[7]==0) lev=100; if (passcode[0]==6 && passcode[1]==6 && passcode[2]==6 && passcode[3]==6 && passcode[4]==6 && passcode[5]==6 && passcode[6]==6 && passcode[7]==6) lev=101; return (lev); } void PlotCode() { // Plot the 8-digit passcode register long i; int no, x, y; long angle; GsSPRITE bignumsprs; InitGsSprite(&bignumsprs); bignumsprs.w = bignumsprs.h = 32; if ((codeangle+=64) == 4096) codeangle = 0; if (PAL) { x = 32; y = 160; } else { x = 32; y = 144; } for (i=0;i<8;i++) { if (i == digit) { bignumsprs.rotate = 45 * DJsin(codeangle); if (bignumsprs.rotate<0) bignumsprs.rotate+=(4096*360); angle = bignumsprs.rotate + (45*4096); if (angle>360*4096) angle-=360*4096; bignumsprs.x = x+16-(DJcos((short)(angle/360))/181); bignumsprs.y = y+16-(DJsin((short)(angle/360))/181); } else { bignumsprs.rotate = 0; bignumsprs.x = x; bignumsprs.y = y; } no = passcode[i]; CalcSprPos (bignumsprs, (320<<1)+(passcode[i]<<5), 132); GsSortSprite( &bignumsprs, &Wot[side], 0); x += 32; } } void CheckExit (void) { if (reachedexit == 0) { if (cursnail.x == exitlist[levno-1][0] && cursnail.y == (exitlist[levno-1][1]+2)) {secret = 0; reachedexit = 128;} if ((cursnail.x+1) == exitlist[levno-1][0] && cursnail.y == (exitlist[levno-1][1]+2)) {secret = 0; reachedexit = 128;} if (cursnail.x == secretexits[levno-1][0] && cursnail.y == (secretexits[levno-1][1]+2)) {secret = 1; reachedexit = 128;} if ((cursnail.x+1) == secretexits[levno-1][0] && cursnail.y == (secretexits[levno-1][1]+2)) {secret = 1; reachedexit = 128;} if (reachedexit == 128 && nocoins>8,(sfxvol*64)>>8); } else if (reachedexit>1) reachedexit--; } void PlotExit (void) { int x,y; register long i; GsSPRITE ballspr; short angle,frame; InitGsSprite (&ballspr); ballspr.w = ballspr.h = 8; angle = exit; frame = exitframe; x = ((exitlist[levno-1][0]-mapx)*20 - mapxdis); y = ((exitlist[levno-1][1]-mapy)*20 - mapydis) - 8; for (i=0;i<16;i++) { ballspr.x = x + (DJsin(angle)>>8); ballspr.y = y + (i<<2); CalcSprPos (ballspr, 1792+((frame % 8)<<3), 496+((frame / 8)<<3)); GsSortFastSprite( &ballspr, &Wot[side], 7); if (++frame == 16) frame = 0; if ((angle+=(2048+128)) >= 4096) angle-=4096; } if (secretexits[levno-1][0] != 0) { angle = exit; frame = exitframe; x = ((secretexits[levno-1][0]-mapx)*20 - mapxdis); y = ((secretexits[levno-1][1]-mapy)*20 - mapydis) - 8; for (i=0;i<16;i++) { ballspr.x = x + (DJsin(angle)>>8); ballspr.y = y + (i<<2); CalcSprPos (ballspr, 1792+((frame % 8)<<3), 496+((frame>>3)<<3)); GsSortFastSprite( &ballspr, &Wot[side], 7); if (++frame == 16) frame = 0; if ((angle+=(2048+128)) >= 4096) angle-=4096; } } } void TimeSlipLogo (void) { GsSPRITE logospr; if (handsdirn) { if ((hand0+=(60*360)) >= (360*4096)) hand0-=(360*4096); if ((hand1+=(5*360)) >= (360*4096)) hand1-=(360*4096); } else { if ((hand0-=(60*360)) < 0) hand0+=(360*4096); if ((hand1-=(5*360)) < 0) hand1+=(360*4096); } InitGsSprite (&logospr); logospr.w = 128; logospr.h = 32; CalcSprPos (logospr, 320*2, 100); logospr.x = 160+(16*(DJsin(hand0/360)))/4096; logospr.y = 128-(16*(DJcos(hand0/360)))/4096; logospr.rotate = hand0; GsSortSprite( &logospr, &Wot[side], 1); logospr.x = 160+(8*(DJsin(hand1/360)))/4096; logospr.y = 128-(8*(DJcos(hand1/360)))/4096; logospr.scalex = logospr.scaley = 2048; logospr.rotate = hand1; GsSortSprite( &logospr, &Wot[side], 1); } void MenuClocks (void) { register long i; for (i=0;i 2048) clocks[i][4]-=2048; // Move Clock clocks[i][0]+=clocks[i][2]; clocks[i][1]+=clocks[i][3]; if (clocks[i][0] < 0 || clocks[i][0] > (320<<16)) clocks[i][2]=-clocks[i][2]; if (clocks[i][1] < 0 || clocks[i][1] > (256<<16)) clocks[i][3]=-clocks[i][3]; PlotClock(clocks[i][0]>>16,clocks[i][1]>>16,clocks[i][4]); } } void PlotClock (short x, short y, int T) { GsSPRITE clockspr; GsGLINE hand; int angle; hand.attribute = 0; hand.r0 = hand.g0 = hand.b0 = 0; hand.r1 = hand.g1 = hand.b1 = 128; hand.x0 = x; hand.y0 = y; if ((angle = T*2) >= 4096) angle-=4096; hand.x1 = x + ((10*DJsin(angle))>>12); hand.y1 = y - ((10*DJcos(angle))>>12); GsSortGLine(&hand, &Wot[side], 2); InitGsSprite (&clockspr); CalcSprPos (clockspr, 1856, 480); clockspr.x = x-16; clockspr.y = y-15; clockspr.w = clockspr.h = 32; GsSortFastSprite( &clockspr, &Wot[side], 2); } void MoveDoors (void) { register long i; u_char prevstate; int snx,sny,vol; for (i=0;i<9;i++) { prevstate = doors[i].state; switch (doors[i].type) { case 0 : case 2 : { if (doors[i].opening==1 && doors[i].state<20) { doors[i].state++; if (doors[i].state==1) { snx = (20*cursnail.x) + (cursnail.xdis>>16); sny = (20*cursnail.y) + (cursnail.ydis>>16); snx = snx - 20*doors[i].x; if (snx<0) snx=-snx; sny = sny - 20*doors[i].y; if (sny<0) sny=-sny; vol = 80-((snx+sny)>>3); if (vol>0) SsUtKeyOn(vabno,DoorSnd,0,48,0,(sfxvol*vol)>>8,(sfxvol*vol)>>8); } } if (doors[i].opening==0 && doors[i].state>0) { doors[i].state--; if (doors[i].state==19) { snx = (20*cursnail.x) + (cursnail.xdis>>16); sny = (20*cursnail.y) + (cursnail.ydis>>16); snx = snx - 20*doors[i].x; if (snx<0) snx=-snx; sny = sny - 20*doors[i].y; if (sny<0) sny=-sny; vol = 80-((snx+sny)>>3); if (vol>0) SsUtKeyOn(vabno,DoorSnd,0,48,0,(sfxvol*vol)>>8,(sfxvol*vol)>>8); } } break; } case 1 : case 3 : { if (doors[i].opening==1 && doors[i].state<30) { doors[i].state++; if (doors[i].state==1) { snx = (20*cursnail.x) + (cursnail.xdis>>16); sny = (20*cursnail.y) + (cursnail.ydis>>16); snx = snx - 20*doors[i].x; if (snx<0) snx=-snx; sny = sny - 20*doors[i].y; if (sny<0) sny=-sny; vol = 80-((snx+sny)>>3); if (vol>0) SsUtKeyOn(vabno,DoorSnd,0,48,0,(sfxvol*vol)>>8,(sfxvol*vol)>>8); } } if (doors[i].opening==0 && doors[i].state>0) { doors[i].state--; if (doors[i].state==29) { snx = (20*cursnail.x) + (cursnail.xdis>>16); sny = (20*cursnail.y) + (cursnail.ydis>>16); snx = snx - 20*doors[i].x; if (snx<0) snx=-snx; sny = sny - 20*doors[i].y; if (sny<0) sny=-sny; vol = 80-((snx+sny)>>3); if (vol>0) SsUtKeyOn(vabno,DoorSnd,0,48,0,(sfxvol*vol)>>8,(sfxvol*vol)>>8); } } break; } } if (prevstate != doors[i].state) { UpdateDoor(&doors[i]); if (CheckHitWall(&cursnail) == 1) doors[i].state = prevstate; if (doors[i].state == prevstate) UpdateDoor(&doors[i]); } } } void UpdateDoor (door* D) { u_char tile; switch (D->type) { case 0 : { if (D->state == 20) tile = 255; else tile = 38; if (D->state == 16) tile = 39; if (D->state == 17) tile = 40; if (D->state == 18) tile = 41; if (D->state == 19) tile = 42; map[D->x][D->y] = tile; if (D->state >= 15) tile = 255; else tile = 38; if (D->state == 11) tile = 39; if (D->state == 12) tile = 40; if (D->state == 13) tile = 41; if (D->state == 14) tile = 42; map[D->x][D->y+1] = tile; if (D->state >= 10) tile = 255; else tile = 38; if (D->state == 6) tile = 39; if (D->state == 7) tile = 40; if (D->state == 8) tile = 41; if (D->state == 9) tile = 42; map[D->x][D->y+2] = tile; if (D->state >= 5) tile = 255; else tile = 38; if (D->state == 1) tile = 39; if (D->state == 2) tile = 40; if (D->state == 3) tile = 41; if (D->state == 4) tile = 42; map[D->x][D->y+3] = tile; break; } case 1 : { if (D->state == 30) tile = 255; else tile = 104; if (D->state == 26) tile = 105; if (D->state == 27) tile = 106; if (D->state == 28) tile = 107; if (D->state == 29) tile = 108; map[D->x][D->y] = tile; if (D->state >= 25) tile = 255; else tile = 104; if (D->state == 21) tile = 105; if (D->state == 22) tile = 106; if (D->state == 23) tile = 107; if (D->state == 24) tile = 108; map[D->x+1][D->y] = tile; if (D->state >= 20) tile = 255; else tile = 104; if (D->state == 16) tile = 105; if (D->state == 17) tile = 106; if (D->state == 18) tile = 107; if (D->state == 19) tile = 108; map[D->x+2][D->y] = tile; if (D->state >= 15) tile = 255; else tile = 104; if (D->state == 11) tile = 105; if (D->state == 12) tile = 106; if (D->state == 13) tile = 107; if (D->state == 14) tile = 108; map[D->x+3][D->y] = tile; if (D->state >= 10) tile = 255; else tile = 104; if (D->state == 6) tile = 105; if (D->state == 7) tile = 106; if (D->state == 8) tile = 107; if (D->state == 9) tile = 108; map[D->x+4][D->y] = tile; if (D->state >= 5) tile = 255; else tile = 104; if (D->state == 1) tile = 105; if (D->state == 2) tile = 106; if (D->state == 3) tile = 107; if (D->state == 4) tile = 108; map[D->x+5][D->y] = tile; break; } case 2 : { if (D->state == 20) tile = 47; else tile = 38; if (D->state == 16) tile = 121; if (D->state == 17) tile = 122; if (D->state == 18) tile = 123; if (D->state == 19) tile = 124; map[D->x][D->y] = tile; if (D->state >= 15) tile = 47; else tile = 38; if (D->state == 11) tile = 121; if (D->state == 12) tile = 122; if (D->state == 13) tile = 123; if (D->state == 14) tile = 124; map[D->x][D->y+1] = tile; if (D->state >= 10) tile = 47; else tile = 38; if (D->state == 6) tile = 121; if (D->state == 7) tile = 122; if (D->state == 8) tile = 123; if (D->state == 9) tile = 124; map[D->x][D->y+2] = tile; if (D->state >= 5) tile = 47; else tile = 38; if (D->state == 1) tile = 121; if (D->state == 2) tile = 122; if (D->state == 3) tile = 123; if (D->state == 4) tile = 124; map[D->x][D->y+3] = tile; break; } case 3 : { if (D->state == 30) tile = 47; else tile = 104; if (D->state == 26) tile = 117; if (D->state == 27) tile = 118; if (D->state == 28) tile = 119; if (D->state == 29) tile = 120; map[D->x][D->y] = tile; if (D->state >= 25) tile = 47; else tile = 104; if (D->state == 21) tile = 117; if (D->state == 22) tile = 118; if (D->state == 23) tile = 119; if (D->state == 24) tile = 120; map[D->x+1][D->y] = tile; if (D->state >= 20) tile = 47; else tile = 104; if (D->state == 16) tile = 117; if (D->state == 17) tile = 118; if (D->state == 18) tile = 119; if (D->state == 19) tile = 120; map[D->x+2][D->y] = tile; if (D->state >= 15) tile = 47; else tile = 104; if (D->state == 11) tile = 117; if (D->state == 12) tile = 118; if (D->state == 13) tile = 119; if (D->state == 14) tile = 120; map[D->x+3][D->y] = tile; if (D->state >= 10) tile = 47; else tile = 104; if (D->state == 6) tile = 117; if (D->state == 7) tile = 118; if (D->state == 8) tile = 119; if (D->state == 9) tile = 120; map[D->x+4][D->y] = tile; if (D->state >= 5) tile = 47; else tile = 104; if (D->state == 1) tile = 117; if (D->state == 2) tile = 118; if (D->state == 3) tile = 119; if (D->state == 4) tile = 120; map[D->x+5][D->y] = tile; break; } } } /* void MoveBalls (void) { register long i; int j,bx,by,sx,sy; u_char coltile; for (i=0;i= 20) { balls[i].xdis-=20; balls[i].x++; } } else { if ((balls[i].xdis-=8) < 0) { balls[i].xdis+=20; balls[i].x--; } } coltile = map[balls[i].x][balls[i].y]; if (coltile == 125 || coltile == 127) { map[balls[i].x][balls[i].y]=coltile+1; balls[i].x = 255; no_targs++; } if (coltile != 255) { if (coldata[coltile][balls[i].ydis>>2][balls[i].xdis>>2] == 1) balls[i].x = 255; } // Check if you have been shot if (paradox == 0 && reachedexit == 0) { bx = 20*balls[i].x + balls[i].xdis; by = 20*balls[i].y + balls[i].ydis; for (j=0;j<=slipno;j++) { sx = 20*snails[j][time].x + snails[j][time].xdis; sy = 20*snails[j][time].y + snails[j][time].ydis; if ((bx>sx-8) && (bxsy-8) && (by>2) sll t7,t6,2 add t6,t7,t6 add t5,t5,t6 srl t6,t2,2 // coldata+=xdis>>2 add t5,t5,t6 lb t4,0(t5) beqz t4,skipballcolcheck li t4,255 sb t4,0(s0) // Delete fire ball skipballcolcheck: lb t4,reachedexit lw t5,paradox lw t6,invuln bnez t4,skipmbloop2 bnez t5,skipmbloop2 bnez t6,skipmbloop2 sll t4,t0,2 // s1=(ball.x*20)+ballxdis add t0,t4,t0 sll t0,t0,2 add s1,t0,t2 sll t4,t1,2 // s2=(ball.y*20)+ballydis add t1,t4,t1 sll t1,t1,2 add s2,t1,t3 la s3,snails lw t0,slipno muli t1,t0,slipsize*sizeof(pastsnail) add s3,s3,t1 lw t0,time muli t1,t0,sizeof(pastsnail) add s3,s3,t1 move s4,s3 moveballslp1: lb t0,0(s3) // snail.x lb t1,1(s3) // snail.y lb t2,2(s3) // snail.xdis lb t3,3(s3) // snail.ydis sll t4,t0,2 // t0=(x*20)+xdis add t0,t4,t0 sll t0,t0,2 add t0,t0,t2 sll t4,t1,2 // t1=(y*20)+ydis add t1,t4,t1 sll t1,t1,2 add t1,t1,t3 sub t2,t0,8 ble s1,t2,skipmbloop1 add t2,t0,20 bge s1,t2,skipmbloop1 sub t2,t1,1 ble s2,t2,skipmbloop1 add t2,t1,20 bge s2,t2,skipmbloop1 // Check if snail hit is current incarnation sne a0,s3,s4 add a0,a0,3 jal StartMessage // Caused paradox li t0,330 sw t0,paradox // Play dying sound jal DeadSound skipmbloop1: sub s3,s3,slipsize*sizeof(pastsnail) la t0,snails bge s3,t0,moveballslp1 skipmbloop2: la t0,balls bne t0,s0,moveballslp2 // Twirl exit about lh t0,exit sub t0,t0,90 bgez t0,dontwrapexit1 add t0,t0,4096 dontwrapexit1: sh t0,exit lh t0,exitframe sub t0,t0,1 bgez t0,dontwrapexit2 li t0,15 dontwrapexit2: sh t0,exitframe lw s0,4(sp) lw s1,8(sp) lw s2,12(sp) lw s3,16(sp) lw s4,20(sp) lw ra,24(sp) addiu sp,sp,24 jr ra hittarget: add t4,t4,1 sb t4,0(t3) li t5,255 sb t5,0(s0) // Delete fire ball lb t5,no_targs add t5,t5,1 sb t5,no_targs b donehittarget } void DeadSound() { SsUtKeyOn(vabno,DyingSnd,0,48,0,(sfxvol*64)>>8,(sfxvol*64)>>8); } void PlotBalls (void) { register long i; GsSPRITE ballspr; InitGsSprite (&ballspr); ballspr.w = ballspr.h = 8; for (i=0;i-16 && ballspr.x<320 && ballspr.y>-16 && ballspr.y<256) { CalcSprPos (ballspr, 1792+((balls[i].sprite % 8)<<3), 496+((balls[i].sprite/8)<<3)); GsSortFastSprite( &ballspr, &Wot[side], 7); } } } } void MovePlatforms (void) { register long i; long x,y,x2,y2,snaily; long ydiff; u_char snailson; u_char hitby; snail tempsnail; for (i=0;i<8;i++) { if (platforms[i].x != 255) { // Work out if you are standing on the current platform x = platformxpos(&platforms[i]); y = platformypos(&platforms[i]); hitby=HitPlatform(&cursnail, &platforms[i]); snailson=0; if (((cursnail.x*20 + (cursnail.xdis>>16)) > x - 20) && ((cursnail.x*20 + (cursnail.xdis>>16)) < x + (platforms[i].sections+2)*20)) { ydiff = ((cursnail.y*20 + (cursnail.ydis>>16))) - (y - 20); if (ydiff==0 && cursnail.yspeed != jumpspeed) {snailson=1; cursnail.yspeed=0;} } if (platforms[i].x != 255) { platforms[i].xangle += platforms[i].xspeed; if (platforms[i].xangle < 0) platforms[i].xangle+=(360*4096); if (platforms[i].xangle >= (360*4096)) platforms[i].xangle-=(360*4096); // Move you if you are standing on this platform if (snailson == 1) { x2 = platformxpos(&platforms[i]); tempsnail = cursnail; cursnail.xdis += (x2-x)<<16; if (cursnail.xdis<0) {cursnail.xdis+=(20<<16); cursnail.x--;} if (cursnail.xdis>(20<<16)) {cursnail.xdis-=(20<<16); cursnail.x++;} if (CheckHitWall(&cursnail) == 1) cursnail=tempsnail; } platforms[i].yangle += platforms[i].yspeed; if (platforms[i].yangle < 0) platforms[i].yangle+=(360*4096); if (platforms[i].yangle >= (360*4096)) platforms[i].yangle-=(360*4096); // Move you if you are standing on this platform y2 = platformypos(&platforms[i]); if (snailson == 1) { tempsnail = cursnail; cursnail.y = (y2 / 20) -1; cursnail.ydis = (y2 % 20)<<16; if (CheckHitWall(&cursnail) == 1) cursnail=tempsnail; } // Check to see if you have been "scooped up" by the platform snaily = (cursnail.y*20) + (cursnail.ydis>>16); if (hitby==0 && HitPlatform(&cursnail, &platforms[i])==1 && snaily<=(y-20) && cursnail.yspeed != jumpspeed) { tempsnail = cursnail; cursnail.y = (y2 / 20) -1; cursnail.ydis = (y2 % 20)<<16; if (CheckHitWall(&cursnail) == 1) cursnail=tempsnail; } } } } } u_char HitPlatform (snail* S, platform* P) { // Returns 1 if snail S and platform P // share the same space at any point long sx,sy,px,py; u_char hit = 0; sx = (S->x*20) + (S->xdis>>16); sy = (S->y*20) + (S->ydis>>16); px = platformxpos(P); py = platformypos(P); if (sx>px-20 && sx<(px+(P->sections+2)*20) && sy>py-20 && syx = (platformxpos (&platforms[i]) - mapx*20) - mapxdis; platspr->y = (platformypos (&platforms[i]) - mapy*20) - mapydis; GsSortFastSprite( platspr, &Wot[side], 6); platspr->x+=20; platspr->u+=20; while (size-- > 0) { GsSortFastSprite( platspr, &Wot[side], 6); platspr->x+=20; } platspr->u+=20; GsSortFastSprite( platspr, &Wot[side], 6); } } } // u_char x,y,sections,type; // long xdist,ydist,xangle,yangle,xspeed,yspeed; asm long platformxpos (platform*) { // Calculates the global x co-ord of a platform // See below for C version .set reorder addiu sp,sp,-8 sw s0,4(sp) sw ra,8(sp) move s0,a0 lw a0,12(s0) // platform.xangle li t0,360 div a0,t0 mflo a0 jal DJsin // DJsin(platform.xangle/360) lw t0,4(s0) // platform.xdist mul t0,t0,v0 sra t0,t0,12 lb v0,0(s0) // platform.x sll t1,v0,2 // platform.x*20 add v0,v0,t1 sll v0,v0,2 add v0,v0,t0 lw s0,4(sp) lw ra,8(sp) addiu sp,sp,8 jr ra } asm long platformypos (platform*) { // Calculates the global y co-ord of a platform // See below for C version .set reorder addiu sp,sp,-8 sw s0,4(sp) sw ra,8(sp) move s0,a0 lw a0,16(s0) // platform.yangle li t0,360 div a0,t0 mflo a0 jal DJsin // DJsin(platform.yangle/360) lw t0,8(s0) // platform.ydist mul t0,t0,v0 sra t0,t0,12 lb v0,1(s0) // platform.y sll t1,v0,2 // platform.y*20 add v0,v0,t1 sll v0,v0,2 add v0,v0,t0 lw s0,4(sp) lw ra,8(sp) addiu sp,sp,8 jr ra } /* long platformxpos (platform* P) { long offset; offset = (P->xdist*(long)(DJsin((short)(P->xangle/360))))/4096; return(P->x*20 + offset); } long platformypos (platform* P) { long offset; offset = (P->ydist*(long)(DJsin((short)(P->yangle/360))))/4096; return(P->y*20 + offset); } */ void PlotWhirl() { GsSPRITE whirlspr; long angle; short radius; InitGsSprite (&whirlspr); whirlspr.w = 256; whirlspr.h = 256; CalcSprPos (whirlspr, 768*2, 256); whirlspr.scalex = whirlspr.scaley = (128-slipping)*64; whirlspr.rotate = (long)(slipping*65536); radius = (short)(((128*(long)(whirlspr.scalex))/(long)(DJsin(512)))); while (whirlspr.rotate >= (4096*360)) { whirlspr.rotate-=(4096*360); } angle = whirlspr.rotate + (45*4096); if (angle >= (360*4096)) angle-=(360*4096); whirlspr.x = 160-((radius*DJcos((short)(angle/360)))/4096); if (PAL) whirlspr.y = 128-((radius*DJsin((short)(angle/360)))/4096); else whirlspr.y = 120-((radius*DJsin((short)(angle/360)))/4096); GsSortSprite( &whirlspr, &Wot[side], 1); } void PlotStars() { int i; GsBOXF starbox; starbox.attribute = 0; starbox.r = 255; starbox.g = starbox.b = 0; for (i=0;i<256;i++) { if ((stars[i].z-=64) < 64) stars[i].z = 4096; starbox.w = (int)(4096-stars[i].z)/960; starbox.h = (int)(4096-stars[i].z)/960; if (stars[i].z > 4096) starbox.w = starbox.h = 1; starbox.x = ((stars[i].x*256)/stars[i].z)+(160-starbox.w/2); if (PAL) starbox.y = ((stars[i].y*256)/stars[i].z)+(128-starbox.h/2); else starbox.y = ((stars[i].y*256)/stars[i].z)+(120-starbox.h/2); GsSortBoxFill( &starbox, &Wot[side], 0); } } void ResetStars() { int i; for (i=0;i<128;i++) { stars[i].x = ((rand() % 255) - 128); stars[i].y = ((rand() % 255) - 128); stars[i].z = ((rand() % 4096) + 4096); } } void PlotBackgr() { GsSPRITE backgrspr; InitGsSprite (&backgrspr); backgrspr.w = 80; backgrspr.h = 256; CalcSprPos (backgrspr, 944*2, 256); backgrspr.y = -((mapy * 5) + mapydis/5); for (backgrspr.x=0;backgrspr.x<320;backgrspr.x+=80) { GsSortFastSprite( &backgrspr, &Wot[side], 15); } CalcSprPos (backgrspr, 984*2, 256); backgrspr.y+=256; for (backgrspr.x=0;backgrspr.x<320;backgrspr.x+=80) { GsSortFastSprite( &backgrspr, &Wot[side], 15); } } void PlotSnails () { register long i; int angle; register GsSPRITE* snailspr = (GsSPRITE*)getScratchAddr(sizeof(GsSPRITE)); u_char dirn,frame; // Set relevant info for Snail sprite InitGsSprite (snailspr); // Go through snail from each time period and plot 'im for (i=0;i<=slipno;i++) { dirn = (snails[i][time].sprite & 1); frame = ((snails[i][time].sprite>>1) & 7); CalcSprPos2 (snailspr, 640+(dirn * 20*6)+(frame * 20), 80); snailspr->x = (snails[i][time].x-mapx)*20 + ((snails[i][time].xdis)-mapxdis); snailspr->y = (snails[i][time].y-mapy)*20 + ((snails[i][time].ydis)-mapydis); if (i==slipno && reachedexit>0) { angle = (128-reachedexit)*(128-reachedexit)*3; while (angle>4096) angle-=4096; snailspr->scalex = DJsin(angle); snailspr->x+=(4096-snailspr->scalex)/410; if (reachedexit<40) snailspr->h = reachedexit/2; GsSortSprite( snailspr, &Wot[side], 8); } else { if (paradox>0) { snailspr->scalex = snailspr->scaley = 4096 + 32*(330-paradox); snailspr->rotate = 160*(330-paradox)*(330-paradox); angle = snailspr->rotate+(4096*45); while (angle>=(360*4096)) angle-=(360*4096); snailspr->x+=10; snailspr->y+=10; snailspr->x -= ((snailspr->scalex/290) * DJcos(angle/360))/4096; snailspr->y -= ((snailspr->scalex/290) * DJsin(angle/360))/4096; GsSortSprite( snailspr, &Wot[side], 8); } else GsSortFastSprite( snailspr, &Wot[side], 8); } } } void MoveSnails () { int i,x1,y1,x2,y2,vol; pastsnail cur; // Move you if (!theend) MoveSnail(&cursnail); if (levno==4 && cursnail.x==30 && trigmess==0) { StartMessage(9); trigmess=1; } if (levno==7 && cursnail.x==18 && trigmess==0) { StartMessage(12); trigmess=1; } if (levno==22 && cursnail.x==16 && cursnail.y>48 && trigmess==0) { StartMessage(16); trigmess=1; } if (levno==1 && cursnail.y<30 && trigmess==0) { StartMessage(17); trigmess=1; } if (levno==1 && doors[2].opening==1 && trigmess==1) { trigmess=2; } if (levno==1 && time>=0 && time<4 && trigmess==2) { StartMessage(18); trigmess=3; } if (levno==1 && doors[2].opening==1 && trigmess==3 && (cursnail.x<53 || cursnail.x>56 || cursnail.y<26 || cursnail.y>29)) { StartMessage(19); trigmess=4; } if (levno==1 && cursnail.y<12 && cursnail.x>58 && trigmess==4) { StartMessage(20); trigmess=5; } // This is where it is found out what switches are being stood on // So reset all doors to being shut until you find out otherwise for (i=0;i<9;i++) doors[i].opening = 0; if (!theend) { snails[slipno][time].x = cursnail.x; snails[slipno][time].y = cursnail.y; snails[slipno][time].xdis = (cursnail.xdis>>16); snails[slipno][time].ydis = (cursnail.ydis>>16); snails[slipno][time].sprite = (snails[slipno][time].sprite | cursnail.dirn | cursnail.frame<<1); } for (i=0;i<=slipno;i++) { cur = snails[i][time]; if ((cur.sprite & 64) == 64) { x1 = (20*snails[i][time].x)+snails[i][time].xdis; y1 = (20*snails[i][time].y)+snails[i][time].ydis; x1 = x1-((20*cursnail.x)+(cursnail.xdis>>16)); if (x1<0) x1=-x1; y1 = y1-((20*cursnail.y)+(cursnail.ydis>>16)); if (y1<0) y1=-y1; vol = 48-((x1+y1)>>3); if (vol>0) SsUtKeyOn(vabno,FireSnd,0,48,0,(sfxvol*vol)>>8,(sfxvol*vol)>>8); LaunchBall(&cur); } // Check if you are standing on a switch if (cur.ydis == 0) { if (map[cur.x][cur.y+1]>19 && map[cur.x][cur.y+1]<38) OnSwitch(cur.x,cur.y+1); if (map[cur.x+1][cur.y+1]>19 && map[cur.x+1][cur.y+1]<38 && cur.xdis != 0) OnSwitch(cur.x+1,cur.y+1); } } if (no_targs==3 && levno==4) doors[0].opening = 1; if (no_targs==4 && levno==6) doors[0].opening = 1; if (no_targs==4 && levno==10) doors[0].opening = 1; if (no_targs==3 && levno==11) doors[4].opening = 1; if (no_targs==8 && levno==16) doors[7].opening = 1; //for (i=0;i<9;i++) doors[i].opening = 1; //Check if you have collided with a past version of yourself if (slipno>0 && paradox == 0 && reachedexit == 0 && !invuln) { x1 = (cursnail.x*20) + (cursnail.xdis>>16); y1 = (cursnail.y*20) + (cursnail.ydis>>16); for (i=0;i-18 && (x1-x2)<18 && (y1-y2)>-18 && (y1-y2)<18) { DeadSound(); StartMessage (2); paradox = 330; } } } } void MoveSnail(snail* you) { int canjump = 0; int i; long x,y; int hitby[8]; u_char tile,ontl,inupd; if (pad & PADLleft) { you->finaldirn = 1; if (you->dirn == 0 && you->frame<4) you->frame=4; if ((you->xspeed-=16384) < -(4<<16)) you->xspeed=-((4<<16)+8192); } if (pad & PADLright) { you->finaldirn = 0; if (you->dirn == 1 && you->frame<4) you->frame=4; if ((you->xspeed+=16384) > (4<<16)) you->xspeed=((4<<16)+8192); } // Tend snail towards speed 0 if (you->xspeed > 0) { if ((you->xspeed-=8192) < 0) you->xspeed = 0; } if (you->xspeed < 0) { if ((you->xspeed+=8192) > 0) you->xspeed = 0; } you->xdis+=you->xspeed; if (you->frame < 4) { if (you->dirn == 0) you->framedel-=you->xspeed; if (you->dirn == 1) you->framedel+=you->xspeed; if (you->framedel < 0) { you->framedel+=(16<<16); if (++you->frame == 4) you->frame = 0; } } else { if (you->dirn == you->finaldirn) { you->frame--; } else { if (++you->frame == 6) {you->dirn = you->finaldirn; you->frame = 5;} } } // If snail moves out of displacement box move into next tile if (you->xdis > (20<<16)) { you->xdis-=(20<<16); you->x+=1; } if (you->xdis < 0) { you->xdis+=(20<<16); you->x-=1; } // Check if you are stuck in a wall if (CheckHitWall(you) == 1) { // Move snail up 4 pixels and check again // For going up steps if ((you->ydis-=(4<<16)) < 0) { you->ydis+=(20<<16); you->y--; } if (CheckHitWall(you) == 1) { // If you've hit a wall then move back down // again because you aren't going up a step if ((you->ydis+=(4<<16)) >= (20<<16)) { you->ydis-=(20<<16); you->y++; } // Move snail backwards in 4 pixel jumps // until no longer stuck in a wall if (you->xspeed > 0) { you->xdis = (you->xdis>>18); you->xdis = (you->xdis<<18); while (CheckHitWall(you) == 1) { if ((you->xdis-=(4<<16)) < 0) { you->xdis+=(20<<16); you->x--; } } } else { you->xdis = (you->xdis>>18); you->xdis = (you->xdis<<18); while (CheckHitWall(you) == 1) { if ((you->xdis+=(4<<16)) >= (20<<16)) { you->xdis-=(20<<16); you->x++; } } } you->xspeed = 0; } } for (i=0;i<8;i++) { hitby[i] = HitPlatform(you,&platforms[i]); // Make sure you can jump if you are on a platform x = platformxpos(&platforms[i]); y = platformypos(&platforms[i]); if (((you->x*20 + (you->xdis>>16)) > x - 20) && ((you->x*20 + (you->xdis>>16)) < x + (platforms[i].sections+2)*20)) { if ((long)(you->y*20 + (you->ydis>>16)) == (y - 20)) canjump = 1; } } // Check if you are in an updraft inupd = 0; tile = map[you->x][you->y]; if (tile>108 && tile<117) inupd = 1; if (you->xdis != 0) { tile = map[you->x+1][you->y]; if (tile>108 && tile<117) inupd = 1; } if (you->ydis != 0) { tile = map[you->x][you->y+1]; if (tile>108 && tile<117) inupd = 1; } if (you->xdis != 0 && you->ydis != 0) { tile = map[you->x+1][you->y+1]; if (tile>108 && tile<117) inupd = 1; } if (inupd == 1) { if ((you->yspeed-=(16384+12288)) < -(8<<16)) you->yspeed=-(8<<16); } // Fall down if ((you->yspeed+=16384) > (8<<16)) you->yspeed=(8<<16); you->ydis+=you->yspeed; // If snail moves out of displacement box move into next tile if (you->ydis > (20<<16)) { you->ydis-=(20<<16); you->y+=1; } if (you->ydis < 0) { you->ydis+=(20<<16); you->y-=1; } for (i=0;i<8;i++) { // Check if you fell onto a platform if (HitPlatform(you,&platforms[i]) == 1 && hitby[i] == 0 && you->yspeed>0) { you->y = (platformypos(&platforms[i]) / 20) -1; you->ydis = (platformypos(&platforms[i]) % 20)<<16; } } // If stuck in a wall move snail backwards in 4 // pixel jumps until no longer stuck in a wall if (CheckHitWall(you) == 1) { if (you->yspeed > 0) { canjump = 1; you->ydis = (you->ydis>>18); you->ydis = (you->ydis<<18); while (CheckHitWall(you) == 1) { if ((you->ydis-=(4<<16)) < 0) { you->ydis+=(20<<16); you->y--; } } // Add some dust when you hit the ground if (you->yspeed==(8<<16)) AddDust(you); if (you->yspeed>(6<<16)) AddDust(you); if (you->yspeed>(4<<16)) AddDust(you); if (you->yspeed>(2<<16)) AddDust(you); } else { you->ydis = (you->ydis>>18); you->ydis = (you->ydis<<18); while (CheckHitWall(you) == 1) { if ((you->ydis+=(4<<16)) >= (20<<16)) { you->ydis-=(20<<16); you->y++; } } } you->yspeed = 0; } ontl = 0; if (you->xdis == 0 && you->ydis == 0) { tile = map[you->x][you->y]; if (tile > 49 && tile < 54) ontl = 1; } if (you->xdis != 0 && you->ydis == 0) { tile = map[you->x][you->y]; if (tile > 49 && tile < 54) ontl = 1; tile = map[you->x+1][you->y]; if (tile > 49 && tile < 54) ontl = 1; } if (you->xdis == 0 && you->ydis != 0) { tile = map[you->x][you->y]; if (tile > 49 && tile < 54) ontl = 1; tile = map[you->x][you->y+1]; if (tile > 49 && tile < 54) ontl = 1; } if (you->xdis != 0 && you->ydis != 0) { tile = map[you->x][you->y]; if (tile > 49 && tile < 54) ontl = 1; tile = map[you->x+1][you->y]; if (tile > 49 && tile < 54) ontl = 1; tile = map[you->x][you->y+1]; if (tile > 49 && tile < 54) ontl = 1; tile = map[you->x+1][you->y+1]; if (tile > 49 && tile < 54) ontl = 1; } if (ontl == 1) { you->yspeed=-(2<<16); SsUtKeyOn(vabno,TrampolineSnd,0,48,0,(sfxvol*64)>>8,(sfxvol*64)>>8); } // Jump if ((pad & PADRdown) && (canjump == 1)) { you->yspeed = jumpspeed; SsUtKeyOn(vabno,JumpSnd,0,48,0,(sfxvol*64)>>8,(sfxvol*64)>>8); } if ((pad & PADRdown) && (ontl ==1)) { you->yspeed = bouncespeed; SsUtKeyOn(vabno,JumpSnd,0,48,0,(sfxvol*64)>>8,(sfxvol*64)>>8); } // Fire if (you->firedel > 0) you->firedel--; if ((pad & PADRright) && (you->firedel==0)) { snails[slipno][time].sprite = 64; you->firedel = 4; } else snails[slipno][time].sprite = 0; } void AddDust(snail* snptr) { if ((dustptr--) == 0) dustptr = 7; dusts[dustptr].x = ((snptr->x*20)<<8)+((snptr->xdis>>8)+(6<<8)); dusts[dustptr].y = ((snptr->y*20)<<8)+((snptr->ydis>>8)+(12<<8)); dusts[dustptr].sprite = 16+(rand() % 16); dusts[dustptr].xspeed = (rand() - 16384)>>6; dusts[dustptr].yspeed = -(256+(rand()>>7)); } void OnSwitch(u_char x, u_char y) { if (map[x][y]<29) map[x][y]+=9; doors[map[x][y]-29].opening = 1; } void LaunchBall (pastsnail* S) { // Launches a fireball from the snail S // Copy over needed info from snail to the next ball slot balls[nextball].y = S->y; balls[nextball].ydis = S->ydis+6; if (balls[nextball].ydis >= 20) { balls[nextball].ydis-=20; balls[nextball].y++; } balls[nextball].dirn = (S->sprite & 1); balls[nextball].sprite = 0; balls[nextball].sprdirn = 0; if ((S->sprite & 1) == 0) { balls[nextball].x = S->x+1; balls[nextball].xdis = S->xdis; } else { balls[nextball].x = S->x; balls[nextball].xdis = S->xdis-8; if (balls[nextball].xdis < 0) { balls[nextball].xdis+=20; balls[nextball].x--; } } // Increase nextball slot and wrap round when 32 is reached // This system means that in an overflow situation the oldest fireball // gets wiped to make way for a new one if (++nextball == noballs) nextball=0; } u_char CheckHitWall(snail* S) { // This returns 1 if snail S is stuck in a wall, otherwise 0 // At any one time a snail can lie on 4 tiles referred to as tl,tr,bl and br // top left, top right, etc. // Each tile is chopped up into a 5x5 grid where each entry can be 1 - solid or // 0 - empty // The variables x1,x2,y1,y2 define what blocks of a tile the snail lies in: // top left block (x1 -> 4, y1 -> 4) // top right block (0 -> x2, y1 -> 4) // bottom left block (x1 -> 4, 0 -> y2) // bottom right block (0 -> x2, 0 -> y2) u_char tlspr = map[S->x][S->y]; u_char trspr = map[(S->x)+1][S->y]; u_char blspr = map[S->x][(S->y)+1]; u_char brspr = map[(S->x)+1][(S->y)+1]; u_char hit = 0; int x1,x2,y1,y2; register long x; register long y; x1 = S->xdis>>18; if (S->xdis == 0) x2 = 255; else x2 = (S->xdis-1)>>18; y1 = S->ydis>>18; if (S->ydis == 0) y2 = 255; else y2 = (S->ydis-1)>>18; if (tlspr!=255) { for (y=y1;y<=4;y++) { for (x=x1;x<=4;x++) { if (coldata[tlspr][y][x] == 1) hit = 1; } } } if (trspr!=255 && x2!=255 && y1!=255) { for (y=y1;y<=4;y++) { for (x=0;x<=x2;x++) { if (coldata[trspr][y][x] == 1) hit = 1; } } } if (blspr!=255 && x1!=255 && y2!=255) { for (y=0;y<=y2;y++) { for (x=x1;x<=4;x++) { if (coldata[blspr][y][x] == 1) hit = 1; } } } if (brspr!=255 && x2!=255 && y2!=255) { for (y=0;y<=y2;y++) { for (x=0;x<=x2;x++) { if (coldata[brspr][y][x] == 1) hit = 1; } } } return(hit); } void TimeSlip (void) { int i; if (!theend) { if (++slipno == 18) quit = 1; else ResetPositions(); } else { cursnail.x = cursnail.y = 0; scrx = (25*20)<<8; scry = (48*20)<<8; ResetPositions(); for (i=0;i<32;i++) hexs[i].angle = -1; nexthex = 0; } VSync(0); time = 0; } void ResetPositions() { register long i; int x,y; u_char tempstate; //Last level bits dobuzz = 0; nextbbslot = 5; //Copy platform data from main store into useable array for (i=0;i<8;i++) { platforms[i].x = platlist[levno-1][i].x; platforms[i].y = platlist[levno-1][i].y; platforms[i].sections = platlist[levno-1][i].sections; platforms[i].type = platlist[levno-1][i].type; platforms[i].xdist = platlist[levno-1][i].xdist; platforms[i].ydist = platlist[levno-1][i].ydist; platforms[i].xangle = platlist[levno-1][i].xangle; platforms[i].yangle = platlist[levno-1][i].yangle; platforms[i].xspeed = platlist[levno-1][i].xspeed; platforms[i].yspeed = platlist[levno-1][i].yspeed; } //Reset all the nasty people nastycount = 255; for (i=0;i<64;i++) nastyflash[i] = 0; for (i=0;i<32;i++) { nasties[i][0] = nastylist[levno-1][i][0]; nasties[i][1] = nastylist[levno-1][i][1]; nasties[i][2] = nastylist[levno-1][i][2]; nasties[i][3] = nasties[i][4] = 0; switch (nasties[i][0]) { case 0 : nasties[i][5] = 5; nasties[i][6] = nastylist[levno-1][i][3]; nasties[i][7] = 0; nasties[i][8] = 0; break; case 1 : nasties[i][5] = 24; nasties[i][6] = 0; nasties[i][7] = nastylist[levno-1][i][3]; nasties[i][8] = 0; nasties[i][9] = nastylist[levno-1][i][4]; break; case 2 : nasties[i][5] = 16; nasties[i][6] = nastylist[levno-1][i][3]; nasties[i][7] = 0; nasties[i][8] = nastylist[levno-1][i][4]; nasties[i][9] = 0; break; case 3 : nasties[i][5] = 255; nasties[i][6] = 0; break; case 4 : nasties[i][4] = 8<<16; nasties[i][5] = 48; nasties[i][6] = nastylist[levno-1][i][3]; nasties[i][7] = 0; nasties[i][8] = 0; nasties[i][9] = 128; break; case 5 : nasties[i][4] = 8<<16; nasties[i][5] = 12; nasties[i][6] = -(4<<16); break; case 6 : nasties[i][5] = 100; nasties[i][6] = nastylist[levno-1][i][3]<<10; nasties[i][7] = 0; nasties[i][8] = 0; break; case 7 : nasties[i][5] = 128; nasties[i][6] = 0; nasties[i][7] = 0; nasties[i][8] = 0; break; case 8 : nasties[i][5] = 12; nasties[i][6] = 0; break; default : if (nastycount == 255) nastycount = i; } } //Wipe any fireballs for (i=0;i0 && paradox==0) message = 255; for (i=0;i<64;i++) {coins[i].sprite = 0; coins[i].collected = (coins[i].collected & 2);} //Wipe off the blood for (i=0;i<64;i++) blood[i].x = 255; nextblood = 0; } void MoveMap (void) { int no_checks,found; int checkx1, checky1, checkx2, checky2, checkdirn; int posscrx, posscry; int i; if (!theend) { if (cursnail.xspeed >= (2<<16)) { if ((maplookahead+=2) > 64) maplookahead = 64; } if (cursnail.xspeed <= -(2<<16)) { if ((maplookahead-=2) < -64) maplookahead = -64; } if ((cursnail.xspeed > -(2<<16)) && (cursnail.xspeed < (2<<16))) { if (maplookahead > 0) { maplookahead-=2; } if (maplookahead < 0) { maplookahead+=2; } } } else { if (time>128) { if (time==129) timetochange = 0; if (time>(bossdeath-512)) { targscrx = (25*20)<<8; targscry = (48*20)<<8; timetochange = 4; } if ((timetochange--) == 0) { timetochange=256; no_checks = 0; found = 0; while (no_checks<16 && !found) { switch (rand() % 6) { case 0: posscrx = (6*20)<<8; posscry = (28*20)<<8; checkx1 = 6; checkx2 = 17; checky1 = 29; checky2 = 35; checkdirn = 0; break; case 1: posscrx = (8*20)<<8; posscry = (34*20)<<8; checkx1 = 6; checkx2 = 19; checky1 = 36; checky2 = 41; checkdirn = 0; break; case 2: posscrx = (10*20)<<8; posscry = (40*20)<<8; checkx1 = 6; checkx2 = 21; checky1 = 42; checky2 = 47; checkdirn = 0; break; case 3: posscrx = (45*20)<<8; posscry = (30*20)<<8; checkx1 = 52; checkx2 = 61; checky1 = 32; checky2 = 38; checkdirn = 1; break; case 4: posscrx = (43*20)<<8; posscry = (36*20)<<8; checkx1 = 50; checkx2 = 61; checky1 = 39; checky2 = 44; checkdirn = 1; break; case 5: posscrx = (41*20)<<8; posscry = (42*20)<<8; checkx1 = 48; checkx2 = 61; checky1 = 45; checky2 = 50; checkdirn = 1; break; } for (i=0;i<=slipno;i++) { if (posscrx != targscrx && snails[i][time+96].x>checkx1 && snails[i][time+96].xchecky1 && snails[i][time+96].y>6); scry+=((targscry-scry)>>6); } } if (++animdelay == 4) {animdelay = 0; doanim = 1;} } void PlotMap (void) { register GsSPRITE* tile = (GsSPRITE*)getScratchAddr(sizeof(GsSPRITE)); int u,v,x,y,xoffset,yoffset,angle,display; register long tileno; register long tilex; register long tiley; // Set sprite used for drawing backdrop to initial values InitGsSprite (tile); if (!theend || slipping>0) { // Find where top left of screen should be given // where you are and what speed your doing // Convert to global co-ords u = (20*cursnail.x + (u_char)(cursnail.xdis>>16)) - 150; v = (20*cursnail.y + (u_char)(cursnail.ydis>>16)) - 118; u+=maplookahead; } else { u = scrx>>8; v = scry>>8; } // Confine screen to edges of map if (u < 0) u = 0; if (u > (48*20)) u = (48*20); if (v < 0) v = 0; if (PAL) { if (v > (51*20)) v = (51*20); } else { if (v > ((52*20)+4)) v = (52*20)+4; } // Change to block-no/displacement form mapx = u / 20; mapxdis = u % 20; mapy = v / 20; mapydis = v % 20; tile->x = -(int)(mapxdis); tile->y = -(int)(mapydis); tilex = mapx; tiley = mapy; if (paradox == 0) { while (tile->y<256) { while (tile->x<320) { if ((tileno = map[tilex++][tiley]) < 255) { if (doanim == 1) map[tilex-1][tiley] = animtable[tileno]; if (tileno>28 && tileno<38) { if (doors[tileno-29].opening==0) map[tilex-1][tiley]=tileno-9; } if (tileno>19 && tileno<29) { if (doors[tileno-20].opening==1) map[tilex-1][tiley]=tileno+9; } tile->tpage = mapsprs[tileno][0]; tile->u = mapsprs[tileno][1]; tile->v = mapsprs[tileno][2]; GsSortFastSprite( tile, &Wot[side], 14); } tile->x+=20; } tilex = mapx; tile->x = -(int)(mapxdis); tile->y+=20; tiley++; } } else { tile->scalex = tile->scaley = 4096 + 32*(330-paradox); tile->rotate = 160*(330-paradox)*(330-paradox); angle = tile->rotate+(4096*45); while (angle>=(360*4096)) angle-=(360*4096); xoffset = -((tile->scalex/290) * DJcos(angle/360))/4096; yoffset = -((tile->scalex/290) * DJsin(angle/360))/4096; display = paradox-20; x = tile->x; y = tile->y; while (y<256) { while (x<320) { tile->x = x; tile->y = y; if ((tileno = map[tilex++][tiley]) < 255) { if (doanim == 1) map[tilex-1][tiley] = animtable[tileno]; if (tileno>28 && tileno<38) { if (doors[tileno-29].opening==0) map[tilex-1][tiley]=tileno-9; } if (tileno>19 && tileno<29) { if (doors[tileno-20].opening==1) map[tilex-1][tiley]=tileno+9; } tile->tpage = mapsprs[tileno][0]; tile->u = mapsprs[tileno][1]; tile->v = mapsprs[tileno][2]; if (--display>0) { tile->x = x + 10 + xoffset; tile->y = y + 10 + yoffset; GsSortSprite( tile, &Wot[side], 14); } } x+=20; } tilex = mapx; x = -(int)(mapxdis); y+=20; tiley++; } } if (doanim == 1) doanim = 0; } void StartNewLev (void) { int i; cursnail.x = startpos[levno-1][0]; cursnail.y = startpos[levno-1][1]; cursnail.xdis = cursnail.ydis = 0; cursnail.xspeed = cursnail.yspeed = 0; cursnail.framedel = 0; cursnail.dirn = cursnail.finaldirn = cursnail.frame = 0; cursnail.firedel = 0; slipno = time = slipping = reachedexit = paradox = 0; nocoins = trigmess = 0; for (i=0;i<64;i++) coins[i].collected = 0; ResetPositions(); SetupMap(); messages[0][0][10] = 48+(cointarget[levno-1]/10); messages[0][0][11] = 48+(cointarget[levno-1] % 10); if (levno==endlev) StartMessage(21); else StartMessage(0); } void SetupMap () { //Copy current map from main memory into proper array //Set starting position of snail int x,y,i; u_char nextcoin = 0; unsigned char * mapptr = (unsigned char *)(leveladdresses[levno-1]); for (y=0;y<64;y++) { for (x=0;x<64;x++) { map[x][y] = *(mapptr++); if (map[x][y] == 253 || map[x][y] == 254) { if (map[x][y] == 253) map[x][y] = 255; else map[x][y] = 47; coins[nextcoin].x = x; coins[nextcoin].y = y; nextcoin++; } } } totalcoins = nextcoin; while (nextcoin<64) { coins[nextcoin].x = 255; nextcoin++; } //Copy over the positions of any doors in the level for (i=0;i<9;i++) { doors[i].x = doorlists[levno-1][i][0]; doors[i].y = doorlists[levno-1][i][1]; doors[i].type = doorlists[levno-1][i][2]; if (doors[i].x == 0 || doors[i].y == 0) doors[i].type = 255; } maplookahead = 0; } void DealWithControllerPad (void) { u_char storemove = 0; pad = PadRead(); if (reachedexit != 0) pad = 0; if (paradox != 0) { pad = 0; if (paradox>1) paradox--; } // quit program if (pad & PADselect) { while (pad & PADselect) pad = PadRead(); quit = 1; } if (theend>0) pad = 0; // pause if (pad & PADstart) { while (pad & PADstart) { pad = PadRead(); } while (!(pad & PADstart)) { pad = PadRead(); } while (pad & PADstart) { pad = PadRead(); } VSync(0); } if ((pad & PADL1) && sfxvol>0) sfxvol--; if ((pad & PADR1) && sfxvol<256) sfxvol++; if ((pad & PADL2) && musicvol>0) { musicvol--; SsSetSerialVol(SS_CD, musicvol, musicvol); } if ((pad & PADR2) && musicvol<127) { musicvol++; SsSetSerialVol(SS_CD, musicvol, musicvol); } if ((pad & PADRleft) && time<(slipsize-4)) { MovePlatforms(); MoveSnails(); MoveNasties(); MoveBalls(); MoveMap(); MoveDoors(); CheckExit(); MoveCoins(); MoveStars2(); MoveDust(); if (message<255) MoveMessage(); time++; MovePlatforms(); MoveSnails(); MoveNasties(); MoveBalls(); MoveMap(); MoveDoors(); CheckExit(); MoveCoins(); MoveStars2(); MoveDust(); if (message<255) MoveMessage(); time++; } } int playlist[13] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0}; void MenuControlPad (void) { pad = PadRead(); // quit program if (pad & PADselect) { while (pad & PADselect) pad = PadRead(); quit = 2; } if ((pad & PADL1) && sfxvol>0) sfxvol--; if ((pad & PADR1) && sfxvol<256) sfxvol++; if ((pad & PADL2) && musicvol>0) { musicvol--; SsSetSerialVol(SS_CD, musicvol, musicvol); } if ((pad & PADR2) && musicvol<127) { musicvol++; SsSetSerialVol(SS_CD, musicvol, musicvol); } if (!waitingforCD) { // pause if (putincheatdel) { if (!(pad & PADstart) && !(pad & PADRdown)) putincheatdel=0; } else { if (changedcode==0 && ((pad & PADstart) || (pad & PADRdown))) { start = 1; levno = CheckCode(); } } if (changedcode==0) { if (pad & PADLup || pad & PADLdown || pad & PADLleft || pad & PADLright || pad & PADRright) changedcode=1; if (pad & PADRright) waitingforCD=1; if (pad & PADLup && passcode[digit]<9) { passcode[digit]++; SsUtKeyOn(vabno,CoinSnd,0,48,0,(sfxvol*64)>>8,(sfxvol*64)>>8); } if (pad & PADLdown && passcode[digit]>0) { passcode[digit]--; SsUtKeyOn(vabno,CoinSnd,0,48,0,(sfxvol*64)>>8,(sfxvol*64)>>8); } if (pad & PADLleft && digit>0) { digit--; SsUtKeyOn(vabno,FireSnd,0,48,0,(sfxvol*52)>>8,(sfxvol*52)>>8); } if (pad & PADLright && digit<7) { digit++; SsUtKeyOn(vabno,FireSnd,0,48,0,(sfxvol*52)>>8,(sfxvol*52)>>8); } } else { if (!(pad & PADLup || pad & PADLdown || pad & PADLleft || pad & PADLright || pad & PADRright || pad & PADRdown)) changedcode=0; } } else { if (changedcode==0) { if (pad & PADRdown) { waitingforCD = 0; changedcode = 1; CdPlay(2,playlist,0); } if (pad & PADRright) { waitingforCD = 0; changedcode = 1; } } else if (!(pad & PADRright)) changedcode = 0; } } // initialise sprite to dummy void InitGsSprite (GsSPRITE* sprite) { sprite->attribute = 1<<24; sprite->x = 0; sprite->y = 0; sprite->w = 20; sprite->h = 20; sprite->tpage = 0; sprite->u = 0; sprite->v = 0; sprite->cx = 320; sprite->cy = 511; // Fade out when you reach the exit or get to the end of a paradox if (reachedexit>0 && reachedexit<60 && ingame==1) sprite->r=sprite->g=sprite->b = (reachedexit*2); else { if (paradox>0 && paradox<60 && ingame==1) sprite->r=sprite->g=sprite->b = (paradox*2); else sprite->r=sprite->g=sprite->b = 132; } sprite->mx = 0; sprite->my = 0; sprite->scalex = ONE; sprite->scaley = ONE; sprite->rotate = 0; } void InitialiseAll (void) { int i,cx,cy; PadInit(); if (PAL) { SetVideoMode(MODE_PAL); GsInitGraph(320,256,GsOFSGPU,0,0); GsDefDispBuff(0,0,0,256); GsDISPENV.screen.x = 5; GsDISPENV.screen.y = 20; GsDISPENV.screen.h = 256; } else { SetVideoMode(MODE_NTSC); GsInitGraph(320,240,GsOFSGPU,0,0); GsDefDispBuff(0,0,0,240); GsDISPENV.screen.x = 5; GsDISPENV.screen.y = 10; GsDISPENV.screen.h = 240; } Wot[0].length=OT_LENGTH; Wot[0].org=wtags[0]; Wot[1].length=OT_LENGTH; Wot[1].org=wtags[1]; GsClearOt(0,0,&Wot[0]); GsClearOt(0,0,&Wot[1]); SetupPlatforms(); SetupNasties(); messages[0][0] = " collect ** coins "; messages[0][1] = " and reach the exit "; messages[0][2] = " "; messages[1][0] = " you need to find "; messages[1][1] = " more coins "; messages[1][2] = " "; messages[2][0] = "you collided with an"; messages[2][1] = " earlier version of "; messages[2][2] = " yourself "; messages[3][0] = " you got shot by an "; messages[3][1] = " earlier version of "; messages[3][2] = " yourself "; messages[4][0] = " an earlier version "; messages[4][1] = " of yourself "; messages[4][2] = " got shot "; messages[5][0] = " you were killed by "; messages[5][1] = " a goblin "; messages[5][2] = " "; messages[6][0] = " an earlier version "; messages[6][1] = " of yourself was "; messages[6][2] = " killed by a goblin "; messages[7][0] = " an electric sphere "; messages[7][1] = " zapped you "; messages[7][2] = " "; messages[8][0] = " a stinger impaled "; messages[8][1] = " you "; messages[8][2] = " "; messages[9][0] = " shoot the targets "; messages[9][1] = " but avoid the "; messages[9][2] = " electric sphere "; messages[10][0] = " you were impaled "; messages[10][1] = " by a spike ball "; messages[10][2] = " "; messages[11][0] = " a past echo got "; messages[11][1] = " impaled on a spike "; messages[11][2] = " ball "; messages[12][0] = " shoot the spike "; messages[12][1] = " balls to make them "; messages[12][2] = " move "; messages[13][0] = " "; messages[13][1] = " a robot killed you "; messages[13][2] = " "; messages[14][0] = " a robot killed a "; messages[14][1] = " past version of "; messages[14][2] = " yourself "; messages[15][0] = " a bouncer "; messages[15][1] = " squished you "; messages[15][2] = " "; messages[16][0] = " your almost at the "; messages[16][1] = " end "; messages[16][2] = " keep going "; messages[17][0] = "stand on the switch "; messages[17][1] = " to open the door "; messages[17][2] = " "; messages[18][0] = " watch out for your "; messages[18][1] = "past self doing just"; messages[18][2] = " what you did "; messages[19][0] = "now that the door is"; messages[19][1] = " open you can get "; messages[19][2] = " through "; messages[20][0] = "hold down square to "; messages[20][1] = "make time run faster"; messages[20][2] = " "; messages[21][0] = " destroy the plasma "; messages[21][1] = " space time relay "; messages[21][2] = " and end the cycle "; messages[22][0] = " a regeneration "; messages[22][1] = " cradle killed you "; messages[22][2] = " "; messages[23][0] = " the plasma relay "; messages[23][1] = " atomizes your body "; messages[23][2] = " "; for (i=0;i -16384 && clocks[i][2] < 16384) clocks[i][2] = (rand() * 16) - 262144; while (clocks[i][3] > -16384 && clocks[i][3] < 16384) clocks[i][3] = (rand() * 16) - 262144; clocks[i][4] = (rand() % 2047); clocks[i][5] = (rand() % 63) - 32; while (clocks[i][5] == 0) clocks[i][5] = (rand() % 63) - 32; } hand0 = 360*(rand() % 4095); hand1 = 360*(rand() % 4095); for (i=0;i>1) & 8128),(cy) & 7936); mapsprs[i][1]=(cx) % 128; mapsprs[i][2]=(cy) % 256; } } void SetupNasties (void) { int lev,i; for (lev=0;levvvlZZRX3 RMPSRMWBB*LR