/*Smiler's Christmas Sack eight-level mini-game Version 1.0 Digital Prawn December 2010 Public Domain Derived from the source code of Smiler 5: The Scattered Runes*/ #include #include #include #include #include #include #include #include //For debugging/playtesting #define STARTING_LEVEL 1 //For the demo version //#define DEMO_VERSION /* Memory Map 23755 ZX BASIC loader 32600 (approx) potential lower limit of stack 32768 Compiled C code and data (can reach up to 56025 MAX - Max code filesize = 23258) 56026 (0xDADA) 3-byte JP instruction to (compiled C) ISR routine 56064 (0xDB00) 257-byte IM2 vector table filled with 0xDADA 63488 1K HEAP for malloc() requests. (Could reach max range of 60527-64511) 64512 UDGs */ #define LEVEL_SIZE 176 #define HEAP_ADDR 63488 #define UDG_ADDR 64512 #define WAIT_KEY while(!in_Inkey()) #ifdef DEMO_VERSION #define NUM_LEVELS 1 #else #define NUM_LEVELS 8 #endif //MACROS #define SGN(x) ((x)<0?-1:((x)>0?1:0)) typedef unsigned char byte; typedef unsigned int word; //Globals //Colours of arrows byte arrow_colour[4]={7,3,2,1}; //level passcodes char *passcode[]= { "156910", "523790", "440617", "481475", "876218", "044737", "919380", "554717", "688025" //Extra passcode for "anagram screen" }; // LAST_K system variable used by IM2 keyboard handling routine extern char LAST_K(23560); // variables used by in_GetKey() byte in_KeyDebounce = 1; byte in_KeyStartRepeat = 20; byte in_KeyRepeatPeriod = 10; word in_KbdState; byte snow_on=0; long heap; char *current_map; /* level map data format (case sensitive) ' ' = open space '#' = red house obstruction (green trees in this game) 'S' = smiler starting point 'G' = Casper starting point (Smiler's Cousin) 'H' = Green house, the object of each level (White house in this game) 'R' = Rune, needed to activate house and solve final anagram (All arrows are listed in the sequence North, East, South, West) 'd','e','f','g' = Magenta arrows 'h','i','j','k' = Red arrows 'l','m','n','o' = Blue arrows 'p','q','r','s' = White arrows 't','u','v',w' = Reserved for future arrows 'x','y','z','{' = Reserved for future arrows a = antagonist (Frowner) */ /* Arrow behaviour Magenta arrows - same as first Smiler game - rotate all arrows on the level 90 degrees clockwise Red arrows - rotate all arrows on the level 90 degrees anti-clockwise Blue arrows - rotate all blue arrows 180 degrees. Rotate all magenta arrows 90 degrees clockwise. Rotate all red arrows 90 degrees anti-clockwise. Do not rotate white arrows. White arrows - do not rotate any arrows - but kill frowners when they step onto them */ /* level map data */ char *map[]= { " " //level 1 " " " ######## " " #Se# H # " " #g # ef# " " # mdo # " " #dhk#lm# " " # d #h # " " #R l#Gj# " " ######## " " ", " " //level 2 " " " ######## " " # o gG# " " #hjl# f# " " # f### # " " #dgH#R # " " # d #### " " # jn gS# " " ######## " " ", " " //level 3 " " " ######## " " # gld#R# " " #h # ik# " " #gj#Sl # " " #j G# n# " " # edfil# " " #H #f # " " ######## " " ", " " //level 4 " " " ######## " " #Ge lon# " " #df##gh# " " #jo#Hem# " " # fR#n # " " #mn##le# " " # o jS# " " ######## " " ", " " //level 5 " " " ######## " " #S ehi # " " #####no# " " #Re m j# " " #f l dH# " " #oj##### " " # gfg G# " " ######## " " ", " " //level 6 " " " ######## " " # jgS#G# " " # # g e# " " #le#ni # " " #jR## h# " " # #H #f# " " #o i # " " ######## " " ", " " //level 7 " " " ######## " " # o egR# " " #i# #de# " " #kShlG # " " # i#n#l# " " #e f ko# " " ##H#m# # " " ######## " " ", " " //level 8 " " " ######## " " #GdeflS# " " #nijkhe# " " #fejhof# " " #ejingg# " " #dfgijh# " " #RledhH# " " ######## " " " }; char *level_name[]= { "Baby it's cold outside", "Winter Wonderland", "Chestnuts roasting", "Ni Liv", "Snowball Express", "Silver Bells", "Christmas Vacation", "It's a Wonderful Life" }; //Anagram char anagram[]="eieldtuy"; char solution[]="yuletide"; //Which player character, smiler or Casper? //0=Smiler, 1=Casper byte current_p; //player x and y and old values (Smiler & Casper) byte px[2],py[2],ox[2],oy[2],is_home[2]; //Found rune? byte found_rune; //Snow variables #define NUM_SNOWFLAKES 32 word screenline[192]; //Addresses of screen line byte xsnow[NUM_SNOWFLAKES],ysnow[NUM_SNOWFLAKES]; byte oxsnow[NUM_SNOWFLAKES],oysnow[NUM_SNOWFLAKES]; byte pixel[8]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; byte snow_count=0; /*Set up a UDG (numbered from 128-255) */ void set_udg(byte n,byte d0, byte d1, byte d2, byte d3, byte d4, byte d5, byte d6, byte d7); /*Print a string at x,y */ void printstrat64(byte x, byte y, char *s); #define printstrat32(x,y,s) printstrat64((x)<<1,(y),(s)) /*Set the current colour attributes */ void setcolattr(byte i, byte p, byte f, byte b); /* Print a colour string at x,y */ void printcolstrat64(byte i, byte p, byte f, byte b, byte x, byte y, char *s); #define printcolstrat32(i,p,f,b,x,y,s) printcolstrat64((i),(p),(f),(b),(x)<<1,(y),(s)) /* print a 2x2 UDG number u at x,y */ void print2x2udgat64(byte x, byte y, byte u); #define print2x2udgat32(x,y,u) print2x2udgat64((x)<<1,(y),(u)) /* print a colour 2x2 UDG number u at x,y */ void printcol2x2udgat64(byte i, byte p, byte f, byte b, byte x, byte y, byte u); #define printcol2x2udgat32(i,p,f,b,x,y,u) printcol2x2udgat64((i),(p),(f),(b),(x)<<1,(y),(u)) /* clear the screen */ void cls(void); /* clear the screen to a specific colour */ void colcls(byte i, byte p, byte f, byte b); /* clear the screen and set the BORDER to the specified colour o*/ void colborcls(byte i, byte p, byte f, byte b, byte o); /* set mode to either 32 or 64 columns */ void setcolmode(byte m); /* init the session */ void init_session(void); /* init the game */ void init_game(void); /*init the level */ void init_level(byte l); /*called in the event of a fatal error */ void bombout(char *s); /* redraw the map pointed to by m*/ void redraw_map(char *m); /* draw the outine of a map */ void draw_map_outline(char *m); /*semi-optimised version of above function which is called many times in the main game loop*/ void fast_printcol2x2udgat64(byte i, byte p, byte x, byte y, byte u); #define fast_printcol2x2udgat32(i,p,x,y,u) fast_printcol2x2udgat64((i),(p),(x)<<1,(y),(u)); /*rotate the arrows on the board */ void rotate_arrows(char *m, byte rotator); /*Print the intro screen*/ void intro_screen(void); /* Set the status line */ void set_status_line(char *s); /* Wrapper around zx_border() library function. zx_border2() also sets BORDCR system variable which is needed if sounds are played when the BORDER is non-white */ void zx_border2(byte b); /*Slight delay in main loop to reduce flicker*/ void main_loop_delay(byte n); /*Initiate the IM2 mode interrupt handler*/ void init_im2_handler(void); /*Play sound effects but only if music is off. Also sleep for s seconds only if music is on. (to provide equivalent delay to that of a sound effect - so status line can be read) */ void my_bit_fx(byte n, byte m, byte s); //Screen for entering level passcodes byte passcode_screen(void); //Set a 2x2 udg to an enlarged character void set_bigchar_udg(byte n, byte c); //Expand a row of character bitmap into twice it's normal width void expand_char_row(byte in, byte *left, byte *right); //Screen for entering final anagram solution //returns 0 for incorrect answer, 1 for correct answer, //2 to cancel back to main menu byte anagram_screen(void); //print a double-sized string void print_double_string(byte i, byte p, byte x, byte y, char *s); //print the Christmas message void christmas_message(void); //Snow routines void init_snow_routines(void); void update_snow(void); //ISR void start_snow(void); void stop_snow(void); void my_plot(byte x, byte y); void my_unplot(byte x, byte y); //Interrupt service routine for animated snow M_BEGIN_ISR(isr) { //char c; // if ((c = in_GetKey()) != 0) // LAST_K = c; if(snow_on) { update_snow(); } } M_END_ISR main() { byte i,level_over, session_over,level,killed; byte rotate_flag=0; init_session(); roswell: session_over=0; level=STARTING_LEVEL; //for playtesting //level=NUM_LEVELS; while(!session_over) { intro_screen(); init_game(); passenter: level=passcode_screen(); if(level>NUM_LEVELS) goto anagram; levelstart: init_level(level); start_snow(); level_over=0; redraw_map(current_map); // main game loop while(!level_over) { byte k,nx,ny,c,ok; char temp[32]; //keep this commented out to enable keyboard auto-repeat //in_WaitForNoKey(); while(!(k=in_Inkey())); //'x' key quits the game if(k=='x') { stop_snow(); goto roswell; } if(k=='r') { set_status_line("Restarting level!"); my_bit_fx(4,3,2); level_over=1; } //Switch between Smiler and Casper if(k=='s') { //update old-coordinates to prevent them erasing //smiler being switched to ox[current_p]=px[current_p]; oy[current_p]=py[current_p]; current_p^=1; redraw_map(current_map); my_bit_fx(1,5,0); } //store old position values for erasing old sprite in draw routine ox[current_p]=px[current_p];oy[current_p]=py[current_p]; nx=px[current_p]+(((k=='p')-(k=='o'))<<1); ny=py[current_p]+(((k=='a')-(k=='q'))<<1); c=current_map[(ny<<3)+(nx>>1)]; //Debugging //sprintf(temp,"%d %d %d %d %d \0",px,py,nx,ny,(int)c); //printstrat32(0,18,temp) ok=0; if(c>='a'&&c<='z') { byte d=c&0x03; ok=((d==0)&&(k=='q'))||((d==1)&&(k=='p'))|| ((d==2)&&(k=='a'))||((d==3)&&(k=='o')); } rotate_flag=0; //if can move into square and have actually moved on this turn if((c==32||c=='H'||c=='R'||ok)&&(px[current_p]!=nx||py[current_p]!=ny)) { //set new value px[current_p]=nx;py[current_p]=ny; if(ok) { rotate_arrows(current_map,c); rotate_flag=1; } //reset is_home flag is_home[current_p]=0; if(c=='H'&&found_rune) { //flag this player character as home is_home[current_p]=1; //if other character home too, then level completed if(is_home[1-current_p]) { redraw_map(current_map); set_status_line("Level Complete!"); for(i=0;i<7;i++) my_bit_fx(1,4,2); level_over=1; level++; } } //Stepped on rune if(c=='R') { found_rune=1; //remove rune from map current_map[(ny<<3)+(nx>>1)]=32; my_bit_fx(1,1,0); } } //only redraw the map if smiler moved redraw_map(current_map); //play arrow sound fx immediately after map redraw if(rotate_flag) my_bit_fx(1,6,0); } stop_snow(); if(level<=NUM_LEVELS) { goto levelstart; } else { anagram: //Don't have the anagram screen in the demo version #ifndef DEMO_VERSION //repeat anagram screen until correct soultion is presented while(!(i=anagram_screen())); //check if anagram screen was cancelled if(i==2) goto roswell; set_status_line("Congrats! Entire game completed!"); #else set_status_line("Congrats! Demo completed! "); #endif for(i=0;i<3;i++) my_bit_fx(2,4,2); printf("PRESS A KEY"); WAIT_KEY; goto roswell; } } } void set_udg(byte n, byte d0, byte d1, byte d2, byte d3, byte d4, byte d5, byte d6, byte d7) { byte *a=(byte *)UDG_ADDR+((n-128)<<3); a[0]=d0;a[1]=d1;a[2]=d2;a[3]=d3; a[4]=d4;a[5]=d5;a[6]=d6;a[7]=d7; } void printstrat64(byte x, byte y, char *s) { putchar(22);putchar(32+y);putchar(32+x); printf("%s",s); } void setcolattr(byte i, byte p, byte f, byte b) { putchar(16); putchar(i|0x30); //ink putchar(17); putchar(p|0x30); //paper putchar(18); putchar(f|0x30); //flash putchar(19); putchar(b|0x30); //bright } void printcolstrat64(byte i, byte p, byte f, byte b, byte x, byte y, char *s) { setcolattr(i,p,f,b); printstrat64(x,y,s); } void print2x2udgat64(byte x, byte y, byte u) { char t[3]; t[2]=0; t[0]=u++;t[1]=u++; putchar(22);putchar(32+y);putchar(32+x); printf("%s",t); putchar(22);putchar(33+y);putchar(32+x); t[0]=u++;t[1]=u++; printf("%s",t); } void printcol2x2udgat64(byte i, byte p, byte f, byte b, byte x, byte y, byte u) { setcolattr(i,p,f,b); print2x2udgat64(x,y,u); } void fast_printcol2x2udgat64(byte i, byte p, byte x, byte y, byte u) { putchar(16); putchar(i|0x30); //ink putchar(17); putchar(p|0x30); //paper putchar(22);putchar(32+y);putchar(32+x);putchar(u++);putchar(u++); putchar(22);putchar(33+y);putchar(32+x);putchar(u++);putchar(u++); } void cls(void) { putchar(12); //send a form feed control } void colcls(byte i, byte p, byte f, byte b) { setcolattr(i,p,f,b); cls(); } void colborcls(byte i, byte p, byte f, byte b, byte o) { colcls(i,p,f,b); zx_border2(o); } void setcolmode(byte m) { putchar(1);putchar(m); } void init_session(void) { //Inititialise the heap mallinit(); // set heap as currently empty sbrk(HEAP_ADDR,1024); // add a 1K heap // Init keyboard routines in_GetKeyReset(); //Init the sound system bit_open(); //Init the IM2 interrupt handler for keyboard handling & AY chip music init_im2_handler(); //Alter UDG address to allow full range of 128 UDGs (above heap) putchar(3);putchar(UDG_ADDR/0x0100);putchar(UDG_ADDR%0x0100); //setup UDGs //tree sprite set_udg(128,0,1,3,7,15,3,7,15); set_udg(129,0,128,192,224,240,192,224,240); set_udg(130,31,3,7,15,31,63,1,1); set_udg(131,248,192,224,240,248,252,128,128); //up-arrow sprite set_udg(132,0xff,0xfe,0xfc,0xf8,0xf0,0xe0,0xc0,0xc0); set_udg(133,0xff,0x7f,0x3f,0x1f,0x0f,0x07,0x03,0x03); set_udg(134,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xff,0xff); set_udg(135,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0xff,0xff); //right-arrow sprite set_udg(136,0xff,0xff,0xff,0xff,0xff,0xff,0xc0,0xc0); set_udg(137,0xff,0xff,0x3f,0x1f,0x0f,0x07,0x03,0x01); set_udg(138,0xc0,0xc0,0xff,0xff,0xff,0xff,0xff,0xff); set_udg(139,0x01,0x03,0x07,0x0f,0x1f,0x3f,0xff,0xff); //down-arrow sprite set_udg(140,0xff,0xff,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc); set_udg(141,0xff,0xff,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f); set_udg(142,0xc0,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff); set_udg(143,0x03,0x03,0x07,0x0f,0x1f,0x3f,0x7f,0xff); //left-arrow sprite set_udg(144,0xff,0xff,0xfc,0xf8,0xf0,0xe0,0xc0,0x80); set_udg(145,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x03); set_udg(146,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xff,0xff); set_udg(147,0x03,0x03,0xff,0xff,0xff,0xff,0xff,0xff); //Smiley face set_udg(148,0xff,0xfc,0xe0,0xc0,0xc0,0xcc,0x8c,0x80); set_udg(149,0xff,0x3f,0x07,0x03,0x03,0x33,0x31,0x01); set_udg(150,0x81,0x91,0xd0,0xc8,0xc6,0xe1,0xfc,0xff); set_udg(151,0x81,0x89,0x0b,0x13,0x63,0x87,0x3f,0xff); //Smiley face (greyed out) set_udg(152,0xff|0xaa,0xfc|0x55,0xe0|0xaa,0xc0|0x55,0xc0|0xaa,0xcc|0x55,0x8c|0xaa,0x80|0x55); set_udg(153,0xff|0xaa,0x3f|0x55,0x07|0xaa,0x03|0x55,0x03|0xaa,0x33|0x55,0x31|0xaa,0x01|0x55); set_udg(154,0x81|0xaa,0x91|0x55,0xd0|0xaa,0xc8|0x55,0xc6|0xaa,0xe1|0x55,0xfc|0xaa,0xff|0x55); set_udg(155,0x81|0xaa,0x89|0x55,0x0b|0xaa,0x13|0x55,0x63|0xaa,0x87|0x55,0x3f|0xaa,0xff|0x55); //Frowner (antagonist) set_udg(156,0xff,0xfc,0xe0,0xc0,0xc0,0xcc,0x8c,0x81); set_udg(157,0xff,0x3f,0x07,0x03,0x03,0x33,0x31,0x81); set_udg(158,0x81,0x80,0xc7,0xc8,0xc0,0xe0,0xfc,0xff); set_udg(159,0x81,0x01,0xe3,0x13,0x03,0x07,0x3f,0xff); //inactive house sprite set_udg(160, 1&0xaa, 3&0x55, 7&0xaa, 15&0x55, 31&0xaa, 63&0x55,127&0xaa,255&0x55); set_udg(161,128&0xaa,192&0x55,224&0xaa,240&0x55,248&0xaa,252&0x55,254&0xaa,255&0x55); set_udg(162,195&0xaa,195&0x55,195&0xaa,195&0x55,255&0xaa,255&0x55,255&0xaa,255&0x55); set_udg(163,255&0xaa,255&0x55, 15&0xaa, 15&0x55, 15&0xaa, 15&0x55, 15&0xaa, 15&0x55); //house sprite set_udg(168,1,3,7,15,31,63,127,255); set_udg(169,128,192,224,240,248,252,254,255); set_udg(170,195,195,195,195,255,255,255,255); set_udg(171,255,255,15,15,15,15,15,15); //Christmas cracker top set_udg(200,128,192,224,240,248,252,254,255); set_udg(201,1,3,7,15,31,63,127,255); set_udg(202,255,255,255,255,255,255,255,255); set_udg(203,255,255,255,255,255,255,255,255); //Christmas cracker bottom set_udg(204,255,255,255,255,255,255,255,255); set_udg(205,255,255,255,255,255,255,255,255); set_udg(206,255,254,252,248,240,224,192,128); set_udg(207,255,127,63,31,15,7,3,1); //blank sprite set_udg(252,0,0,0,0,0,0,0,0); set_udg(253,0,0,0,0,0,0,0,0); set_udg(254,0,0,0,0,0,0,0,0); set_udg(255,0,0,0,0,0,0,0,0); //Set 32 column mode setcolmode(32); // Set the screen to black background and border colborcls(0,0,0,0,0); //Allocate memory for current map if(!(current_map=malloc(LEVEL_SIZE))) { bombout("Insufficient RAM"); } //Initialise the snow routines init_snow_routines(); } void init_game(void) { //Set 32 column mode for main game setcolmode(32); } void init_level(byte l) { char s[32]; // Set the screen to black background and black border //and clear the screen colborcls(0,0,0,0,0); //Reset found_rune found_rune=0; //Set the large UDG 164 to current letter of anagram //(Converted to upper case) set_bigchar_udg(164,anagram[l-1]&0xdf); memcpy(current_map, map[l-1],LEVEL_SIZE); sprintf(s,"Level %d: %s\0",l,level_name[l-1]); set_status_line(s); printstrat32(0,23,"Code:"); printstrat32(5,23,passcode[l-1]); draw_map_outline(current_map); //Set current sprite to Smiler current_p=0; //Reset is_home? flags is_home[0]=is_home[1]=0; } void bombout(char *s) { setcolmode(64); colborcls(1,0,0,1,0); puts("Fatal Error:"); puts(s); exit(0); } void redraw_map(char *m) { //of=occupied flag byte i,x,y,of; //skip top and bottom for(i=16;i<160;i++) { x=(i&0x0f)<<1; y=(i>>3)&0xfe; of=0; if(x==px[0]&&y==py[0]) { //Erase old smiler if moved off a space if((ox[0]!=x||oy[0]!=y)&&(m[(oy[0]<<3)+(ox[0]>>1)]==32)) { //check for other smiler if(ox[0]==px[1]&&oy[0]==py[1]) { fast_printcol2x2udgat32(0,1,ox[0],oy[0],152); } else { fast_printcol2x2udgat32(0,0,ox[0],oy[0],252); //blank space } } //Draw Smiler fast_printcol2x2udgat32(0,(current_p?1:6),x,y,(current_p?152:148)); of=1; } if(x==px[1]&&y==py[1]) { //Erase old Casper if moved off a space if((ox[1]!=x||oy[1]!=y)&&(m[(oy[1]<<3)+(ox[1]>>1)]==32)) { //check for other smiler if(ox[1]==px[0]&&oy[1]==py[0]) { fast_printcol2x2udgat32(0,1,ox[1],oy[1],152); } else { fast_printcol2x2udgat32(0,0,ox[1],oy[1],252); //blank space } } //Draw Casper fast_printcol2x2udgat32(0,(current_p?2:1),x,y,(current_p?148:152)); of=1; } if(!of) { //print a map tile or home //Probably not much faster to skip edges //if((x>0x00)&&(x<0x1e) //All lower case letters are arrows if(m[i]>='a'&&m[i]<='z') { fast_printcol2x2udgat32(5,arrow_colour[(m[i]&0x0f)>>2],x,y,132+((m[i]&0x03)<<2)); //arrow } else if(m[i]=='H') { fast_printcol2x2udgat32(7,0,x,y,found_rune?168:160); } } } } void draw_map_outline(char *m) { byte i,x,y; christmas_message(); /* Not needed in this version for(i=0;i<16;i+=2) { fast_printcol2x2udgat32(4,0,8+i,4,128); fast_printcol2x2udgat32(4,0,8+i,18,128); fast_printcol2x2udgat32(4,0,8,4+i,128); fast_printcol2x2udgat32(4,0,22,4+i,128); } */ for(i=16;i<160;i++) { x=(i&0x0f)<<1; y=(i>>3)&0xfe; //print just the trees here //skip map edges for speedup if((x>0x00)&&(x<0x1e)) { switch(m[i]) { case '#': fast_printcol2x2udgat32(4,0,x,y,128); //tree break; case 'S': //smiley man ox[0]=px[0]=x; //set starting position oy[0]=py[0]=y; m[i]=' '; //blank the smiley off the current map break; case 'G': //Casper ox[1]=px[1]=x; //set starting position oy[1]=py[1]=y; m[i]=' '; //blank Casper off the current map break; case 'R': //Rune fast_printcol2x2udgat32(7,0,x,y,164); //Rune break; default: break; } } } } void rotate_arrows(char *m, byte rotator) { byte i; switch(rotator) { //the clockwise rotators case 'd':case 'e':case 'f':case 'g': for(i=16;i='a'&&m[i]<='z') m[i]=(m[i]&0xfc)+((m[i]+1)&3); break; //the anti-clockwise rotators case 'h':case 'i':case 'j':case 'k': for(i=16;i='a'&&m[i]<='z') m[i]=(m[i]&0xfc)+((m[i]-1)&3); break; //these rotators turn themselves 180deg and also // turn defg clockwise and hijk anti-clockwise //leave pqrs untouched case 'l':case 'm':case 'n':case 'o': for(i=16;i'9'))&&(k!=12)) k=0; } //debugging //printf("%d",k); if(k==12) { if(i) i--; printstrat32(9+(i<<1),12,"*"); //my_bit_fx(1,1,0); } else { buf[i]=k;buf[i+1]=0; printstrat32(9+(i<<1),12,buf+i); //my_bit_fx(1,6,0); i++; } } #ifdef DEMO_VERSION return 1; #endif match=0; i=0; //Search 1 more than NUM_LEVELS because the final "anagram screen" //also has a passcode while(i<(NUM_LEVELS+1)&&!match) { if(!strcmp(buf,passcode[i])) { match=i; } i++; } return match+1; } void set_bigchar_udg(byte n, byte c) { byte *chrptr=(byte *)(0x3d00+((c-32)<<3)); byte t0,t1,t2,t3,t4,t5,t6,t7; expand_char_row(*chrptr++,&t0,&t1); expand_char_row(*chrptr++,&t2,&t3); expand_char_row(*chrptr++,&t4,&t5); expand_char_row(*chrptr++,&t6,&t7); set_udg(n++,t0,t0,t2,t2,t4,t4,t6,t6); set_udg(n++,t1,t1,t3,t3,t5,t5,t7,t7); expand_char_row(*chrptr++,&t0,&t1); expand_char_row(*chrptr++,&t2,&t3); expand_char_row(*chrptr++,&t4,&t5); expand_char_row(*chrptr++,&t6,&t7); set_udg(n++,t0,t0,t2,t2,t4,t4,t6,t6); set_udg(n++,t1,t1,t3,t3,t5,t5,t7,t7); } void expand_char_row(byte in, byte *left, byte *right) { byte i; word w=0; for(i=0;i<8;i++) { if(in&(1<>8; *right=w&0xff; } byte anagram_screen(void) { char buf[9]; byte i,k; setcolmode(32); colborcls(7,2,0,0,2); //clear screen and set border printstrat32(1,10,"Type the anagram solution:"); printstrat32(10,12,"--------"); printstrat32(4,14,"Press ENTER to abort"); printstrat32(0,23,"Code:"); printstrat32(5,23,passcode[8]); i=0; while(i<8) { in_WaitForNoKey(); k=0; while(!k) { k=in_Inkey(); //Allow ENTER to cancel the anagram screen if(k==13) return 2; //allow only lowercase alphabetical keys and delete if(((k<'a')||(k>'z'))&&(k!=12)) k=0; } if(k==12) { if(i) i--; printstrat32(10+i,12,"-"); //my_bit_fx(1,1,0); } else { buf[i]=k;buf[i+1]=0; printstrat32(10+i,12,buf+i); //my_bit_fx(1,6,0); i++; } } return(strcmp(buf,solution)==0); } void print_double_string(byte i, byte p, byte x, byte y, char *s) { char c; while(c=*s++) { set_bigchar_udg(172,c); fast_printcol2x2udgat32(i,p,x,y,172); x+=2; } } void christmas_message(void) { print_double_string(4,2,7,0," MERRY "); print_double_string(4,2,7,2,"CHRISTMAS"); print_double_string(4,2,0,0," "); print_double_string(4,2,0,2," "); print_double_string(4,2,26,0," "); print_double_string(4,2,26,2," "); fast_printcol2x2udgat32(2,0,5,0,200); fast_printcol2x2udgat32(2,0,25,0,200); fast_printcol2x2udgat32(2,0,5,2,204); fast_printcol2x2udgat32(2,0,25,2,204); } void init_snow_routines(void) { byte i,t; //Generate lookup table of screen addresses for(i=0;i<192;i++) screenline[i]=0x4000+((i&0xc0)<<5)+((i&0x38)<<2)+((i&0x07)<<8); //init snowflake co-ordinates for(i=0;i63)&&(t<192)); oxsnow[i]=xsnow[i]=t; //only allow snow between scanlines 32 and 175 inclusive t=32+rand()%144; oysnow[i]=ysnow[i]=t; } } void update_snow(void) { byte i,s; //snow count counts 0,1,2,3 - process a quarter of snowflakes on each interrupt s=snow_count<<3; snow_count=(snow_count+1)&3; //replot the snow for(i=s;i-s<8;i++) { //update new snow co-ordinates ysnow[i]=ysnow[i]+snow_count+1; if(ysnow[i]>175) ysnow[i]=32; //random movement of snow xsnow[i]=xsnow[i]+(rand()&1)-(rand()&1); //avoid snow wandering onto play area if(xsnow[i]==64) xsnow[i]=192; if(xsnow[i]==191) xsnow[i]=63; //Unplot the snow *(byte *)(screenline[oysnow[i]]+(oxsnow[i]>>3))&=~pixel[oxsnow[i]&7]; //Plot the snow *(byte *)(screenline[ysnow[i]]+(xsnow[i]>>3))|=pixel[xsnow[i]&7]; //update old snow co-ordinates oxsnow[i]=xsnow[i]; oysnow[i]=ysnow[i]; } } void start_snow(void) { byte y; //set white ink and black paper at edges of screen for(y=4;y<22;y++) { printcolstrat32(7,0,0,1,0,y," "); printcolstrat32(7,0,0,1,24,y," "); } snow_on=1; } void stop_snow(void) { snow_on=0; } void my_plot(byte x, byte y) { *(byte *)(screenline[y]+(x>>3))|=pixel[x&7]; } void my_unplot(byte x, byte y) { *(byte *)(screenline[y]+(x>>3))&=~pixel[x&7]; }