diff --git a/src/CGame.cpp b/src/CGame.cpp
index b783defa3..c741a4609 100644
--- a/src/CGame.cpp
+++ b/src/CGame.cpp
@@ -291,8 +291,6 @@ void CGame::preallocateCKP(stCloneKeenPlus *pCKP)
demomode = DEMO_NODEMO;
current_demo = 1;
- memset(&pCKP->Control, 0, sizeof(stControl));
-
pCKP->Joystick = NULL;
acceleratemode = 0;
diff --git a/src/CGraphics.cpp b/src/CGraphics.cpp
index 843024784..9740c6f33 100644
--- a/src/CGraphics.cpp
+++ b/src/CGraphics.cpp
@@ -48,7 +48,7 @@ bool CGraphics::allocScrollBufmem(void)
if (g_pVideoDriver->getZoomValue() > 1)
{
g_pLogFile->ftextOut("allocmem(): allocating %d bytes for blit buffer...", blitbuf_memsize);
- blitbuffer = (unsigned char*) malloc(blitbuf_memsize);
+ blitbuffer = new unsigned char[blitbuf_memsize];
if (!blitbuffer)
{
g_pLogFile->ftextOut(RED,"Failure
");
@@ -63,12 +63,12 @@ void CGraphics::freemem(void)
{
if (scrollbuffer)
{
- delete[] scrollbuffer;
+ delete[] scrollbuffer; scrollbuffer = NULL;
g_pLogFile->ftextOut(BLACK,true," Scrollbuffer memory released to system.
");
}
if (blitbuffer)
{
- free(blitbuffer);
+ delete[] blitbuffer; blitbuffer = NULL;
g_pLogFile->ftextOut(BLACK,true," Blitbuffer memory released to system.
");
}
}
diff --git a/src/game.cpp b/src/game.cpp
index 1c49f410b..014c2e98f 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -1,1490 +1,1487 @@
-/* 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"
-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];
-
- // check inventory or saved cities
- memset(extras,false,4*sizeof(bool));
- 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, pCKP);
- 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_BEAR] = OBJ_BEAR_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_BJ_DEFSPRITE;
- objdefsprites[OBJ_JACK] = OBJ_BJ_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;i>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, stCloneKeenPlus *pCKP)
-{
- if (player[theplayer].godmode || g_pInput->getHoldedKey(KTAB)) return;
- if (player[theplayer].ankhtime) return;
- if (pCKP->Control.levelcontrol.level_done) 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;
- }
-
-
-}
-
-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;
- }
-
-}
+/* 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"
+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, pCKP);
+ 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_BEAR] = OBJ_BEAR_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_BJ_DEFSPRITE;
+ objdefsprites[OBJ_JACK] = OBJ_BJ_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;i>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, stCloneKeenPlus *pCKP)
+{
+ if (player[theplayer].godmode || g_pInput->getHoldedKey(KTAB)) return;
+ if (player[theplayer].ankhtime) return;
+ if (pCKP->Control.levelcontrol.level_done) 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;
+ }
+
+
+}
+
+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;
+ }
+
+}
diff --git a/src/include/declarations.h b/src/include/declarations.h
index eba9dd909..4b1de124d 100644
--- a/src/include/declarations.h
+++ b/src/include/declarations.h
@@ -3,6 +3,7 @@
#include
#include
+#include
#define MAX_COMMANDS 8
#define MAX_SOUND_LENGTH 1024
@@ -11,7 +12,7 @@
#define MAX_NUMBER_OF_FILES 100
-typedef struct stDisplay
+struct stDisplay
{
unsigned int Width;
unsigned int Height;
@@ -21,15 +22,18 @@ typedef struct stDisplay
short Filtermode;
short Zoom;
unsigned short FrameSkip;
-} stDisplay;
+
+ // as long as we only have POD
+ stDisplay() { memset(this, 0, sizeof(stDisplay)); }
+};
-typedef struct stDevice
+struct stDevice
{
SDL_Joystick *Joystick;
SDL_Event Event;
-} stDevice;
+};
-typedef struct stLevelControl
+struct stLevelControl
{
// level control
int command; // used to give a command to playgame_levelmanager()
@@ -57,18 +61,23 @@ typedef struct stLevelControl
unsigned int level_done, level_done_timer;
unsigned int level_finished_by; // index of player that finished level
unsigned int exitXpos;
-} stLevelControl;
+
+ // as long as we only have POD
+ stLevelControl() { memset(this, 0, sizeof(stLevelControl)); }
+};
-typedef struct stControl
+struct stControl
{
- short eseq; // see only the ending sequence
- short dtm; // go direct to map.
- short storyboard; // go to storyboard
- short skipstarting; // Skip Startmenu, Intro and Mainmenu.
+ bool eseq; // see only the ending sequence
+ bool dtm; // go direct to map.
+ bool storyboard; // go to storyboard
+ bool skipstarting; // Skip Startmenu, Intro and Mainmenu.
stLevelControl levelcontrol;
-} stControl;
+
+ stControl() : eseq(false), dtm(false), storyboard(false), skipstarting(false) {}
+};
struct stGameData
{
diff --git a/src/include/gui/dialog.h b/src/include/gui/dialog.h
index feacde3fc..8f319b9e3 100644
--- a/src/include/gui/dialog.h
+++ b/src/include/gui/dialog.h
@@ -8,50 +8,52 @@
* Author: gerstrong
*/
+#ifndef __CG_DIALIG_H__
+#define __CG_DIALIG_H__
+
+#include
+#include
+
#define STARTER_SAVE 1
#define STARTER_ESCAPE 2
#define STARTER_SOUNDOPT 3
#define STARTER_DISPLAYOPT 4
#define STARTER_GAMEOPT 5
-typedef struct stTextLine
+struct stTextLine
{
- char *Text;
+ std::string Text;
short ID; // items are orded by ID
-} stTextLine;
+};
-typedef struct stSeparator
+struct stSeparator
{
short ID; // items are orded by ID
-} stSeparator;
+};
-typedef struct stOptionSwitch
+struct stOptionSwitch
{
char *Name;
char **Option;
short selected;
short numSel;
short ID; // items are orded by ID
-} stOptionSwitch;
+};
-typedef struct stStarterSwitch
+struct stStarterSwitch
{
- char *Name;
+ std::string Name;
int numFunctionToLaunch;
short ID; // items are sorted by IDs
-} stStarterSwitch;
+};
-typedef struct stDlgStruct // imagine every substructure as typical control
+struct stDlgStruct // imagine every substructure as typical control
{
- stTextLine *TextLine;
- stOptionSwitch *OptionSwitch;
- stStarterSwitch *StarterSwitch;
- stSeparator *Separator;
+ std::vector TextLine;
+ std::vector OptionSwitch;
+ std::vector StarterSwitch;
+ std::vector Separator;
+};
- short num_TextLines;
- short num_OptionSwitches;
- short num_StarterSwitch;
- short num_Separators;
-
-} stDlgStruct;
+#endif
diff --git a/src/keen.h b/src/keen.h
index 6c51fa217..20c5964fb 100644
--- a/src/keen.h
+++ b/src/keen.h
@@ -119,15 +119,15 @@ typedef struct stMap
#define BDOWN 4
#define BLEFT 5
-typedef struct stBitmap
+struct stBitmap
{
int xsize;
int ysize;
unsigned char *bmptr;
char name[9];
-} stBitmap;
+};
-typedef struct stSprite
+struct stSprite
{
char xsize, ysize;
unsigned char imgdata[64][64];
@@ -135,9 +135,9 @@ typedef struct stSprite
// bounding box for hit detection
unsigned int bboxX1, bboxY1;
unsigned int bboxX2, bboxY2;
-} stSprite;
+};
-typedef struct stInventory
+struct stInventory
{
unsigned long score;
unsigned long extralifeat;
@@ -153,7 +153,7 @@ typedef struct stInventory
unsigned char HasFuel;
unsigned char HasBattery;
unsigned char HasVacuum;
-} stInventory;
+};
// for strings loaded from "strings.dat"
#define MAX_STRINGS 100
@@ -169,7 +169,7 @@ struct stString
};
/* Structs used for different enemies data, these are in a union */
-typedef struct stYorpData
+struct stYorpData
{
unsigned char state;
@@ -180,8 +180,9 @@ typedef struct stYorpData
signed int yorpdie_inertia_y;
unsigned char movedir;
-} stYorpData;
-typedef struct stGargData
+};
+
+struct stGargData
{
unsigned char state;
@@ -194,8 +195,9 @@ typedef struct stGargData
unsigned char movedir;
unsigned char detectedPlayer, detectedPlayerIndex;
-} stGargData;
-typedef struct stVortData
+};
+
+struct stVortData
{
unsigned char state;
@@ -218,8 +220,9 @@ typedef struct stVortData
int JumpLeftFrame;
int DyingFrame;
int DeadFrame;
-} stVortData;
-typedef struct stBearData
+};
+
+struct stBearData
{
unsigned char state;
@@ -232,8 +235,9 @@ typedef struct stBearData
unsigned int running;
int dist_traveled;
-} stBearData;
-typedef struct stButlerData
+};
+
+struct stButlerData
{
unsigned char state;
unsigned char timer,animtimer;
@@ -241,8 +245,9 @@ typedef struct stButlerData
unsigned int dist_traveled;
unsigned char movedir;
-} stButlerData;
-typedef struct stTankData
+};
+
+struct stTankData
{
unsigned char state;
@@ -264,8 +269,9 @@ typedef struct stTankData
unsigned int firetimes;
unsigned int timetillcanfire;
unsigned int timetillcanfirecauseonsamelevel;
-} stTankData;
-typedef struct stRayData
+};
+
+struct stRayData
{
char state;
char direction;
@@ -280,20 +286,23 @@ typedef struct stRayData
// for earth chunks
int baseframe;
-} stRayData;
-typedef struct stDoorData
+};
+
+struct stDoorData
{
char timer;
char distance_traveled;
-} stDoorData;
-typedef struct stIceChunk
+};
+
+struct stIceChunk
{
char movedir;
char state;
unsigned int originalX, originalY;
int timer;
-} stIceChunk;
-typedef struct stTeleportData
+};
+
+struct stTeleportData
{
char animtimer;
char animframe;
@@ -312,17 +321,18 @@ typedef struct stTeleportData
char fadeamt;
char fadetimer;
-} stTeleportData;
-typedef struct stRopeData
+};
+
+struct stRopeData
{
char state;
int droptimer;
int droptimes;
int stoneX, stoneY;
int vortboss;
-} stRopeData;
+};
-typedef struct stWalkerData
+struct stWalkerData
{
unsigned char state;
@@ -333,9 +343,9 @@ typedef struct stWalkerData
unsigned char walkdir;
unsigned char kickedplayer[MAX_PLAYERS];
-} stWalkerData;
+};
-typedef struct stPlatformData
+struct stPlatformData
{
unsigned char state;
unsigned char animframe;
@@ -344,9 +354,9 @@ typedef struct stPlatformData
unsigned char movedir;
unsigned char kickedplayer[MAX_PLAYERS];
-} stPlatformData;
+};
-typedef struct stSEData
+struct stSEData
{
unsigned int type;
@@ -360,9 +370,9 @@ typedef struct stSEData
unsigned int frame;
int mx,my;
int blowx,blowy;
-} stSEData;
+};
-typedef struct stBabyData
+struct stBabyData
{
char state;
char dir;
@@ -373,9 +383,9 @@ typedef struct stBabyData
char walkframe;
int walktimer;
-} stBabyData;
+};
-typedef struct stFoobData
+struct stFoobData
{
char state;
char dir;
@@ -385,9 +395,9 @@ typedef struct stFoobData
int OffOfSameLevelTime;
int spooktimer;
int SpookedByWho;
-} stFoobData;
+};
-typedef struct stNinjaData
+struct stNinjaData
{
char state;
char dir;
@@ -401,7 +411,7 @@ typedef struct stNinjaData
int KickMoveTimer;
int isdying;
int dietimer;
-} stNinjaData;
+};
typedef struct stMotherData
{
@@ -644,7 +654,7 @@ typedef struct stAnimTile
#define SCROLLTRIGGERDOWN 114
// this structure contains all the variables used by a player
-typedef struct stPlayer
+struct stPlayer
{
// these coordinates are CSFed
unsigned long x;
@@ -726,7 +736,9 @@ typedef struct stPlayer
unsigned int ankhtime, ankhshieldobject;
stInventory inventory;
-} stPlayer;
+
+ stPlayer() { memset(this, 0, sizeof(stPlayer)); }
+};
typedef struct stShipQueue
{
@@ -845,7 +857,7 @@ typedef struct stShipQueue
#include "keenext.h"
#include "sdl/CSettings.h"
-typedef struct stCloneKeenPlus
+struct stCloneKeenPlus
{
stCommand Command[MAX_COMMANDS];
SDL_Joystick *Joystick;
@@ -857,7 +869,11 @@ typedef struct stCloneKeenPlus
stOption Option[NUM_OPTIONS];
unsigned short numGames;
unsigned short shutdown;
-}stCloneKeenPlus;
+
+ stCloneKeenPlus() : Joystick(NULL), GameData(NULL), numGames(0), shutdown(SHUTDOWN_NONE) {
+ memset(&Event, 0, sizeof(Event));
+ }
+};
// keen.c
void playgame_levelmanager(stCloneKeenPlus *pCKP);
diff --git a/src/menu.cpp b/src/menu.cpp
index ed50b0bca..2d372fe42 100644
--- a/src/menu.cpp
+++ b/src/menu.cpp
@@ -360,14 +360,6 @@ int mainmenu(stCloneKeenPlus *pCKP,int defaultopt)
return selection;
}
-void initialiazeDlgStruct(stDlgStruct *pDlgStruct)
-{
- pDlgStruct->OptionSwitch = (stOptionSwitch*) malloc(pDlgStruct->num_OptionSwitches*sizeof(stOptionSwitch));
- pDlgStruct->Separator = (stSeparator*) malloc(pDlgStruct->num_Separators*sizeof(stSeparator));
- pDlgStruct->StarterSwitch = (stStarterSwitch*) malloc(pDlgStruct->num_StarterSwitch*sizeof(stStarterSwitch));
- pDlgStruct->TextLine = (stTextLine*) malloc(pDlgStruct->num_TextLines*sizeof(stTextLine));
-}
-
int getDifficulty(stCloneKeenPlus *pCKP)
{
CDialog *DifficultyMenu;