/* GAME.C Main and miscellaneous functions for in-game, contains the main game loop, etc. */ #include "keen.h" #include "demobox.h" #include "include/game.h" #include "sdl/CVideoDriver.h" #include "include/menu.h" #include "include/misc.h" #include "include/gamedo.h" #include "include/gamepdo.h" #include "include/gm_pdowm.h" #include "include/eseq_ep3.h" #include "sdl/CTimer.h" #include "sdl/CInput.h" #include "sdl/sound/CSound.h" #include "include/enemyai.h" #include "hqp/CMusic.h" #include "vorticon/CPlayer.h" #include "vorticon/CHighScores.h" #include "hqp/CHQBitmap.h" #include "CLogFile.h" char otherplayer; // TODO: seperate status boxes for the different players // TODO: Your Ship Needs These Parts in multiplayer int playerbaseframes[MAX_PLAYERS] = {0,0,0,0,0,0,0,0}; unsigned int max_scroll_x, max_scroll_y; char debugmode=0,acceleratemode=0; // and this is where the magic happens void gameloop(stCloneKeenPlus *pCKP) { unsigned int i; int enter,lastquit; // Enable the yorp/garg statues elders switches animations for(int i=0 ; iControl.levelcontrol.curlevel; crashflag3 = pCKP->Control.levelcontrol.episode; why_term_ptr = "No player start position! (flag2=pCKP->Control.levelcontrol.curlevel, flag3=pCKP->Control.levelcontrol.episode)"; } if (!loadinggame) { gameloop_initialize(pCKP); } else { loadinggame = 0; fade.mode = FADE_GO; fade.dir = FADE_IN; fade.curamt = 0; fade.fadetimer = 0; fade.rate = FADE_NORM; } // fire all guns immediately first time around gunfiretimer = (gunfirefreq+1); // if this is Mortimer's Castle, fade in and do the conversation // with Mortimer. if (pCKP->Control.levelcontrol.episode==3 && pCKP->Control.levelcontrol.curlevel==16) { for(i=0;ipollEvents(); g_pTimer->SpeedThrottle(); gamedo_RenderScreen(pCKP); } while(fade.mode!=FADE_COMPLETE /*&& !immediate_keytable[KQUIT]*/); eseq3_Mortimer(pCKP); } lastquit = 1; g_pInput->flushKeys(); // The Windows need that. I don't know why! // Now, we are ready to loop the game scenes (map and level) // Let's create the player objects do { if (primaryplayer==1) otherplayer = 0; else otherplayer = 1; #ifdef NETWORK_PLAY // if (numplayers>1) net_getdata(); if (is_server) { Net_Server_Run(); } else if (is_client) { Net_Client_Run(); } #endif gamedo_fades(); // periodically make all enemy gun fixtures fire (in ep3) // (also ice cannons in ep1) we do this in a global variable // so they're all in sync. when gunfiretimer==0 all gun SE // objects will fire. if (gunfiretimer > gunfirefreq) { gunfiretimer = 0; } else gunfiretimer++; // gather input and copy to player[].keytable[] structures gamedo_getInput(pCKP); // run the player behaviour for each player in the game if (!map.isworldmap) { for(i=0;iControl.levelcontrol.gameovermode && pCKP->Control.levelcontrol.level_done==LEVEL_NOT_DONE) { ScreenIsScrolling = 0; if (gamedo_ScrollTriggers(primaryplayer)) ScreenIsScrolling = 1; } // do frameskipping, and render/blit the screen if it's time gamedo_frameskipping(pCKP); // when we complete a fade out flag to exit the game loop if (fade.mode==FADE_COMPLETE) { if (fade.dir==FADE_OUT) { demomode = DEMO_NODEMO; pCKP->Control.levelcontrol.level_done = LEVEL_COMPLETE; pCKP->Control.levelcontrol.command = LVLC_CHANGE_LEVEL; if (pCKP->Control.levelcontrol.curlevel != WM_MAP_NUM) { // exiting a level, going back to world map for(i=0;iControl.levelcontrol.success==1) { // mark level as completed on world map pCKP->Control.levelcontrol.levels_completed[pCKP->Control.levelcontrol.curlevel] = 1; } pCKP->Control.levelcontrol.chglevelto = WM_MAP_NUM; } } else { fade.mode = NO_FADE; } } // when walking through the exit door don't show keen's sprite past // the door frame (so it looks like he walks "through" the door) if (pCKP->Control.levelcontrol.level_done==LEVEL_DONE_WALK) { gamepdo_walkbehindexitdoor(pCKP->Control.levelcontrol.level_finished_by, pCKP); } // allow enter to return to main menu // if we're in game over mode enter = (g_pInput->getPressedCommand(IC_STATUS)); if (pCKP->Control.levelcontrol.gameovermode) { if (enter) { int cities=0; CHighScores *HighScoreTable; if (pCKP->Control.levelcontrol.levels_completed[4]) cities++; if (pCKP->Control.levelcontrol.levels_completed[6]) cities++; if (pCKP->Control.levelcontrol.levels_completed[7]) cities++; if (pCKP->Control.levelcontrol.levels_completed[13]) cities++; if (pCKP->Control.levelcontrol.levels_completed[11]) cities++; if (pCKP->Control.levelcontrol.levels_completed[9]) cities++; if (pCKP->Control.levelcontrol.levels_completed[15]) cities++; if (pCKP->Control.levelcontrol.levels_completed[16]) cities++; HighScoreTable = new CHighScores(pCKP); bool extras[4] = {false,false,false,false}; // check inventory or saved cities if(pCKP->Control.levelcontrol.episode == 1) { if(player[0].inventory.HasJoystick) extras[0] = true; if(player[0].inventory.HasBattery) extras[1] = true; if(player[0].inventory.HasVacuum) extras[2] = true; if(player[0].inventory.HasFuel) extras[3] = true; } HighScoreTable->writeHighScore((int)player[0].inventory.score,extras,cities); HighScoreTable->showHighScore(); delete HighScoreTable; if (fade.mode!=FADE_GO && fade.dir!=FADE_OUT) { fade.dir = FADE_OUT; fade.curamt = PAL_FADE_SHADES; fade.fadetimer = 0; fade.rate = FADE_NORM; fade.mode = FADE_GO; } pCKP->Control.levelcontrol.command = LVLC_GAME_OVER; } if (fade.mode==FADE_COMPLETE && fade.dir==FADE_OUT) { pCKP->Control.levelcontrol.command = LVLC_GAME_OVER; } } #ifdef NETWORK_PLAY // if (numplayers>1) net_senddata(); #endif if (g_pInput->getPressedKey(KQUIT)) { VerifyQuit(pCKP); } if (QuitState != NO_QUIT) return; // limit frame rate if (!acceleratemode) { g_pInput->pollEvents(); g_pTimer->SpeedThrottle(); #ifdef NETWORK_PLAY // if (numplayers>1) net_sync(); #endif } if(g_pInput->getExitEvent()) { g_pInput->sendKey(KQUIT); g_pInput->cancelExitEvent(); } } while(!crashflag && pCKP->Control.levelcontrol.command==LVLC_NOCOMMAND); // Cleanup the player structure! } // gives keycard for door doortile to player p void give_keycard(int doortile, int p) { bool keystack = options[OPT_KEYCARDSTACK].value; // True if set g_pSound->playSound(SOUND_GET_CARD, PLAY_NOW); if (doortile==DOOR_YELLOW) player[p].inventory.HasCardYellow = keystack ? player[p].inventory.HasCardYellow + 1 : 1; else if (doortile==DOOR_RED) player[p].inventory.HasCardRed = keystack ? player[p].inventory.HasCardRed + 1 : 1; else if (doortile==DOOR_GREEN) player[p].inventory.HasCardGreen = keystack ? player[p].inventory.HasCardGreen + 1 : 1; else if (doortile==DOOR_BLUE) player[p].inventory.HasCardBlue = keystack ? player[p].inventory.HasCardBlue + 1 : 1; else { crashflag = 1; crashflag2 = doortile; why_term_ptr = "give_keycard(): invalid value for doortile parameter."; } } // take away the specified keycard from player p void take_keycard(int doortile, int p) { if (doortile==DOOR_YELLOW) player[p].inventory.HasCardYellow--; else if (doortile==DOOR_RED) player[p].inventory.HasCardRed--; else if (doortile==DOOR_GREEN) player[p].inventory.HasCardGreen--; else if (doortile==DOOR_BLUE) player[p].inventory.HasCardBlue--; if(player[p].inventory.HasCardYellow > 9) player[p].inventory.HasCardYellow = 0; if(player[p].inventory.HasCardRed > 9) player[p].inventory.HasCardRed = 0; if(player[p].inventory.HasCardGreen > 9) player[p].inventory.HasCardGreen = 0; if(player[p].inventory.HasCardBlue > 9) player[p].inventory.HasCardBlue = 0; } // unregisters all animated tiles with baseframe tile void unregister_animtiles(int tile) { int i; for(i=0;iplaySound(SOUND_DOOR_OPEN, PLAY_NOW); take_keycard(doortile, cp); /* erase door from map */ if (pCKP->Control.levelcontrol.episode==3) { chgtotile = map.mapdata[mpx-1][mpy]; } else { chgtotile = tiles[map.mapdata[mpx][mpy]].chgtile; } if(TileProperty[map.mapdata[mpx][mpy-1]][BEHAVIOR] > 1 && TileProperty[map.mapdata[mpx][mpy-1]][BEHAVIOR] < 6) // This happens because, sometimes the player opens the door // from a lower part. { map_chgtile(mpx, mpy-1, chgtotile); tilefix=1; } if(TileProperty[map.mapdata[mpx][mpy]][BEHAVIOR] > 1 && TileProperty[map.mapdata[mpx][mpy]][BEHAVIOR] < 6) // This happens because, sometimes the player opens the door // from a lower part. { map_chgtile(mpx, mpy, chgtotile); // upper? } if(TileProperty[map.mapdata[mpx][mpy+1]][BEHAVIOR] > 1 && TileProperty[map.mapdata[mpx][mpy+1]][BEHAVIOR] < 6) // This happens because, sometimes the player opens the door // from a lower part. { map_chgtile(mpx, mpy+1, chgtotile); // When he stands in front of the door! } // replace the door tiles with a door object, which will do the animation o = spawn_object(mpx<<4< than "extra life at" and award 1-UPs when appropriate void extralifeat(int cp) { if (player[cp].inventory.score > player[cp].inventory.extralifeat) { g_pSound->playSound(SOUND_EXTRA_LIFE, PLAY_NOW); player[cp].inventory.lives++; player[cp].inventory.extralifeat += 20000; } } // have keen pick up the goodie at screen pixel position (px, py) void keen_get_goodie(int px, int py, int theplayer, stCloneKeenPlus *pCKP) { int mpx,mpy,t; /*int i;*/ mpx = px>>4; mpy = py>>4; t = map.mapdata[mpx][mpy]; if ((TileProperty[t][BEHAVIOR] < 17 && TileProperty[t][BEHAVIOR] > 5) || (TileProperty[t][BEHAVIOR] > 17 && TileProperty[t][BEHAVIOR] < 22) || (TileProperty[t][BEHAVIOR] == 27 || TileProperty[t][BEHAVIOR] == 28) ) // All pickupable items //if (tiles[t].pickupable) { // pick up the goodie, i.e. erase it from the map map_chgtile(mpx, mpy, tiles[t].chgtile); //if (tiles[t].isAnimated) map_deanimate(mpx, mpy); if (TileProperty[t][ANIMATION] != 1) map_deanimate(mpx, mpy); } else if (TileProperty[t][BEHAVIOR] == 1) //else if (tiles[t].lethal) { // whoah, this "goodie" isn't so good... killplayer(theplayer); return; } // do whatever the goodie is supposed to do... procgoodie(t, mpx, mpy, theplayer, pCKP); } void initgame(stCloneKeenPlus *pCKP) { int x,y; unsigned int i; animtiletimer = curanimtileframe = 0; //PlatExtending = 0; // reset player walk frame widths for(i=0;iControl.levelcontrol.episode==1) { gunfirefreq = ICECANNON_FIRE_FREQ; } else { gunfirefreq = GUN_FIRE_FREQ; } // reset the ysize attribute of all doors sprites[DOOR_YELLOW_SPRITE].ysize = 32; sprites[DOOR_RED_SPRITE].ysize = 32; sprites[DOOR_GREEN_SPRITE].ysize = 32; sprites[DOOR_BLUE_SPRITE].ysize = 32; pCKP->Control.levelcontrol.level_done_timer = 0; pCKP->Control.levelcontrol.gameovermode = 0; // all objects -> not exist for(i=1;iControl.levelcontrol.episode==1) { objdefsprites[OBJ_YORP] = OBJ_YORP_DEFSPRITE; objdefsprites[OBJ_GARG] = OBJ_GARG_DEFSPRITE; objdefsprites[OBJ_BUTLER] = OBJ_BUTLER_DEFSPRITE; objdefsprites[OBJ_TANK] = OBJ_TANK_DEFSPRITE; objdefsprites[OBJ_ICECHUNK] = OBJ_ICECHUNK_DEFSPRITE; objdefsprites[OBJ_ICEBIT] = OBJ_ICEBIT_DEFSPRITE; objdefsprites[OBJ_ROPE] = OBJ_ROPE_DEFSPRITE; objdefsprites[OBJ_RAY] = OBJ_RAY_DEFSPRITE_EP1; objdefsprites[OBJ_VORT] = OBJ_VORT_DEFSPRITE_EP1; } else if (pCKP->Control.levelcontrol.episode==2) { objdefsprites[OBJ_WALKER] = OBJ_WALKER_DEFSPRITE; objdefsprites[OBJ_TANKEP2] = OBJ_TANKEP2_DEFSPRITE; objdefsprites[OBJ_VORTELITE] = OBJ_VORTELITE_DEFSPRITE; objdefsprites[OBJ_RAY] = OBJ_RAY_DEFSPRITE_EP2; objdefsprites[OBJ_VORT] = OBJ_VORT_DEFSPRITE_EP2; objdefsprites[OBJ_PLATFORM] = OBJ_PLATFORM_DEFSPRITE_EP2; objdefsprites[OBJ_BABY] = OBJ_BABY_DEFSPRITE_EP2; } else if (pCKP->Control.levelcontrol.episode==3) { objdefsprites[OBJ_FOOB] = OBJ_FOOB_DEFSPRITE; objdefsprites[OBJ_NINJA] = OBJ_NINJA_DEFSPRITE; objdefsprites[OBJ_MOTHER] = OBJ_MOTHER_DEFSPRITE; objdefsprites[OBJ_MEEP] = OBJ_MEEP_DEFSPRITE; objdefsprites[OBJ_BALL] = OBJ_BALL_DEFSPRITE; objdefsprites[OBJ_JACK] = OBJ_BALL_DEFSPRITE; objdefsprites[OBJ_RAY] = OBJ_RAY_DEFSPRITE_EP3; objdefsprites[OBJ_VORT] = OBJ_VORT_DEFSPRITE_EP3; objdefsprites[OBJ_PLATFORM] = OBJ_PLATFORM_DEFSPRITE_EP3; objdefsprites[OBJ_BABY] = OBJ_BABY_DEFSPRITE_EP3; } objdefsprites[OBJ_DOOR] = DOOR_YELLOW_SPRITE; objdefsprites[OBJ_TELEPORTER] = OBJ_TELEPORTER_DEFSPRITE; objdefsprites[OBJ_SECTOREFFECTOR] = BlankSprite; // initilize game variables pCKP->Control.levelcontrol.level_done = LEVEL_NOT_DONE; animtiletimer = curanimtileframe = 0; DemoObjectHandle = 0; for(i=0;iControl.levelcontrol.levels_completed[i] = 0; for(i=0;iControl.levelcontrol.episode==1) { player[i].inventory.charges = 0; } else if (pCKP->Control.levelcontrol.episode==2) { player[i].inventory.charges = 3; } else { player[i].inventory.charges = 5; } if (demomode) player[i].inventory.charges = 100; // start with pogo stick in all episodes but 1 if (pCKP->Control.levelcontrol.episode!=1 || demomode) { player[i].inventory.HasPogo = 1; } else { player[i].inventory.HasPogo = 0; } } initsprites(pCKP, s); if (demomode) srand(375); primaryplayer = 0; return 0; } char spawn_object(int x, int y, int otype) { int i; // find an unused object slot for(i=1;itextOut(PURPLE, "Warning : Object could not be created."); return 0; } // common enemy/object ai, such as falling, setting blocked variables, // detecting player contact, etc. void common_enemy_ai(int o) { int x,y,xa,ya,xsize,ysize; int temp; int cplayer; if (objects[o].type==OBJ_DEMOMSG) return; xsize = sprites[objects[o].sprite].xsize; ysize = sprites[objects[o].sprite].ysize; // set value of blockedd--should object fall? temp = (objects[o].y>>CSF)+ysize; if ((temp>>4)<<4 != temp) { objects[o].blockedd = 0; } else { // on a tile boundary, test if tile under object is solid objects[o].blockedd = 0; x = (objects[o].x>>CSF); y = (objects[o].y>>CSF)+ysize+1; for(xa=0;xa 1 && TileProperty[getmaptileat(x+xa,y)][BEHAVIOR] < 6) ) { objects[o].blockedd = 1; goto setblockedd; } } if(TileProperty[getmaptileat(x+xsize-2, y)][BUP] || (TileProperty[getmaptileat(x+xa,y)][BEHAVIOR] > 1 && TileProperty[getmaptileat(x+xa,y)][BEHAVIOR] < 6) ) { objects[o].blockedd = 1; } setblockedd: ; } // set blockedu objects[o].blockedu = 0; x = (objects[o].x>>CSF); y = (objects[o].y>>CSF)-1; for(xa=0;xa>CSF)-1; y = (objects[o].y>>CSF)+1; for(ya=0;ya>CSF)+ysize-1))][BRIGHT]) //if (tiles[getmaptileat(x, ((objects[o].y>>CSF)+ysize-1))].solidr) { objects[o].blockedl = 1; } setblockedl: ; // set blockedr objects[o].blockedr = 0; x = (objects[o].x>>CSF)+xsize; y = (objects[o].y>>CSF)+1; for(ya=0;ya>CSF)+ysize-1))][BLEFT]) //if (tiles[getmaptileat(x, ((objects[o].y>>CSF)+ysize-1))].solidl) { objects[o].blockedr = 1; } setblockedr: ; // hit detection with players objects[o].touchPlayer = 0; for(cplayer=0;cplayerOBJ_YINERTIA_RATE) { if (objects[o].yinertia < OBJFALLSPEED) objects[o].yinertia++; objects[o].yinertiatimer = 0; } else objects[o].yinertiatimer++; } objects[o].y += objects[o].yinertia; } } // returns nonzero if object1 overlaps object2 char hitdetect(int object1, int object2) { int s1, s2; unsigned int rect1x1, rect1y1, rect1x2, rect1y2; unsigned int rect2x1, rect2y1, rect2x2, rect2y2; // get the sprites used by the two objects s1 = objects[object1].sprite; s2 = objects[object2].sprite; // get the bounding rectangle of the first object rect1x1 = objects[object1].x + sprites[s1].bboxX1; rect1y1 = objects[object1].y + sprites[s1].bboxY1; rect1x2 = objects[object1].x + sprites[s1].bboxX2; rect1y2 = objects[object1].y + sprites[s1].bboxY2; // get the bounding rectangle of the second object rect2x1 = objects[object2].x + sprites[s2].bboxX1; rect2y1 = objects[object2].y + sprites[s2].bboxY1; rect2x2 = objects[object2].x + sprites[s2].bboxX2; rect2y2 = objects[object2].y + sprites[s2].bboxY2; // find out if the rectangles overlap if ((rect1x1 < rect2x1) && (rect1x2 < rect2x1)) return 0; if ((rect1x1 > rect2x2) && (rect1x2 > rect2x2)) return 0; if ((rect1y1 < rect2y1) && (rect1y2 < rect2y1)) return 0; if ((rect1y1 > rect2y2) && (rect1y2 > rect2y2)) return 0; return 1; } void killplayer(int theplayer) { if (player[theplayer].godmode || g_pInput->getHoldedKey(KTAB)) return; if (player[theplayer].ankhtime) return; if (!player[theplayer].pdie) { player[theplayer].pdie = PDIE_DYING; player[theplayer].pdieframe = 0; player[theplayer].pdietimer = 0; player[theplayer].pdietillfly = DIE_TILL_FLY_TIME; player[theplayer].pdie_xvect = rand()%(DIE_MAX_XVECT*2); player[theplayer].pdie_xvect -= DIE_MAX_XVECT; player[theplayer].inventory.lives--; player[theplayer].y += (8<stop(); g_pSound->playSound(SOUND_KEEN_DIE, PLAY_NOW); } } void freezeplayer(int theplayer) { if (player[theplayer].godmode /*|| immediate_keytable[KTAB]*/) return; if (player[theplayer].ankhtime) return; // give the player a little "kick" player[theplayer].pjumptime = PJUMP_NORMALTIME_1; player[theplayer].pjumpupdecreaserate = PJUMP_UPDECREASERATE_1; player[theplayer].pjumpupspeed = 15; player[theplayer].pjumping = PJUMPUP; player[theplayer].pjumpupspeed_decreasetimer = 0; player[theplayer].pjustjumped = 1; // and freeze him (stun him on ep2/3) player[theplayer].pfrozentime = PFROZEN_TIME; player[theplayer].pfrozenframe = 0; player[theplayer].pfrozenanimtimer = 0; player[theplayer].ppogostick = false; } void PlayerTouchedExit(int theplayer, stCloneKeenPlus *pCKP) { /*int i;*/ if (!player[theplayer].pjumping && !player[theplayer].pfalling\ && !player[theplayer].ppogostick && \ pCKP->Control.levelcontrol.level_done==LEVEL_NOT_DONE) { // don't allow player to walk through a door if he's standing // on an object such as a platform or an enemy if (player[theplayer].psupportingobject) { return; } // if player has ankh shut it off if (player[theplayer].ankhtime) { player[theplayer].ankhtime = 0; objects[player[theplayer].ankhshieldobject].exists = 0; } player[theplayer].ppogostick = false; g_pMusicPlayer->stop(); g_pSound->playSound(SOUND_LEVEL_DONE, PLAY_NOW); pCKP->Control.levelcontrol.level_done = LEVEL_DONE_WALK; pCKP->Control.levelcontrol.level_finished_by = theplayer; } } void endlevel(int success, stCloneKeenPlus *pCKP) { if (fade.mode == NO_FADE) { fade.dir = FADE_OUT; fade.curamt = PAL_FADE_SHADES; fade.fadetimer = 0; fade.rate = FADE_NORM; fade.mode = FADE_GO; pCKP->Control.levelcontrol.success = success; pCKP->Control.levelcontrol.tobonuslevel = 0; } } void SetGameOver(stCloneKeenPlus *pCKP) { /*int x,y,bmnum;*/ if (!pCKP->Control.levelcontrol.gameovermode) { pCKP->Control.levelcontrol.gameovermode = 1; g_pSound->playSound(SOUND_GAME_OVER, PLAY_NOW); } } // this is so objects can block the player, // player can stand on them, etc. // x and y are the CSFed coordinates to check (e.g. playx and playy) // returns nonzero if there is a solid object // at that point char checkobjsolid(unsigned int x, unsigned int y, unsigned int cp) { int o; for(o=1;o= objects[o].x+sprites[objects[o].sprite].bboxX1) if (x <= objects[o].x+sprites[objects[o].sprite].bboxX2) if (y >= objects[o].y+sprites[objects[o].sprite].bboxY1) if (y <= objects[o].y+sprites[objects[o].sprite].bboxY2) return o; } } return 0; } // returns 1 if player cp has the card to door t, which -> door char CheckDoorBlock(int t, int cp, int which,stCloneKeenPlus *pCKP) { if (which==DOOR_YELLOW) { if (!player[cp].inventory.HasCardYellow) { player[cp].blockedby = t; return 1; } } else if (which==DOOR_RED) { if (!player[cp].inventory.HasCardRed) { player[cp].blockedby = t; return 1; } } else if (which==DOOR_GREEN) { if (!player[cp].inventory.HasCardGreen) { player[cp].blockedby = t; return 1; } } else if (which==DOOR_BLUE) { if (!player[cp].inventory.HasCardBlue) { player[cp].blockedby = t; return 1; } } return 0; } // checks if tile at (x,y) is solid to the player walking left into it. // returns 1 and sets blockedby if so. char checkissolidl(int x, int y, int cp, stCloneKeenPlus *pCKP) { int t; t = getmaptileat(x, y); if(TileProperty[t][BLEFT] || x < 0) //if (tiles[t].solidl) { player[cp].blockedby = t; return 1; } if (checkobjsolid(x<=16) { y2 = 0; t++; } } } // creates a mask from a sourcetile, places it in desttile void MakeMask(int sourcetile, int desttile, int transparentcol) { int x,y,c; for(y=0;y<16;y++) { for(x=0;x<16;x++) { c = tiledata[sourcetile][y][x]; if (c != transparentcol) c = 0; else c = 15; tiledata[desttile][y][x] = c; } } } // replaces all instances of color find in sprite s with // color replace, as long as the y is greater than miny void ReplaceSpriteColor(int s, int find, int replace, int miny) { int x,y; for(y=miny;yControl.levelcontrol.episode==1) { // MakeMask(443, 155, 7); // tiles[443].masktile = 155; // tiles[428].masktile = 155; } } void procgoodie(int t, int mpx, int mpy, int theplayer, stCloneKeenPlus *pCKP) { if ((TileProperty[t][BEHAVIOR] > 5 && TileProperty[t][BEHAVIOR] < 11) || (TileProperty[t][BEHAVIOR] > 17 && TileProperty[t][BEHAVIOR] < 22) ) { if((player[theplayer].x*player[theplayer].y) % 2 == 1) g_pSound->playStereofromCoord(SOUND_GET_BONUS, PLAY_NOW, 0); else g_pSound->playStereofromCoord(SOUND_GET_BONUS, PLAY_NOW, 320); } else if (TileProperty[t][BEHAVIOR] > 10 && TileProperty[t][BEHAVIOR] < 16) g_pSound->playSound(SOUND_GET_ITEM, PLAY_NOW); switch(TileProperty[t][BEHAVIOR]) { // keycards case 18: give_keycard(DOOR_YELLOW, theplayer); break; case 19: give_keycard(DOOR_RED, theplayer); break; case 20: give_keycard(DOOR_GREEN, theplayer); break; case 21: give_keycard(DOOR_BLUE, theplayer); break; case DOOR_YELLOW: if (player[theplayer].inventory.HasCardYellow) open_door(DOOR_YELLOW, DOOR_YELLOW_SPRITE, mpx, mpy, theplayer, pCKP); break; case DOOR_RED: if (player[theplayer].inventory.HasCardRed) open_door(DOOR_RED, DOOR_RED_SPRITE, mpx, mpy, theplayer, pCKP); break; case DOOR_GREEN: if (player[theplayer].inventory.HasCardGreen) open_door(DOOR_GREEN, DOOR_GREEN_SPRITE, mpx, mpy, theplayer, pCKP); break; case DOOR_BLUE: if (player[theplayer].inventory.HasCardBlue) open_door(DOOR_BLUE, DOOR_BLUE_SPRITE, mpx, mpy, theplayer, pCKP); break; case 7: // What gives you 100 Points player[theplayer].inventory.score += 100; extralifeat(theplayer); break; case 8: // What gives you 200 Points player[theplayer].inventory.score += 200; extralifeat(theplayer); break; case 6: // What gives you 500 Points player[theplayer].inventory.score += 500; extralifeat(theplayer); break; case 9: // What gives you 1000 Points player[theplayer].inventory.score += 1000; extralifeat(theplayer); break; case 10: // What gives you 5000 Points player[theplayer].inventory.score += 5000; extralifeat(theplayer); break; case 15: // raygun player[theplayer].inventory.charges += 5; break; case 16: // the Holy Pogo Stick player[theplayer].inventory.HasPogo = 1; g_pSound->playSound(SOUND_GET_PART, PLAY_NOW); break; case 11: player[theplayer].inventory.HasJoystick = 1; g_pSound->playSound(SOUND_GET_PART, PLAY_NOW); break; case 12: player[theplayer].inventory.HasBattery = 1; g_pSound->playSound(SOUND_GET_PART, PLAY_NOW); break; case 13: player[theplayer].inventory.HasVacuum = 1; g_pSound->playSound(SOUND_GET_PART, PLAY_NOW); break; case 14: player[theplayer].inventory.HasFuel = 1; g_pSound->playSound(SOUND_GET_PART, PLAY_NOW); break; // in-level teleporter // (in level13.ck1 that takes you to the bonus level) case 24: endlevel(0, pCKP); pCKP->Control.levelcontrol.tobonuslevel = 1; break; case YORPSTATUEHEAD: if(pCKP->Control.levelcontrol.episode == 1) { youseeinyourmind(mpx, mpy, pCKP); } else if(pCKP->Control.levelcontrol.episode == 2) if(!player[theplayer].blockedr && !player[theplayer].blockedl) VorticonElder(mpx, mpy, pCKP); break; case 27: if(pCKP->Control.levelcontrol.episode == 3) GiveAnkh(theplayer); break; case 28: player[theplayer].inventory.charges++; g_pSound->playSound(SOUND_GET_ITEM, PLAY_NOW); break; case 17: if (pCKP->Control.levelcontrol.canexit && (!pCKP->Control.levelcontrol.isfinallevel || player[theplayer].inventory.HasFuel)) { pCKP->Control.levelcontrol.exitXpos = (mpx+2)<<4; PlayerTouchedExit(theplayer, pCKP); } break; case 23:break; // these are switches. They cannot not be picked up! case 25:break; // Refer to JumpandPogo to check the activation code case 26:break; // we fell off the bottom of the map case TILE_FELLOFFMAP_EP1: if (!player[theplayer].pdie) { g_pSound->playSound(SOUND_KEEN_FALL, PLAY_FORCE); player[theplayer].ankhtime = 0; player[theplayer].godmode = 0; player[theplayer].pdie = PDIE_FELLOFFMAP; } break; default: why_term_ptr = "procgoodie_ep1: Unknown goodie-- value given in flag2."; break; } } // yorp/walker etc "bump". // if solid = 0, player can possibly force his way through. // if solid = 1, object acts like a solid "wall". void bumpplayer(int p, int pushamt, bool solid) { player[p].playpushed_x = pushamt; if (solid) { if (pushamt > 0) { if (player[p].pinertia_x < 0) player[p].pinertia_x = 0; } else { if (player[p].pinertia_x > 0) player[p].pinertia_x = 0; } } player[p].playpushed_decreasetimer = 0; if (!player[p].pjumping) { player[p].pdir = player[p].pshowdir = (pushamt<0)?LEFT:RIGHT; } } void GiveAnkh(int cp) { int o; if (!player[cp].ankhtime) { o = spawn_object(player[cp].x, player[cp].y, OBJ_SECTOREFFECTOR); objects[o].ai.se.type = SE_ANKHSHIELD; player[cp].ankhshieldobject = o; } g_pSound->playSound(SOUND_ANKH, PLAY_NOW); player[cp].ankhtime = PLAY_ANKH_TIME; gamepdo_ankh(cp); } void gameloop_initialize(stCloneKeenPlus *pCKP) { unsigned int x,y,i/*,tl*/; int timeout; if (pCKP->Control.levelcontrol.episode == 3) { // coat the top of the map ("oh no!" border) with a non-solid tile // so keen can jump partially off the top of the screen for(x=1;xControl.levelcontrol.episode==1) { // coat the bottom of the map below the border. // since the border has solidceil=1 this provides // a platform to catch yorps that fall off the map y = map.ysize; for(x=2;x>CSF>>4 < (map.xsize/2) || pCKP->Control.levelcontrol.episode==1) { x += (18<>CSF>>4 < (map.xsize/2) || pCKP->Control.levelcontrol.episode==1) player[i].pdir = player[i].pshowdir = RIGHT; else player[i].pdir = player[i].pshowdir = LEFT; } } // scroll past the first two tiles (the level border), they'll // now never be visible because you're not allowed to scroll // left past X=32. for(i=0;i<2*16;i++) { map_scroll_right(); map_scroll_down(); } // scroll the screen until the primary player is onscreen // enough to where he doesn't set off the scroll triggers for(timeout=0;timeout<10000;timeout++) { if (!gamedo_ScrollTriggers(primaryplayer)) break; } // initiate fade-in fade.mode = FADE_GO; fade.dir = FADE_IN; fade.rate = FADE_NORM; fade.curamt = 0; fade.fadetimer = 0; // "keens left" when returning to world map after dying if (pCKP->Control.levelcontrol.dokeensleft) { keensleft(pCKP); pCKP->Control.levelcontrol.dokeensleft = 0; } }