// C Header File // Created 5/18/2003; 1:19:59 PM static void DrawVehicle(void); static inline void PressButtonAndOpenDoor(short idx); static inline short tileIsOccupied(short x, short y); static inline void HandleDoors(void); static short GetButtonIdx(short xtile, short ytile); static inline void HandlePressedButtons(void); static inline void HandleShotButtons(short tile_x,short tile_y); static inline void AdjustLevelSettings(void); static inline void HandleEvents(void); __attribute__((noinline)) void handleLightSkullsTriggerEnemies(void); #ifndef __LEVEL_EXEC_H__ #define __LEVEL_EXEC_H__ #include "gfx.h" #include "sys.h" #include "sprites_init.h" static void DrawVehicle(void) { register GameGlobals *ggg asm("a4") = gg; short x = 96/2-48/2; short y = 96-24; short bytewidth = 48>>3; short height = 24; memset(ggg->HUDlight,0x00,576*sizeof(short)); memset(ggg->HUDdark,0x00,576*sizeof(short)); memset(ggg->HUDmask,0xFF,576*sizeof(short)); SpriteX8_AND_96x96(x,y,height,vehicleAmask,bytewidth,ggg->HUDmask); SpriteX8_OR_96x96(x,y,height,vehicleAmask,bytewidth,ggg->HUDmask); SpriteX8_AND_96x96(x,y,height,vehicleAlight,bytewidth,ggg->HUDlight); SpriteX8_OR_96x96(x,y,height,vehicleAlight,bytewidth,ggg->HUDlight); SpriteX8_AND_96x96(x,y,height,vehicleAdark,bytewidth,ggg->HUDdark); SpriteX8_OR_96x96(x,y,height,vehicleAdark,bytewidth,ggg->HUDdark); } static inline void PressButtonAndOpenDoor(short idx) { register GameGlobals *ggg asm("a4") = gg; short location = ggg->button_data[idx].y*fc->map_width + ggg->button_data[idx].x; //Update ggg->button tile ggg->button[idx].status = !ggg->button[idx].status; short pressed = ggg->button[idx].status==BUTTON_PRESSED; fc->map_data[location] = pressed?ggg->button[idx].aftertile:ggg->button[idx].beforetile; if(!ggg->button_data[idx].doorx) //No linked door { if(ggg->levelstyle == level_fadeIntoDistance) //Light switch { ggg->lights = pressed?LIGHTS_ON:LIGHTS_OFF; ggg->ceilmode = pressed?ggg->ceilmode2:BLACK; ggg->floormode = pressed?ggg->floormode2:BLACK; SetUpCeilingAndFloor(); if(ggg->lights==LIGHTS_ON) { short a; SpriteStruct *extra = ggg->sprites_extra; FATSPRITE *spr = ggg->sprites; for(a=0;asprite_count;a++) { spr->drawmode = extra->drawmode; ++spr; ++extra; } } } } if(KeyCheck(KEY_STRAFE)) { //Show updated ggg->button FAT_Render(fc); //Wait about 2/3 a second { unsigned long count = int5_counter; while(int5_counter < count+12) continue; } { short player_x = fc->cam_xpos; short player_y = fc->cam_ypos; short player_orientation = fc->cam_orientation; short mappos; FATDOOR* door = FAT_GetDoor(ggg->button_data[idx].doorx,ggg->button_data[idx].doory); if(!door) return; //Clear HUD memset(ggg->HUDlight,0x00,576*sizeof(short)); memset(ggg->HUDdark,0x00,576*sizeof(short)); memset(ggg->HUDmask,0xFF,576*sizeof(short)); //Move camera to where door is fc->cam_xpos = (ggg->button_data[idx].doorx<<6) + 32; fc->cam_ypos = (ggg->button_data[idx].doory<<6) + 32; mappos = (fc->cam_ypos>>6)*fc->map_width+(fc->cam_xpos>>6); if(door->type==DOOR_HORIZONTAL) { fc->cam_ypos -= 64; if(/*fc->map_data[mappos]==traversedTile||*/ fc->map_data[mappos]==OPEN_DOOR_TILE) { fc->cam_orientation = ANGLE_SOUTH; fc->cam_ypos -= 32; } else { fc->cam_orientation = ANGLE_NORTH; fc->cam_ypos += 128+31; } } else { fc->cam_xpos += 64; if(/*fc->map_data[mappos]==traversedTile||*/ fc->map_data[mappos]==OPEN_DOOR_TILE) { fc->cam_orientation = ANGLE_WEST; fc->cam_xpos += 31; } else { fc->cam_orientation = ANGLE_EAST; fc->cam_xpos -= 128+32; } } /* //Keep updating screen while door opens while(door->state != DOOR_OPEN) { UpdateDoor(fc,door); FAT_Render(fc); }*/ FAT_Render(fc); //Wait about a second { unsigned long count = int5_counter; while(int5_counter < count+19) continue; } //Go back to normal view fc->cam_xpos = player_x; fc->cam_ypos = player_y; fc->cam_orientation = player_orientation; SetupCrosshair(); if(ggg->levelstyle==level_vehicle) DrawVehicle(); else DrawWeapon(ggg->cur_weapon,W_OFF); } } if(ggg->button_data[idx].doorx) textEnqueue(stringIdx(gamestrings,eDoorToggled)); } static inline short tileIsOccupied(short x, short y) { register GameGlobals *ggg asm("a4") = gg; short a; short location = y*fc->map_width+x; char spot = fc->map_data[location]; fc->map_data[location]=1; if(!ValidMove(fc->cam_xpos,fc->cam_ypos)) { fc->map_data[location] = spot; //printf_xy(100,0,"P "); return 1; } FATSPRITE *spr = ggg->sprites; for(a=0;asprite_count;a++,spr++) { short a=spr->xpos>>6,b=spr->ypos>>6; if(a==x && b==y) { fc->map_data[location] = spot; return 1; } if(abs(a-x)<3 && abs(b-y)<3) { if(!ValidMove(spr->xpos,spr->ypos)) { fc->map_data[location] = spot; return 1; } } } fc->map_data[location] = spot; //printf_xy(100,0,"Nothing "); return 0; } static inline void HandleDoors(void) { register GameGlobals *ggg asm("a4") = gg; short a; register FATDOOR *curdoor = FAT_GetDoorsArray(); for(a=0;adoorcount;a++) { if(curdoor->state==DOOR_OPEN) { if(ggg->doortimers[a]!=MAX_DOOR_WAIT) ggg->doortimers[a]++; //if(ggg->doortimers[a]==MAX_DOOR_WAIT) else { if(!tileIsOccupied(curdoor->xtile,curdoor->ytile)) { ggg->doortimers[a] = 0; curdoor->state = DOOR_CLOSING; } } } else { if (curdoor->state == DOOR_OPENING) { curdoor->position+=4; if (curdoor->position >= 64) { curdoor->position = 64; curdoor->state = DOOR_OPEN; *(fc->map_data + fc->map_width * curdoor->ytile + curdoor->xtile) = OPEN_DOOR_TILE; } } else if (curdoor->state == DOOR_CLOSING) { curdoor->position-=4; if (curdoor->position <= 0) { curdoor->position = 0; curdoor->state = DOOR_CLOSED; } *(fc->map_data + fc->map_width * curdoor->ytile + curdoor->xtile) = CLOSED_DOOR_TILE; } } ++curdoor; } } /*************************************************************** * use a search to find a button's index based on coords ****************************************************************/ static short GetButtonIdx(short xtile, short ytile) { register GameGlobals *ggg asm("a4") = gg; unsigned short low, high; if(!ggg->buttoncount) return -1; if(ggg->button_data[ggg->cached_button].x==xtile && ggg->button_data[ggg->cached_button].y==ytile) return ggg->cached_button; low = 0; high = ggg->buttoncount-1; while (low <= high) { if (ggg->button_data[low].y==ytile) { if (ggg->button_data[low].x==xtile) { ggg->cached_button = low; return low; }} low++; } return -1; } static inline void HandlePressedButtons(void) { register GameGlobals *ggg asm("a4") = gg; //Player is pressing the ChgButton key if(ggg->chgbutton_flag && !ggg->oldChgbutton_flag) { short tile_x = ((FAT_Cos16384(fc->cam_orientation) >> 8)+fc->cam_xpos)>>6; short tile_y = ((FAT_Sin16384(fc->cam_orientation) >> 8)+fc->cam_ypos)>>6; short idx = GetButtonIdx(tile_x,tile_y); if(idx != -1)//a button is near { if(!ggg->button[idx].shootonly || ggg->button[idx].status==BUTTON_UNPRESSED) { if(ggg->button[idx].isKeycard) { if(ggg->playerHasKeycard) PressButtonAndOpenDoor(idx); else textEnqueue(stringIdx(gamestrings,eNeedKeycard)); } else if(ggg->button[idx].shootonly!=SHOOT_ONLY) PressButtonAndOpenDoor(idx); } } else // no button is near {//maybe a door is FATDOOR *door = FAT_GetDoor(tile_x,tile_y); if(door) { short i = (short)((long)door->clientdata); if(i==-1) { if(door->state==DOOR_CLOSED) door->state = DOOR_OPENING; } else if(ggg->button[i].status == BUTTON_PRESSED) { if(door->state==DOOR_CLOSED) door->state = DOOR_OPENING; } else if(door!=ggg->olddoor) textEnqueue(stringIdx(gamestrings,eLocked)); ggg->olddoor = door; } } } } static inline void HandleShotButtons(short tile_x,short tile_y) { register GameGlobals *ggg asm("a4") = gg; short idx = GetButtonIdx(tile_x,tile_y); if(idx != -1) { if(ggg->button[idx].status==BUTTON_UNPRESSED || ggg->button[idx].shootonly!=SHOOT_ONLY) if(ggg->button[idx].shootonly!=PRESS_ONLY) PressButtonAndOpenDoor(idx); } } __attribute__((noinline)) void handleLightSkullsTriggerEnemies(void) { register GameGlobals *ggg asm("a4") = gg; short a; for(a=0;amap_width*fc->map_height;a++) { if(fc->map_data[a]==51) fc->map_data[a] = 52;//Light Skulls } //Trigger Enemies char Xvalue; for(a=0;amap_width*fc->map_height;a++) { if(ggg->sprite_count == MAX_SPRITES) return; //Can't handle any more Xvalue = fc->map_data[a]; if(Xvalue <= ((char)-0x60) && Xvalue >= ((char)-0x68)) { InitSprite(Xvalue+0x40,(a%fc->map_width)*64+32, (a/fc->map_width)*64+32,ggg->sprite_count); ggg->sprite_count++; } } } __attribute__((noinline)) void handleElevator(void) { register GameGlobals *ggg asm("a4") = gg; short a,cur=ggg->current_level-29; while(fc->cam_orientation/ANGLE_090 != ANGLE_SOUTH/ANGLE_090) //Face South //for(a=0;a<(ANGLE_180)/TURN_SIZE;a++) { PlayerTurn(RIGHT,TURN_SIZE); FAT_Render(fc); } short tile_x = ((FAT_Cos16384(fc->cam_orientation) >> 8)+fc->cam_xpos)>>6; short tile_y = ((FAT_Sin16384(fc->cam_orientation) >> 8)+fc->cam_ypos)>>6; FATDOOR *door = FAT_GetDoor(tile_x,tile_y); if(!door) { tile_x = ((FAT_Cos16384(fc->cam_orientation) >> 7)+fc->cam_xpos)>>6; tile_y = ((FAT_Sin16384(fc->cam_orientation) >> 7)+fc->cam_ypos)>>6; door = FAT_GetDoor(tile_x,tile_y); } if(door) { while(door->state != DOOR_CLOSED) { HandleDoors(); FAT_Render(fc); } } DrawGrayRect(0+display_offsetx,2+display_offsety,95+display_offsetx, 97+display_offsety,COLOR_DARKGRAY,RECT_FILLED); FontSetSys(F_6x8); for(a=1;a<9;a++) //The end complex is 8 floors, { ggg->textbuf[0] = '0' + a; ggg->textbuf[1] = 0; DrawGrayStr(a*8+display_offsetx,46+display_offsety,ggg->textbuf,A_REVERSE); } DrawGrayStr(a*8+display_offsetx,46+display_offsety,"R",A_REVERSE); //(plus the Roof) short x = cur*8+display_offsetx - 2, y = 46+display_offsety - 2; InvertGrayRect(x,y,x+9,y+12); waitMsec(1000); InvertGrayRect(x,y,x+9,y+12); x+=8; InvertGrayRect(x,y,x+9,y+12); waitMsec(800); } static inline void DisplayMission(void) { register GameGlobals *ggg asm("a4") = gg; switch(ggg->levelstyle) { case level_findWorkingVehicle: textEnqueue(stringIdx(gamestrings,eFindWorkingVehicle)); break; case level_vehicle: textEnqueue(stringIdx(gamestrings,eVehicle)); break; case level_killAllEnemiesToExit: textEnqueue(stringIdx(gamestrings,eKillAllEnemiesToExit)); break; case level_killGuardianToContinue: textEnqueue(stringIdx(gamestrings,eKillGuardianToContinue)); break; case level_destroyAllMonitors: textEnqueue(stringIdx(gamestrings,eDestroyAllMonitors)); break; case level_destroyAllPanels: textEnqueue(stringIdx(gamestrings,eDestroyAllPanels)); break; case level_destroyAllGenerators: textEnqueue(stringIdx(gamestrings,eDestroyAllGenerators)); break; } } static inline void AdjustLevelSettings(void) { register GameGlobals *ggg asm("a4") = gg; switch(ggg->levelstyle) { case level_vehicle: DrawVehicle(); ggg->vehicle_speed = 0; break; case level_killAllEnemiesToExit: ggg->canExit = FALSE; break; case level_killGuardianToContinue: ggg->canExit = FALSE; break; case level_destroyAllMonitors: ggg->canExit = FALSE; break; case level_destroyAllPanels: ggg->canExit = FALSE; break; case level_destroyAllGenerators: ggg->canExit = FALSE; break; case level_fadeIntoDistance: ggg->lights = LIGHTS_OFF; ggg->ceilmode = BLACK; ggg->floormode = BLACK; SetUpCeilingAndFloor(); break; } DisplayMission(); } static inline void HandleEvents(void) { register GameGlobals *ggg asm("a4") = gg; short x = fc->cam_xpos>>6; short y = fc->cam_ypos>>6; char *mapcode = fc->map_data + y*fc->map_width + x; short *camdir = &fc->cam_orientation; short HUDsize = 576 * sizeof (short); //short centered; short a; char atSpawnPt; //centered = (fc->cam_xpos & ~63) >15 && (fc->cam_xpos & ~63)<48 && (fc->cam_ypos & ~63) >15 && (fc->cam_ypos & ~63)<48; if(*mapcode!=ggg->old_tile) //The player just moved to the tile { switch(*mapcode) { case exitPoint: if(ggg->old_tile!=traversedTile) { if(ggg->canExit) { ggg->quitting = NEW_LEVEL; } else { textEnqueue(stringIdx(gamestrings,eObjectiveNotComplete)); DisplayMission(); } } break; case faceNorth: *camdir = ANGLE_NORTH; break; case faceNorthEast: *camdir = ANGLE_NORTH+ANGLE_045; break; case faceEast: *camdir = ANGLE_EAST; break; case faceSouthEast: *camdir = ANGLE_SOUTH-ANGLE_045; break; case faceSouth: *camdir = ANGLE_SOUTH; break; case faceSouthWest: *camdir = ANGLE_SOUTH+ANGLE_045; break; case faceWest: *camdir = ANGLE_WEST; break; case faceNorthWest: *camdir = ANGLE_NORTH-ANGLE_045; break; case moveNorth: ggg->cur_orientation = ANGLE_NORTH; break; case moveNorthEast: ggg->cur_orientation = ANGLE_NORTH+ANGLE_045; break; case moveEast: ggg->cur_orientation = ANGLE_EAST; break; case moveSouthEast: ggg->cur_orientation = ANGLE_SOUTH-ANGLE_045; break; case moveSouth: ggg->cur_orientation = ANGLE_SOUTH; break; case moveSouthWest: ggg->cur_orientation = ANGLE_SOUTH+ANGLE_045; break; case moveWest: ggg->cur_orientation = ANGLE_WEST; break; case moveNorthWest: ggg->cur_orientation = ANGLE_NORTH-ANGLE_045; break; case automoveOn: ggg->automove = TRUE; break; case automoveOff: ggg->automove = FALSE; break; case turnAndExit: { ggg->automove = FALSE; for(a=0;a<(ANGLE_360)/TURN_SIZE;a++) { PlayerTurn(RIGHT,(TURN_SIZE<<1)); FAT_Render(fc); } BlackGrayScreen2B(ggg->BGlight,ggg->BGdark); dissolveGSFromTo(ggg->BGlight,ggg->BGdark,ggg->plane1,ggg->plane2); memset(ggg->HUDlight,0xFF,HUDsize); memset(ggg->HUDdark,0xFF,HUDsize); memset(ggg->HUDmask,0xFF,HUDsize); ggg->quitting = NEW_LEVEL; } break; case clearWall47: for(a=0;amap_width*fc->map_height;a++) { if(fc->map_data[a]==47) fc->map_data[a] = 0; } break; /*case lightsToggle: a = ggg->lights; ggg->lights = !a; ggg->ceilmode = a?BLACK:ggg->ceilmode2; ggg->floormode = a?BLACK:ggg->floormode2; SetUpCeilingAndFloor(); if(ggg->lights==LIGHTS_ON) { short a; SpriteStruct *extra = ggg->sprites_extra; FATSPRITE *spr = ggg->sprites; for(a=0;asprite_count;a++) { spr->drawmode = extra->drawmode; ++spr; ++extra; } } break;*/ case lightsOn: ggg->lights = LIGHTS_ON; ggg->ceilmode = ggg->ceilmode2; ggg->floormode = ggg->floormode2; SetUpCeilingAndFloor(); short a; SpriteStruct *extra = ggg->sprites_extra; FATSPRITE *spr = ggg->sprites; for(a=0;asprite_count;a++) { spr->drawmode = extra->drawmode; ++spr; ++extra; } break; case lightsOff: a = ggg->lights; ggg->lights = LIGHTS_OFF; ggg->ceilmode = BLACK; ggg->floormode = BLACK; SetUpCeilingAndFloor(); break; /*case lightSkullsTriggerEnemies: handleLightSkullsTriggerEnemies(); *mapcode = 0; break;*/ case coalRealization: textEnqueue(stringIdx(gamestrings,eCoalRealization)); *mapcode = 0; break; } } if(ggg->old_tile==automoveToggle && *mapcode!=automoveToggle) { //Gosh, this is a pain short dir = fc->cam_orientation; if(_keytest(RR_UP)) dir += ANGLE_000; else if(_keytest(RR_DOWN)) dir += ANGLE_180; else if(_keytest(RR_RIGHT)/* && ggg->strafe_flag*/) dir += ANGLE_090; else if(_keytest(RR_LEFT)/* && ggg->strafe_flag*/) dir += ANGLE_270; ggg->automove = !(ggg->automove); ggg->cur_orientation = FAT_ClampAngle(dir); } if(*mapcode == automoveWhenDoorOpens) { //printf_xy(120,90,"YES"); short tile_x = ((FAT_Cos16384(fc->cam_orientation) >> 8)+fc->cam_xpos)>>6; short tile_y = ((FAT_Sin16384(fc->cam_orientation) >> 8)+fc->cam_ypos)>>6; FATDOOR *door = FAT_GetDoor(tile_x,tile_y); if(door) { if(door->state==DOOR_OPEN) { ggg->automove = TRUE; ggg->cur_orientation = fc->cam_orientation; } } } //else printf_xy(120,90,"NO "); atSpawnPt = *mapcode<=spawnEast && *mapcode >= spawnNorthEast; if(atSpawnPt) { if(ggg->current_level>STARTLEVEL) { if(*mapcode!=ggg->old_tile && lev && ggg->old_tile!=traversedTile) //The player just moved to the spawn pt { char levz[20]; if(lev==38) strcpy(levz,"ROOF"); else if(lev>29 && lev<38) sprintf(levz,"FLOOR %i",lev-29); else sprintf(levz,"LEVEL %02i",lev); textEnqueueF("%s %s.",stringIdx(gamestrings,eButtonToGoBack),levz); } else if(KeyCheck(KEY_PRESSBUTTON) && lev && ggg->old_tile!=traversedTile) { if(lev) {ggg->quitting=OLD_LEVEL;ggg->current_level=lev+1;} } } } /* if(*mapcode!=traversedTile && *mapcode!=OPEN_DOOR_TILE && !atSpawnPt && *mapcode!=exitPoint) *mapcode = traversedTile;*/ switch(ggg->levelstyle) { case level_killAllEnemiesToExit: { short enemies=FALSE; SpriteStruct *extra = ggg->sprites_extra; for(a=0;asprite_count;a++) { if(extra->desire != ENEMY_NONE) { enemies = TRUE; break; }//end if ++extra; }//end for if(!enemies) { ggg->canExit = TRUE; ggg->levelstyle = level_normal; //Don't check anymore } } break; case level_killGuardianToContinue: { short enemies=FALSE; SpriteStruct *extra = ggg->sprites_extra; for(a=0;asprite_count;a++) { if(extra->type == fatty) { enemies = TRUE; break; }//end if ++extra; }//end for if(!enemies) { ggg->canExit = TRUE; ggg->levelstyle = level_normal; //Don't check anymore } } break; case level_destroyAllPanels: if(!ggg->panel_count) { ggg->canExit = TRUE; ggg->levelstyle = level_normal; //Don't check anymore } break; case level_destroyAllMonitors: if(!ggg->monitor_count) { ggg->canExit = TRUE; ggg->levelstyle = level_normal; //Don't check anymore } break; case level_destroyAllGenerators: { short generators=FALSE; SpriteStruct *extra = ggg->sprites_extra; for(a=0;asprite_count;a++,extra++) { if(extra->type == generator && extra->life!=INVINCIBLE) { generators = TRUE; break; }//end if }//end for if(!generators) { ggg->canExit = TRUE; ggg->lights = LIGHTS_OFF; ggg->ceilmode = BLACK; ggg->floormode = BLACK; SetUpCeilingAndFloor(); ggg->levelstyle = level_normal; //Don't check anymore } } break; } if(ggg->lights==LIGHTS_OFF) { SpriteStruct *extra = ggg->sprites_extra; FATSPRITE *spr = ggg->sprites; for(a=0;asprite_count;a++) { if((dist(abs(fc->cam_xpos-spr->xpos), abs(fc->cam_ypos-spr->ypos))>200UL)) spr->drawmode = SPRITEMODE_UNUSED; else spr->drawmode = extra->drawmode; ++spr; ++extra; } } ggg->old_tile = *mapcode; } #endif