//video gen and sound //D.5 is sync:1000 ohm + diode to 75 ohm resistor //D.6 is video:330 ohm + diode to 75 ohm resistor //C.0 is sound #pragma regalloc- //I allocate the registers myself #pragma optsize- //optimize for speed #include #include #include #include #include #include //cycles = 63.625 * 16 Note NTSC is 63.55 //but this line duration makes each frame exactly 1/60 sec //which is nice for keeping a realtime clock #define lineTime 1018 #define begin { #define end } #define ScreenTop 30 #define ScreenBot 230 #define T0reload 256-60 //maze size definitions #define height 10 #define width 10 #define mleft 8 #define mright 88 #define mtop 8 #define mbot 88 #define vcDrawStart 2 #define vrDrawStart 128 #define hrDrawStart 256 #define hcDrawStart 1 //States #define title1 0 #define title2 1 #define title3 2 #define title4 3 #define title5 4 #define clear 5 #define select1 6 #define select2 7 #define select3 8 #define select4 9 #define select5 10 #define select6 11 #define setup 12 #define check 13 #define create1 14 #define create2 15 #define create3 16 #define draw1 17 #define draw2 18 #define draw3 19 #define draw4 20 #define play 21 #define monster 22 #define key 23 #define win1 24 #define win2 25 #define win3 26 #define win4 27 #define win5 28 #define lose1 29 #define lose2 30 #define lose3 31 #define lose4 32 #define lose5 33 #define lose6 34 #define select7 35 #define select8 36 #define escape 37 #define munch 38 #define progGame 39 #define lose7 40 //NOTE that v1 to v8 and i must be in registers! register char v1 @4; register char v2 @5; register char v3 @6; register char v4 @7; register char v5 @8; register char v6 @9; register char v7 @10; register char v8 @11; register int i @12; #pragma regalloc+ char syncON, syncOFF; int LineCount; int time; char screen[1600], t, ts[10]; //Variables for man and monster on title screen unsigned char man, mon; //Variables for game setup unsigned char numPlayers, numMonsters, numKeys; unsigned char afterclear, progression, cursor; //Variables for storing and controlling user input unsigned char userInput0,userInput1,lastInput0,lastInput1; unsigned char userInput, lastInput; char userSwitch; //Variables for maze-generation algorithm unsigned char setnum, done; unsigned char lowset, highset; unsigned char set[10][10]; unsigned char walls[10][10]; //Variables for drawing maze int rowOffset, scrIndex; char colOffset; //Variables for storing and updating player position unsigned char playerNum, man0k,man0j,man1k,man1j; char mank, manj; //Variables for controlling monster movement unsigned char monsterMove, monsterBack, monsterNum; unsigned char monster0Back, monster1Back, monster2Back; char monster0k, monster0j, monster1k, monster1j, monster2k, monster2j, monsterk, monsterj; //Variables for tracking keys and exit unsigned char keyk[5], keyj[5]; unsigned char keysFound, foundKey; unsigned char escaped; char wink,winj; //Variables for tracking player deaths unsigned char eaten; unsigned char lives[2]; //Variables used for iteration and randomized selection unsigned char s, ia, ja, k, j, n; char m, ic, jc; unsigned int p; unsigned char state; //current state unsigned char min2,min1,sec2,sec1; //timer digit values unsigned int score; //current player's score //Strings for copying and displaying words from flash char string3[3]; char string4[4]; char string5[5]; char string6[6]; char string7[7]; eeprom unsigned int bestscore; //best score saved in eeprom //Words for Menu and Title Displays flash char title01[] = "MAZE"; flash char title02[] = "RUNNER"; flash char title03[] = "MARTIN"; flash char title04[] = "AND"; flash char title05[] = "JOHNSON"; flash char title06[] = "PRODUCT"; flash char title07[] = "ION"; flash char title08[] = "PRESS"; flash char select01[] = "PROGRES"; flash char select02[] = "SION"; flash char select03[] = "SINGLE"; flash char select04[] = "GAME"; flash char single01[] = "PLAYERS"; flash char single02[] = "MONSTER"; flash char single03[] = "KEYS"; flash char win01[] = "YOU"; flash char win02[] = "ESCAPED"; flash char win03[] = "THE"; flash char win04[] = "YOUR"; flash char win05[] = "SCORE"; flash char win06[] = "CONGRAT"; flash char win07[] = "ULATION"; flash char lose01[] = "WERE"; flash char lose02[] = "EATEN"; flash char lose03[] = "YUMMY"; flash char lose04[] = "LOSE"; flash char best01[] = "BEST"; flash char time1[] = "TIME"; flash char lvl[] = "LVL"; //Point plot lookup table flash char pos[8]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; //define some character bitmaps //5x7 characters flash char bitmap[40][7]={ //0 0b01110000, 0b10001000, 0b10011000, 0b10101000, 0b11001000, 0b10001000, 0b01110000, //1 0b00100000, 0b01100000, 0b00100000, 0b00100000, 0b00100000, 0b00100000, 0b01110000, //2 0b01110000, 0b10001000, 0b00001000, 0b00010000, 0b00100000, 0b01000000, 0b11111000, //3 0b11111000, 0b00010000, 0b00100000, 0b00010000, 0b00001000, 0b10001000, 0b01110000, //4 0b00010000, 0b00110000, 0b01010000, 0b10010000, 0b11111000, 0b00010000, 0b00010000, //5 0b11111000, 0b10000000, 0b11110000, 0b00001000, 0b00001000, 0b10001000, 0b01110000, //6 0b01000000, 0b10000000, 0b10000000, 0b11110000, 0b10001000, 0b10001000, 0b01110000, //7 0b11111000, 0b00001000, 0b00010000, 0b00100000, 0b01000000, 0b10000000, 0b10000000, //8 0b01110000, 0b10001000, 0b10001000, 0b01110000, 0b10001000, 0b10001000, 0b01110000, //9 0b01110000, 0b10001000, 0b10001000, 0b01111000, 0b00001000, 0b00001000, 0b00010000, //A 0b01110000, 0b10001000, 0b10001000, 0b10001000, 0b11111000, 0b10001000, 0b10001000, //B 0b11110000, 0b10001000, 0b10001000, 0b11110000, 0b10001000, 0b10001000, 0b11110000, //C 0b01110000, 0b10001000, 0b10000000, 0b10000000, 0b10000000, 0b10001000, 0b01110000, //D 0b11110000, 0b10001000, 0b10001000, 0b10001000, 0b10001000, 0b10001000, 0b11110000, //E 0b11111000, 0b10000000, 0b10000000, 0b11111000, 0b10000000, 0b10000000, 0b11111000, //F 0b11111000, 0b10000000, 0b10000000, 0b11111000, 0b10000000, 0b10000000, 0b10000000, //G 0b01110000, 0b10001000, 0b10000000, 0b10011000, 0b10001000, 0b10001000, 0b01110000, //H 0b10001000, 0b10001000, 0b10001000, 0b11111000, 0b10001000, 0b10001000, 0b10001000, //I 0b01110000, 0b00100000, 0b00100000, 0b00100000, 0b00100000, 0b00100000, 0b01110000, //J 0b00111000, 0b00010000, 0b00010000, 0b00010000, 0b00010000, 0b10010000, 0b01100000, //K 0b10001000, 0b10010000, 0b10100000, 0b11000000, 0b10100000, 0b10010000, 0b10001000, //L 0b10000000, 0b10000000, 0b10000000, 0b10000000, 0b10000000, 0b10000000, 0b11111000, //M 0b10001000, 0b11011000, 0b10101000, 0b10101000, 0b10001000, 0b10001000, 0b10001000, //N 0b10001000, 0b10001000, 0b11001000, 0b10101000, 0b10011000, 0b10001000, 0b10001000, //O 0b01110000, 0b10001000, 0b10001000, 0b10001000, 0b10001000, 0b10001000, 0b01110000, //P 0b11110000, 0b10001000, 0b10001000, 0b11110000, 0b10000000, 0b10000000, 0b10000000, //Q 0b01110000, 0b10001000, 0b10001000, 0b10001000, 0b10101000, 0b10010000, 0b01101000, //R 0b11110000, 0b10001000, 0b10001000, 0b11110000, 0b10100000, 0b10010000, 0b10001000, //S 0b01111000, 0b10000000, 0b10000000, 0b01110000, 0b00001000, 0b00001000, 0b11110000, //T 0b11111000, 0b00100000, 0b00100000, 0b00100000, 0b00100000, 0b00100000, 0b00100000, //U 0b10001000, 0b10001000, 0b10001000, 0b10001000, 0b10001000, 0b10001000, 0b01110000, //V 0b10001000, 0b10001000, 0b10001000, 0b10001000, 0b10001000, 0b01010000, 0b00100000, //W 0b10001000, 0b10001000, 0b10001000, 0b10101000, 0b10101000, 0b10101000, 0b01010000, //X 0b10001000, 0b10001000, 0b01010000, 0b00100000, 0b01010000, 0b10001000, 0b10001000, //Y 0b10001000, 0b10001000, 0b10001000, 0b01010000, 0b00100000, 0b00100000, 0b00100000, //Z 0b11111000, 0b00001000, 0b00010000, 0b00100000, 0b01000000, 0b10000000, 0b11111000, //Running Man 0b00000000, 0b00100000, 0b11111000, 0b00100000, 0b01010000, 0b10010000, 0b00000000, //The Smiling Face of Death 0b00000000, 0b10001000, 0b01010000, 0b00000000, 0b11111000, 0b10001000, 0b01110000, //blank 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, //key 0b00000000, 0b00111000, 0b00101000, 0b00111000, 0b00100000, 0b01000000, 0b10100000 }; //================================== //This is the sync generator and raster generator. It MUST be entered from //sleep mode to get accurate timing of the sync pulses #pragma warn- interrupt [TIM1_COMPA] void t1_cmpA(void) begin //start the Horizontal sync pulse PORTD = syncON; //count timer 0 at 1/usec TCNT0=0; //update the curent scanline number LineCount ++ ; //begin inverted (Vertical) synch after line 247 if (LineCount==248) begin syncON = 0b00100000; syncOFF = 0; end //back to regular sync after line 250 if (LineCount==251) begin syncON = 0; syncOFF = 0b00100000; end //start new frame after line 262 if (LineCount==263) begin LineCount = 1; end delay_us(2); //adjust to make 5 us pulses //end sync pulse PORTD = syncOFF; if (LineCount=ScreenTop) begin //compute byte index for beginning of the next line //left-shift 4 would be individual lines // <<3 means line-double the pixels //The 0xfff8 truncates the odd line bit //i=(LineCount-ScreenTop)<<3 & 0xfff8; // #asm push r16 lds r12, _LineCount lds r13, _Linecount+1 ldi r16, 30 sub r12, r16 ldi r16,0 sbc r13, r16 lsl r12 rol r13 lsl r12 rol r13 lsl r12 rol r13 mov r16,r12 andi r16,0xf0 mov r12,r16 pop r16 #endasm //load 16 registers with screen info #asm push r14 push r15 push r16 push r17 push r18 push r19 push r26 push r27 ldi r26,low(_screen) ;base address of screen ldi r27,high(_screen) add r26,r12 ;offset into screen (add i) adc r27,r13 ld r4,x+ ;load 16 registers and inc pointer ld r5,x+ ld r6,x+ ld r7,x+ ld r8,x+ ld r9,x+ ld r10,x+ ld r11,x+ ld r12,x+ ld r13,x+ ld r14,x+ ld r15,x+ ld r16,x+ ld r17,x+ ld r18,x+ ld r19,x pop r27 pop r26 #endasm delay_us(4); //adjust to center image on screen //blast 16 bytes to the screen #asm ;but first a macro to make the code shorter ;the macro takes a register number as a parameter ;and dumps its bits serially to portD.6 ;the nop can be eliminated to make the display narrower .macro videobits ;regnum BST @0,7 IN R30,0x12 BLD R30,6 nop OUT 0x12,R30 BST @0,6 IN R30,0x12 BLD R30,6 nop OUT 0x12,R30 BST @0,5 IN R30,0x12 BLD R30,6 nop OUT 0x12,R30 BST @0,4 IN R30,0x12 BLD R30,6 nop OUT 0x12,R30 BST @0,3 IN R30,0x12 BLD R30,6 nop OUT 0x12,R30 BST @0,2 IN R30,0x12 BLD R30,6 nop OUT 0x12,R30 BST @0,1 IN R30,0x12 BLD R30,6 nop OUT 0x12,R30 BST @0,0 IN R30,0x12 BLD R30,6 nop OUT 0x12,R30 .endm videobits r4 ;video line -- byte 1 videobits r5 ;byte 2 videobits r6 ;byte 3 videobits r7 ;byte 4 videobits r8 ;byte 5 videobits r9 ;byte 6 videobits r10 ;byte 7 videobits r11 ;byte 8 videobits r12 ;byte 9 videobits r13 ;byte 10 videobits r14 ;byte 11 videobits r15 ;byte 12 videobits r16 ;byte 13 videobits r17 ;byte 14 videobits r18 ;byte 15 videobits r19 ;byte 16 clt ;clear video after the last pixel on the line IN R30,0x12 BLD R30,6 OUT 0x12,R30 pop r19 pop r18 pop r17 pop r16 pop r15 pop r14 #endasm end end #pragma warn+ //================================== //plot one point //at x,y with color 1=white 0=black 2=invert #pragma warn- void video_pt(char x, char y, char c) begin #asm ; i=(x>>3) + ((int)y<<4) ; the byte with the pixel in it push r16 ldd r30,y+2 ;get x lsr r30 lsr r30 lsr r30 ;divide x by 8 ldd r12,y+1 ;get y lsl r12 ;mult y by 16 clr r13 lsl r12 rol r13 lsl r12 rol r13 lsl r12 rol r13 add r12, r30 ;add in x/8 ;v2 = screen[i]; r5 ;v3 = pos[x & 7]; r6 ;v4 = c r7 ldi r30,low(_screen) ldi r31,high(_screen) add r30, r12 adc r31, r13 ld r5,Z ;get screen byte ldd r26,y+2 ;get x ldi r27,0 andi r26,0x07 ;form x & 7 ldi r30,low(_pos*2) ldi r31,high(_pos*2) add r30,r26 adc r31,r27 lpm r6,Z ld r16,y ;get c ;if (v4==1) screen[i] = v2 | v3 ; ;if (v4==0) screen[i] = v2 & ~v3; ;if (v4==2) screen[i] = v2 ^ v3 ; cpi r16,1 brne tst0 or r5,r6 tst0: cpi r16,0 brne tst2 com r6 and r5,r6 tst2: cpi r16,2 brne writescrn eor r5,r6 writescrn: ldi r30,low(_screen) ldi r31,high(_screen) add r30, r12 adc r31, r13 st Z, r5 ;write the byte back to the screen pop r16 #endasm end #pragma warn+ //================================== // put a big character on the screen // c is index into bitmap void video_putchar(char x, char y, char c) begin v7 = x; for (v6=0;v6<7;v6++) begin v1 = bitmap[c][v6]; v8 = y+v6; video_pt(v7, v8, (v1 & 0x80)==0x80); video_pt(v7+1, v8, (v1 & 0x40)==0x40); video_pt(v7+2, v8, (v1 & 0x20)==0x20); video_pt(v7+3, v8, (v1 & 0x10)==0x10); video_pt(v7+4, v8, (v1 & 0x08)==0x08); end end //================================== // put a string of big characters on the screen void video_puts(char x, char y, char *str) begin char i ; for (i=0; str[i]!=0; i++) begin if (str[i]>=0x30 && str[i]<=0x3a) video_putchar(x,y,str[i]-0x30); else video_putchar(x,y,str[i]-0x40+9); x = x+6; end end //================================== //plot a line //at x1,y1 to x2,y2 with color 1=white 0=black 2=invert //NOTE: this function requires signed chars //Code is from David Rodgers, //"Procedural Elements of Computer Graphics",1985 void video_line(char x1, char y1, char x2, char y2, char c) begin int e; signed char dx,dy,j, temp; signed char s1,s2, xchange; signed char x,y; x = x1; y = y1; dx = cabs(x2-x1); dy = cabs(y2-y1); s1 = csign(x2-x1); s2 = csign(y2-y1); xchange = 0; if (dy>dx) begin temp = dx; dx = dy; dy = temp; xchange = 1; end e = ((int)dy<<1) - dx; for (j=0; j<=dx; j++) begin video_pt(x,y,c) ; if (e>=0) begin if (xchange==1) x = x + s1; else y = y + s2; e = e - ((int)dx<<1); end if (xchange==1) y = y + s2; else x = x + s1; e = e + ((int)dy<<1); end end //================================== // set up the ports and timers void main(void) begin //init timer 1 to generate sync OCR1A = lineTime; //One NTSC line TCCR1B = 9; //full speed; clear-on-match TCCR1A = 0x00; //turn off pwm and oc lines TIMSK = 0x10; //enable interrupt T1 cmp //init ports DDRD = 0xf0; //video out and switches //D.5 is sync:1000 ohm + diode to 75 ohm resistor //D.6 is video:330 ohm + diode to 75 ohm resistor //init timer 0 to 1/uSec TCCR0 = 2; //initialize synch constants LineCount = 1; syncON = 0b00000000; syncOFF = 0b00100000; //init software timer t=0; time=0; //enable sleep mode MCUCR = 0b10000000; #asm ("sei"); //initialize game setup numPlayers=1; numMonsters=0; numKeys=1; //The following loop executes once/video line during lines //1-230, then does all of the frame-end processing while(1) begin //stall here until next line starts //sleep enable; mode=idle //use sleep to make entry into sync ISR uniform time #asm ("sleep"); //The following code executes during the vertical blanking //Code here can be as long as //a total of 60 lines x 63.5 uSec/line x 8 cycles/uSec if (LineCount==231) begin switch(state){ case title1: *strcpyf(string4, title01); video_puts(34, 2, string4); *strcpyf(string6, title02); video_puts(58, 10, string6); state = title2; break; case title2: video_putchar(40, 26, 10); *strcpyf(string6, title03); video_puts(52, 26, string6); *strcpyf(string3, title04); video_puts(31, 38, string3); state = title3; break; case title3: *strcpyf(string7, title05); video_puts(55, 38, string7); *strcpyf(string7, title06); video_puts(34, 50, string7); state = title4; break; case title4: *strcpyf(string3, title07); video_puts(76, 50, string3); *strcpyf(string5, title08); video_puts(43, 92, string5); video_putchar(79, 92, 12); state = title5; break; case title5: if (m == 4){ if (man == 0) {video_putchar(man, 70, 36); man = man + 3;} else {video_putchar(man-3, 70, 38); if (man == 126) {man = 0;} else {video_putchar(man, 70, 36); man = man + 3;} } if (man < 15 && mon < 15) {m = 0;} } if (m == 7) { if (man > 15 | mon > 15) { if (mon == 0) {video_putchar(mon, 70, 37); mon = mon + 3;} else {video_putchar(mon-3, 70, 38); if (mon == 126) {mon = 0;} else {video_putchar(mon, 70, 37); mon = mon + 3;} } } m = 0; } m++; if ((PINB | 0x0f) == 0xef) {state = clear; afterclear = select1; m = 0;} //increment random seed until user exits intro screen p++; break; case clear: for (scrIndex = 0; scrIndex < 1600; scrIndex++) screen[scrIndex] = 0; scrIndex = 0; state = afterclear; break; case select1: *strcpyf(string7, select01); *strcpyf(string4, select02); video_puts(32, 10, string7); video_puts(74, 10, string4); state = select2; break; case select2: *strcpyf(string6, select03); video_puts(32, 30, string6); *strcpyf(string4, select04); video_puts(74, 30, string4); state = select3; break; case select3: *strcpyf(string4, best01); video_puts(35, 58, string4); *strcpyf(string5, win05); video_puts(65, 58, string5); state = select4; break; case select4: //Display best score video_putchar(54, 68, ((bestscore/1000)%10)); video_putchar(60, 68, ((bestscore/100)%10)); video_putchar(66, 68, ((bestscore/10)%10)); video_putchar(72, 68, (bestscore%10)); state = select5; cursor = 10; progression = 1; score = 0; break; case select5: video_putchar(20, cursor, 36); *strcpyf(string5, title08); video_puts(41, 92, string5); video_putchar(77, 92, 11); if ((PINB | 0xf0) == 0xf7 && progression != 1) {video_putchar(20, 30, 38); cursor = 10; progression = 1;} else if ((PINB | 0xf0) == 0xfd && progression == 1) {video_putchar(20, 10, 38); cursor = 30; progression = 0;} if ((PINB | 0x0f) == 0xdf) {state = clear; if (progression == 1){afterclear = progGame;} else {afterclear = select6;} } break; case select6: *strcpyf(string7, single01); video_puts(26, 10, string7); *strcpyf(string7, single02); video_puts(26, 30, string7); state = select7; break; case select7: video_putchar(68, 30, 28); *strcpyf(string4, single03); video_puts(26, 50, string4); *strcpyf(string5, title08); video_puts(36, 92, string5); video_putchar(72, 92, 12); state = select8; cursor = 10; numPlayers = 1; numKeys = 1; numMonsters = 0; //reset time and lives for single game n=0; sec1=0; sec2=0; min1=0; min2=0; lives[0]=3; lastInput = 0xff; break; case select8: video_putchar(14, cursor, 36); video_putchar(86, 10, numPlayers); video_putchar(86, 30, numMonsters); video_putchar(86, 50, numKeys); //get user 1 input if((PINB)!=0xff){ userInput0=PINB; } if (m == 10){ //protect against double-move if(userInput0==lastInput){userInput0=0xff;} if ((userInput0 | 0xf0) == 0xf7 && cursor != 10) { video_putchar(14, 30, 38); video_putchar(14, 50, 38); video_putchar(14, 70, 38); cursor = cursor - 20; } else if ((userInput0 | 0xf0) == 0xfd && cursor != 50){ video_putchar(14, 10, 38); video_putchar(14, 30, 38); video_putchar(14,50, 38); cursor = cursor + 20; } if ((userInput0 | 0xf0) == 0xfb && cursor == 10 && numPlayers != 2) { numPlayers = 2; } if ((userInput0 | 0xf0) == 0xfe && cursor == 10 && numPlayers != 1) { numPlayers = 1; } if ((userInput0 | 0xf0) == 0xfb && cursor == 30 && numMonsters != 3) { numMonsters = numMonsters + 1; } if ((userInput0 | 0xf0) == 0xfe && cursor == 30 && numMonsters != 0) { numMonsters = numMonsters - 1; } if ((userInput0 | 0xf0) == 0xfb && cursor == 50 && numKeys != 4) { numKeys = numKeys + 1; } if ((userInput0 | 0xf0) == 0xfe && cursor == 50 && numKeys != 1) { numKeys = numKeys - 1; } if (numPlayers == 1) { lives[1]=0; } else lives[1] = 3; m = 0; lastInput = userInput0; userInput0 = 0xff; } m++; //when user presses button, clear screen and start building maze if ((PINB | 0x0f) == 0xef) {state = clear; afterclear = setup; } break; case progGame: numPlayers=1; if(progression==1){ lives[0]=3; min2=0; min1=0; sec2=0; sec1=0; n=0; numKeys=1; numMonsters=0; } else if(progression==2){ numKeys=1; numMonsters=1; } else if(progression==3){ numKeys=2; numMonsters=1; } else if(progression==4){ numKeys=2; numMonsters=2; } else if(progression==5){ numKeys=3; numMonsters=1; } else if(progression==6){ numKeys=3; numMonsters=2; } else if(progression==7){ numKeys=3; numMonsters=3; } else if(progression==8){ numKeys=4; numMonsters=1; } else if(progression==9){ numKeys=4; numMonsters=2; } else if(progression==10){ numKeys=4; numMonsters=3; } else{ state=win1; } //go on to setup if(progression<11){state=setup;} break; case setup: //put each cell of maze in its own set, and put up all walls setnum=0; for(k=0;k99){ m=0; //clear "maze generation" bar when it reaches 100 pixels video_line(1,93,100,93,0); } break; case create1: //Pick random cell and random side of cell for wall to knock down srand(p); p++; ic=(char)(rand()%height); jc=(char)(rand()%width); s=(char)(rand() & 0x03); //Check to see if s is along edge of maze - if so, change accordingly if((ic==0 && s==0) || (jc==width-1 && s==1)) s=s+2; else if((ic==height-1 && s==2) || (jc==0 && s==3)) s=s-2; //find adjacent element if(s==0){ia=ic-1; ja=jc;} else if(s==1){ia=ic; ja=jc+1;} else if(s==2){ia=ic+1; ja=jc;} else{ia=ic; ja=jc-1;} //Check if selected elements are already connected (ie. are in same set) if(set[ia][ja] != set[ic][jc]){ //Combine sets lowset=min(set[ia][ja], set[ic][jc]); highset=max(set[ia][ja], set[ic][jc]); for(k=0; k0){ progression++; //move to next stage in progression afterclear=progGame; //keep going with progression } else{afterclear = win1;} } //if first of two players has just escaped... if(numPlayers==2){ //if player 1 escaped... if(escaped==1){ //erase player 1's character video_putchar(mleft+(man0j<<3)+2,mtop+(man0k<<3)+1,38); //player 2 becomes player 1 man0k=man1k; man0j=man1j; lives[0]=lives[1]; lastInput0=lastInput1; userSwitch=1; //switch so controller 2 still controls remaining player } else{ //if player 2 escaped, just erase him video_putchar(mleft+(man1j<<3)+2,mtop+(man1k<<3)+1,38); } numPlayers=1; //only one player left state=monster; //move on to monsters } //reset escaped variable escaped=0; break; case monster: //get user 1 input if((PINB | 0xf0)!=0xff){userInput0=PINB;} //get user 2 input if((PINC | 0xf0)!=0xff){userInput1=PINC;} //if player 2 is last person in maze, he becomes "user 1" if(userSwitch==1){userInput0=userInput1;} //move monster if it is being used if(monsterNum < numMonsters){ //load variables for current monster if(monsterNum==0){ monsterk=monster0k; monsterj=monster0j; monsterBack=monster0Back; } else if(monsterNum==1){ monsterk=monster1k; monsterj=monster1j; monsterBack=monster1Back; } else{ monsterk=monster2k; monsterj=monster2j; monsterBack=monster2Back; } //if monster is on man before moving, man is eaten if(man0k==monsterk && man0j==monsterj){eaten=1;} else if(numPlayers>1 && man1k==monsterk && man1j==monsterj){eaten=2;} //Move Monster //pick random direction srand(p); p++; s=(char)(rand() & 0x03); //decode direction if(s>2){monsterMove=0x08;} else if(s>1){monsterMove=0x04;} else if(s>0){monsterMove=0x02;} else{monsterMove=0x01;} //don't move backward unless it's the only option if((monsterMove==monsterBack) && (walls[monsterk][monsterj] != monsterMove)){monsterMove=0;} //don't walk into a wall if((walls[monsterk][monsterj] & monsterMove) != monsterMove){monsterMove=0;} else{ //find "backward" direction so monster can try to avoid doubling back if(monsterMove > 2){monsterBack=monsterMove>>2;} else if(monsterMove > 0){monsterBack=monsterMove<<2;} } //update monster position and erase old if(monsterMove==0x01){ video_putchar(mleft+(monsterj<<3)+2,mtop+(monsterk<<3)+1,38); //erase old position monsterk--; //move up } else if(monsterMove==0x02){ video_putchar(mleft+(monsterj<<3)+2,mtop+(monsterk<<3)+1,38); //erase old position monsterj++; //move right } else if(monsterMove==0x04){ video_putchar(mleft+(monsterj<<3)+2,mtop+(monsterk<<3)+1,38); //erase old position monsterk++; //move down } else if(monsterMove==0x08){ video_putchar(mleft+(monsterj<<3)+2,mtop+(monsterk<<3)+1,38); //erase old position monsterj--; //move left } //draw monster in new position video_putchar(mleft+(monsterj<<3)+2,mtop+(monsterk<<3)+1,37); //if monster is on man after moving, man is eaten if(man0k==monsterk && man0j==monsterj){eaten=1;} else if(numPlayers>1 && man1k==monsterk && man1j==monsterj){eaten=2;} //save variables for current monster if(monsterNum==0){ monster0k=monsterk; monster0j=monsterj; monster0Back=monsterBack; } else if(monsterNum==1){ monster1k=monsterk; monster1j=monsterj; monster1Back=monsterBack; } else{ monster2k=monsterk; monster2j=monsterj; monster2Back=monsterBack; } //redraw keys in case monster erased one for(ic=0;ic bestscore)){ bestscore=score; } video_putchar(84, 75, ((score/1000)%10)); video_putchar(90, 75, ((score/100)%10)); video_putchar(96, 75, ((score/10)%10)); video_putchar(102, 75, (score%10)); *strcpyf(string5, title08); video_puts(41, 92, string5); video_putchar(77, 92, 11); //wait for player to press button if ((PINB | 0x0f) == 0xdf){ state = clear; afterclear = title1; } break; //Win Cases: display winning message case win1: *strcpyf(string3, win01); video_puts(30, 26, string3); *strcpyf(string7, win02); video_puts(54, 26, string7); state = win2; break; case win2: *strcpyf(string3, win03); video_puts(39, 36, string3); *strcpyf(string4, title01); video_puts(63, 36, string4); state = win3; break; case win3: *strcpyf(string7, win06); video_puts(18, 5, string7); *strcpyf(string7, win07); video_puts(60, 5, string7); state = win4; break; case win4: video_putchar(102, 5, 28); *strcpyf(string4, win04); video_puts(32, 56, string4); *strcpyf(string5, win05); video_puts(62, 56, string5); state = win5; break; case win5: score = progression; score = score<<1; score = score + lives[0] + lives[1]; if (progression == 0) { score = score + keysFound + numMonsters; } score = score<<4; if (progression == 0){ if (min2 == 0 && min1 < 2) { score = score + 25 - (min1<<4) - sec2; } } if (progression != 0){ if (min2 == 0 && min1 < 6) score = score + 102 - (min1<<4) - sec2; } score = score<<4; if(progression!=0 && (score > bestscore)){ bestscore=score; } video_putchar(50, 68, ((score/1000)%10)); video_putchar(56, 68, ((score/100)%10)); video_putchar(62, 68, ((score/10)%10)); video_putchar(68, 68, (score%10)); *strcpyf(string5, title08); video_puts(40, 92, string5); video_putchar(76, 92, 11); if ((PINB | 0x0f) == 0xdf) {state = clear; afterclear=title1; } break; }//end switch(state) end //line 231 end //while end //main