diff --git a/src/.settings/org.eclipse.ltk.core.refactoring.prefs b/src/.settings/org.eclipse.ltk.core.refactoring.prefs
deleted file mode 100644
index d7586fd76..000000000
--- a/src/.settings/org.eclipse.ltk.core.refactoring.prefs
+++ /dev/null
@@ -1,3 +0,0 @@
-#Sat Jan 10 20:53:00 CET 2009
-eclipse.preferences.version=1
-org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false
diff --git a/src/CGame.cpp b/src/CGame.cpp
index 880221369..6aa24af59 100644
--- a/src/CGame.cpp
+++ b/src/CGame.cpp
@@ -19,17 +19,25 @@
#include "vorticon/CCredits.h"
#include "CLogFile.h"
#include "fileio.h"
+#include "fileio/CExeFile.h"
+#include "fileio/CTileLoader.h"
+#include "fileio/CPatcher.h"
#include "sdl/sound/CSound.h"
#include "sdl/CVideoDriver.h"
CGame::CGame() {
m_Episode = 0;
memset(m_DataDirectory,0,256);
- Latch = new CLatch();
+
+ TileLoader = NULL;
+ EGAGraphics = NULL;
+ m_Messages = NULL;
}
CGame::~CGame() {
- if(Latch){ delete Latch; Latch = NULL;}
+ if(EGAGraphics) delete EGAGraphics;
+ if(TileLoader) delete TileLoader;
+ if(m_Messages) delete m_Messages;
}
short CGame::runCycle(stCloneKeenPlus *pCKP)
@@ -39,7 +47,7 @@ short CGame::runCycle(stCloneKeenPlus *pCKP)
int eseq = 0;
int defaultopt = 0;
- initgamefirsttime(pCKP, Latch->getLatchHeader()->NumSprites);
+ initgamefirsttime(pCKP, EGAGraphics->getNumSprites());
initgame(pCKP);
g_pLogFile->ftextOut("Game starting...
");
@@ -107,7 +115,7 @@ short CGame::runCycle(stCloneKeenPlus *pCKP)
numplayers = 1;
defaultopt = 0;
current_demo = 1;
- initgamefirsttime(pCKP, Latch->getLatchHeader()->NumSprites);
+ initgamefirsttime(pCKP, EGAGraphics->getNumSprites());
loadinggame = 0;
playgame_levelmanager(pCKP);
break;
@@ -115,7 +123,7 @@ short CGame::runCycle(stCloneKeenPlus *pCKP)
defaultopt = 0;
current_demo = 1;
numplayers = 2;
- initgamefirsttime(pCKP, Latch->getLatchHeader()->NumSprites);
+ initgamefirsttime(pCKP, EGAGraphics->getNumSprites());
loadinggame = 0;
playgame_levelmanager(pCKP);
break;
@@ -126,7 +134,7 @@ short CGame::runCycle(stCloneKeenPlus *pCKP)
defaultopt = 0;
current_demo = 1;
numplayers = 1; // here was 2. Why was that? I don't understand
- initgamefirsttime(pCKP, Latch->getLatchHeader()->NumSprites);
+ initgamefirsttime(pCKP, EGAGraphics->getNumSprites());
playgame_levelmanager(pCKP);
}
break;
@@ -159,7 +167,7 @@ short CGame::runCycle(stCloneKeenPlus *pCKP)
case MAINMNU_TIMEOUT:
case MAINMNU_DEMO:
- retval = play_demo(current_demo, pCKP, Latch->getLatchHeader()->NumSprites);
+ retval = play_demo(current_demo, pCKP, EGAGraphics->getNumSprites());
if (retval==DEMO_RESULT_FILE_BAD)
{
@@ -215,11 +223,39 @@ int CGame::loadResources(unsigned short Episode, char *DataDirectory)
m_Episode = Episode;
memcpy(m_DataDirectory, DataDirectory, 256);
- // Decode the graphics for the game (EGALATCH, EGASPRIT)
- if (Latch->loadGraphics(Episode, DataDirectory)) return 1;
+ if( ( *(DataDirectory+strlen(DataDirectory)-1) != '/' ) && strlen(DataDirectory) > 0)
+ strcat(DataDirectory,"/");
+ // Decode the entire graphics for the game (EGALATCH, EGASPRIT)
+ EGAGraphics = new CEGAGraphics(Episode, DataDirectory); // Path is relative to the data dir
+ if(!EGAGraphics) return 1;
+
+ EGAGraphics->loadData();
+
+ // Get the EXE of the game and decompress it if needed.
+ CExeFile *ExeFile = new CExeFile(Episode, DataDirectory);
+ ExeFile->readData();
+ int version = ExeFile->getEXEVersion();
+ g_pLogFile->ftextOut("Commander Keen Episode %d (Version %d.%d) was detected.
", Episode, version/100,version%100);
+ if(version == 134) g_pLogFile->ftextOut("This version of the game is not supported!
");
+
+ // Patch the EXE-File-Data directly in the memory.
+ CPatcher *Patcher = new CPatcher(Episode, ExeFile->getEXEVersion(), ExeFile->getData(), DataDirectory);
+ Patcher->patchMemory();
+ delete Patcher;
+
+ // Load tile attributes.
+ if(TileLoader) delete TileLoader;
+ TileLoader = new CTileLoader(Episode, ExeFile->getEXEVersion(), ExeFile->getData());
+ if(!TileLoader->load()) return 1;
+
+ // load the strings. TODO: After that this one will replace loadstrings
+ //m_Messages = new CMessages(); delete ExeFile;
+ //m_Messages->readData(char *buf, int episode, int version);
loadstrings("strings.dat");
+ delete ExeFile;
+
// Load the sound data
int ok;
ok = g_pSound->loadSoundData(m_Episode, DataDirectory);
@@ -227,14 +263,17 @@ int CGame::loadResources(unsigned short Episode, char *DataDirectory)
return 0;
}
+void CGame::freeResources(void)
+{
+ if(EGAGraphics) { delete EGAGraphics; EGAGraphics = NULL; }
+}
+
void CGame::preallocateCKP(stCloneKeenPlus *pCKP)
{
// This function prepares the CKP Structure so that the it is allocated in the memory.
pCKP->numGames = 0;
pCKP->Resources.GameSelected = 0;
- TileProperty = NULL;
-
pCKP->GameData = NULL;
pCKP->GameData = new stGameData[1];
@@ -254,9 +293,3 @@ void CGame::preallocateCKP(stCloneKeenPlus *pCKP)
player[0].x = player[0].y = 0;
}
-
-
-
-
-CLatch *CGame::getLatch(void)
-{ return Latch; }
diff --git a/src/CGame.h b/src/CGame.h
index 60469eebc..6dd5ce2e0 100644
--- a/src/CGame.h
+++ b/src/CGame.h
@@ -9,7 +9,8 @@
#define CGAME_H_
#include
-#include "CLatch.h"
+#include "vorticon/CEGAGraphics.h"
+#include "vorticon/CMessages.h"
class CGame {
public:
@@ -17,9 +18,9 @@ public:
virtual ~CGame();
int loadResources(unsigned short Episode, char *DataDirectory);
+ void freeResources(void);
short runCycle(stCloneKeenPlus *pCKP);
void preallocateCKP(stCloneKeenPlus *pCKP);
- CLatch *getLatch(void);
private:
static const unsigned short MAX_TEXT_LENGTH = 256;
@@ -27,7 +28,9 @@ private:
char m_DataDirectory[MAX_TEXT_LENGTH];
int current_demo;
- CLatch *Latch;
+ CEGAGraphics *EGAGraphics;
+ CMessages *m_Messages;
+ CTileLoader *TileLoader;
};
#endif /* CGAME_H_ */
diff --git a/src/CGraphics.cpp b/src/CGraphics.cpp
index 723888d92..6af7864fa 100644
--- a/src/CGraphics.cpp
+++ b/src/CGraphics.cpp
@@ -115,6 +115,9 @@ void CGraphics::drawTile(int x, int y, unsigned int t)
memset(offset, COLOUR_MASK, 16);
offset+=512;
}
+
+ //HQBitmap->updateHQBitmap(g_pVideoDriver->getScrollSurface(),x,y);
+
}
else
{
@@ -161,7 +164,7 @@ unsigned int xstart,ystart;
{
if (tiledata[tmask][ya][xa] != 15)
{
- //scrollbuffer[bufoffY+bufoffX] = tiledata[til][ya][xa];
+ scrollbuffer[bufoffY+bufoffX] = tiledata[til][ya][xa];
}
bufoffX = (bufoffX+1)&511;
}
@@ -552,9 +555,7 @@ unsigned char *bmdataptr;
int CGraphics::getBitmapNumberFromName(const char *bmname)
{
-
- // TODO: Implement Code for Introduction Screen
-int i;
+ int i;
for(i=0;iupdateHQBitmap(g_pVideoDriver->getBGLayerSurface(),scroll_x-32,scroll_y-32);
+ {
+ SDL_Rect srcrect;
+ //SDL_Rect dstrect;
+
+ srcrect.x = scroll_x-32;
+ srcrect.y = scroll_y-32;
+ srcrect.w = g_pVideoDriver->getBGLayerSurface()->w;
+ srcrect.h = g_pVideoDriver->getBGLayerSurface()->h;
+
+ HQBitmap->updateHQBitmap(g_pVideoDriver->getBGLayerSurface(), &srcrect, NULL);
+ }
}
void CGraphics::loadHQGraphics(unsigned char episode, unsigned char level, char *datadir)
diff --git a/src/CLatch.cpp b/src/CLatch.cpp
index 1a52c7008..6f762702f 100644
--- a/src/CLatch.cpp
+++ b/src/CLatch.cpp
@@ -9,11 +9,13 @@
#include
#include
#include "CLatch.h"
+#include "vorticon/CPlanes.h"
#include "fileio.h"
#include "keen.h"
#include "keenext.h"
#include "CLogFile.h"
+//#include "vorticon/CEGAGraphics.h"
CLatch::CLatch() {
SpriteTable = NULL;
@@ -70,6 +72,13 @@ char CLatch::loadHeader(int episode, const char *path)
sprintf(fname, "%s%d", buffer,episode);
+ /*CEGAGraphics *EGAGraphics;
+
+ EGAGraphics = new CEGAGraphics(episode);
+
+ EGAGraphics->loadData();
+
+ delete EGAGraphics;*/
headfile = fopen(fname, "rb");
if (!headfile)
@@ -142,6 +151,7 @@ char CLatch::loadHeader(int episode, const char *path)
for(j=0;j<16;j++) SpriteTable[i].Name[j] = fgetc(headfile);
// for some reason each sprite occurs 4 times in the table.
// we're only interested in the first occurance.
+ // These are copies for smoother rendering. Not needed since SDL and HW_SURFACE
for(j=0;j<3;j++)
{
for(k=0;k < static_cast(sizeof(SpriteHead));k++) fgetc(headfile);
@@ -190,7 +200,7 @@ char CLatch::loadHeader(int episode, const char *path)
}
-// load the EGAHEAD file
+// load the EGALATCH file
char CLatch::load(int episode, const char *path)
{
@@ -204,7 +214,6 @@ unsigned long RawDataSize;
char buffer[256];
-
formatPathString(buffer,path);
strcat(buffer,"egalatch.ck");
@@ -234,7 +243,6 @@ char buffer[256];
if (LatchHeader.Compressed)
{
g_pLogFile->ftextOut("latch_loadlatch(): Decompressing...
");
- fseek(latchfile, 6, SEEK_SET);
if (lz_decompress(latchfile, (unsigned char*) RawData)) return 1;
}
else
@@ -261,7 +269,8 @@ char buffer[256];
g_pLogFile->ftextOut("latch_loadlatch(): Decoding 8x8 tiles...
", fname);
// set up the getbit() function
- setplanepositions(plane1 + LatchHeader.Off8Tiles, \
+
+ CPlanes *Planes = new CPlanes(plane1 + LatchHeader.Off8Tiles, \
plane2 + LatchHeader.Off8Tiles, \
plane3 + LatchHeader.Off8Tiles, \
plane4 + LatchHeader.Off8Tiles, \
@@ -287,7 +296,7 @@ char buffer[256];
}
// read a bit out of the current plane, shift it into the
// correct position and merge it
- c |= (getbit(RawData, p) << p);
+ c |= (Planes->getbit(RawData, p) << p);
// map black pixels to color 16 because of the way the
// vorticon death sequence works in ep1
if (p==3 && c==0) c = 16;
@@ -297,11 +306,13 @@ char buffer[256];
}
}
+ delete Planes;
+
// ** read the 16x16 tiles **
g_pLogFile->ftextOut("latch_loadlatch(): Decoding 16x16 tiles...
", fname);
// set up the getbit() function
- setplanepositions(plane1 + LatchHeader.Off16Tiles, \
+ Planes = new CPlanes(plane1 + LatchHeader.Off16Tiles, \
plane2 + LatchHeader.Off16Tiles, \
plane3 + LatchHeader.Off16Tiles, \
plane4 + LatchHeader.Off16Tiles, \
@@ -323,7 +334,7 @@ char buffer[256];
{
c = tiledata[t][y][x];
}
- c |= (getbit(RawData, p) << p);
+ c |= (Planes->getbit(RawData, p) << p);
if (p==3 && c==0) c = 16;
tiledata[t][y][x] = c;
@@ -332,6 +343,8 @@ char buffer[256];
}
}
+ delete Planes;
+
// ** read the bitmaps **
g_pLogFile->ftextOut("latch_loadlatch(): Allocating %d bytes for bitmap data...
", BitmapBufferRAMSize);
BitmapData = new char[BitmapBufferRAMSize];
@@ -344,7 +357,7 @@ char buffer[256];
g_pLogFile->ftextOut("latch_loadlatch(): Decoding bitmaps...
", fname);
// set up the getbit() function
- setplanepositions(plane1 + LatchHeader.OffBitmaps, \
+ Planes = new CPlanes(plane1 + LatchHeader.OffBitmaps, \
plane2 + LatchHeader.OffBitmaps, \
plane3 + LatchHeader.OffBitmaps, \
plane4 + LatchHeader.OffBitmaps, \
@@ -380,7 +393,7 @@ char buffer[256];
{
c = *bmdataptr;
}
- c |= (getbit(RawData, p) << p);
+ c |= (Planes->getbit(RawData, p) << p);
if (p==3 && c==0) c = 16;
*bmdataptr = c;
bmdataptr++;
@@ -389,55 +402,17 @@ char buffer[256];
}
}
+ delete Planes;
+
if(RawData){ delete[] RawData; RawData = NULL;}
return 0;
}
-// initilizes the positions getbit will retrieve data from
-void CLatch::setplanepositions(unsigned long p1, unsigned long p2, unsigned long p3,\
- unsigned long p4, unsigned long p5)
-{
-int i;
- getbit_bytepos[0] = p1;
- getbit_bytepos[1] = p2;
- getbit_bytepos[2] = p3;
- getbit_bytepos[3] = p4;
- getbit_bytepos[4] = p5;
- for(i=0;i<=4;i++)
- {
- getbit_bitmask[i] = 128;
- }
-}
// retrieves a bit from plane "plane". the positions of the planes
// should have been previously initilized with setplanepositions()
-unsigned char CLatch::getbit(char *buf, unsigned char plane)
-{
-int retval;
-int byt;
- if (!getbit_bitmask[plane])
- {
- getbit_bitmask[plane] = 128;
- getbit_bytepos[plane]++;
- }
-
- byt = buf[getbit_bytepos[plane]];
-
- if (byt & getbit_bitmask[plane])
- {
- retval = 1;
- }
- else
- {
- retval = 0;
- }
-
- getbit_bitmask[plane] >>= 1;
-
- return retval;
-}
char CLatch::loadSprites(int episode, const char *path)
@@ -447,10 +422,8 @@ unsigned long plane1, plane2, plane3, plane4, plane5;
char fname[80];
int x,y,s,c,p;
unsigned long RawDataSize;
-/*int i;
-unsigned char ch;*/
-
char buffer[256];
+CPlanes *Planes;
formatPathString(buffer,path);
@@ -478,7 +451,6 @@ char buffer[256];
if (LatchHeader.Compressed)
{
g_pLogFile->ftextOut("latch_loadsprites(): Decompressing...
");
- fseek(spritfile, 6, SEEK_SET);
if (lz_decompress(spritfile, (unsigned char*) RawData)) return 1;
}
else
@@ -506,7 +478,7 @@ char buffer[256];
g_pLogFile->ftextOut("latch_loadsprites(): Decoding sprites...
", fname);
// set up the getbit() function
- setplanepositions(plane1 + LatchHeader.OffSprites, \
+ Planes = new CPlanes(plane1 + LatchHeader.OffSprites, \
plane2 + LatchHeader.OffSprites, \
plane3 + LatchHeader.OffSprites, \
plane4 + LatchHeader.OffSprites, \
@@ -535,7 +507,7 @@ char buffer[256];
{
c = sprites[s].imgdata[y][x];
}
- c |= (getbit(RawData, p) << p);
+ c |= (Planes->getbit(RawData, p) << p);
if (p==3 && c==0) c = 16;
sprites[s].imgdata[y][x] = c;
}
@@ -552,11 +524,12 @@ char buffer[256];
{
for(x=0;xgetbit(RawData, 4));
}
}
}
+ delete Planes;
return 0;
}
diff --git a/src/CLatch.h b/src/CLatch.h
index 7322da3d8..e3bfecee9 100644
--- a/src/CLatch.h
+++ b/src/CLatch.h
@@ -58,9 +58,6 @@ private:
unsigned long BitmapBufferRAMSize;
- unsigned long getbit_bytepos[5];
- unsigned char getbit_bitmask[5];
-
EgaHead LatchHeader;
SpriteHead *SpriteTable;
BitmapHead *BitmapTable;
diff --git a/src/CLogFile.h b/src/CLogFile.h
index 9a41ccf63..f9956121d 100644
--- a/src/CLogFile.h
+++ b/src/CLogFile.h
@@ -8,9 +8,7 @@
#ifndef CLOGFILE_H_
#define CLOGFILE_H_
-#define REVISION "CloneKeenPlus Beta v0.2.9.7 (Commander Genius)"
-
-#include
+#define REVISION "Commander Genius Prerelease v0.3"
#include "CSingleton.h"
#define g_pLogFile CLogFile::Get()
diff --git a/src/ai/mother.cpp b/src/ai/mother.cpp
index 5b74915d8..bbfaebc58 100644
--- a/src/ai/mother.cpp
+++ b/src/ai/mother.cpp
@@ -11,8 +11,8 @@
#define MOTHER_HURT 2
#define MOTHER_DEAD 3
-#define MOTHER_WALK_ANIM_RATE 40
-#define MOTHER_WALK_SPD 4
+#define MOTHER_WALK_ANIM_RATE 30
+#define MOTHER_WALK_SPD 3
#define MOTHER_SPIT_PROB 1000
#define MOTHER_SPIT_SHOW_TIME 100
diff --git a/src/ai/yorp.cpp b/src/ai/yorp.cpp
index b3ddb1c09..00f5706cd 100644
--- a/src/ai/yorp.cpp
+++ b/src/ai/yorp.cpp
@@ -81,7 +81,7 @@ char numlooks;
// half of the yorp
if ((player[objects[o].touchedBy].y>>CSF)+16 < (objects[o].y>>CSF)+12)
{
- player[objects[o].touchedBy].ppogostick = 0; // No pogo, You get it disabled at this point
+ player[objects[o].touchedBy].ppogostick = false; // No pogo, You get it disabled at this point
g_pSound->playStereofromCoord(SOUND_YORP_STUN, PLAY_NOW, objects[o].scrx);
objects[o].ai.yorp.state = YORP_STUNNED;
objects[o].ai.yorp.looktimes = 0;
diff --git a/src/eseq_ep2.cpp b/src/eseq_ep2.cpp
index 56bbd0e0b..71e4b0ffa 100644
--- a/src/eseq_ep2.cpp
+++ b/src/eseq_ep2.cpp
@@ -58,6 +58,8 @@ int x, y, t, o, i;
int tantalus_animframe, tantalus_animtimer;
int state, timer, spawnedcount;
+ o=0;
+
fade.mode = FADE_GO;
fade.rate = FADE_NORM;
fade.dir = FADE_OUT;
diff --git a/src/fileio.cpp b/src/fileio.cpp
index 475e399af..8f7cc704b 100644
--- a/src/fileio.cpp
+++ b/src/fileio.cpp
@@ -10,18 +10,16 @@
#include "sdl/sound/CSound.h"
#include "hqp/CMusic.h"
#include "include/fileio.h"
-#include "include/fileio/lzexe.h"
#include "include/fileio/rle.h"
#include "vorticon/CPlayer.h"
#include "CLogFile.h"
#include "CGraphics.h"
#include
+#include
+#include
extern CPlayer *Player;
-int numtiles;
-int **TileProperty; // This version will replace the old stTile Structure and save memory
-
unsigned int curmapx, curmapy;
unsigned char mapdone;
void addmaptile(unsigned int t)
@@ -37,6 +35,56 @@ void addmaptile(unsigned int t)
}
}
+bool renameFilenamesLowerCase(const char *dir_name)
+{
+#ifdef TARGET_WIN32
+ return true;
+#else
+ DIR *p_Dir;
+ char newname[256];
+ char buf[256];
+ struct dirent *dp;
+
+ memset(newname,0,256);
+ strcpy(buf,dir_name);
+
+ if(buf[0] == '\0')
+ strcpy(buf,"./");
+
+ chdir("data");
+
+ if((p_Dir = opendir(buf))==NULL)
+ return false;
+
+ bool retval = true;
+ // This function checks if all the files in the directory are lower case.
+ // If they aren't rename them
+ while((dp = readdir(p_Dir)) != NULL)
+ {
+ if(dp->d_type == DT_REG)
+ {
+ strcpy(newname,dp->d_name);
+
+ int len = strlen(newname);
+ for(int pos=0 ; pos < len ; pos++ )
+ if(newname[pos] >= 'A' && newname[pos] <= 'Z')
+ newname[pos] += ('a'-'A');
+
+ if(strncmp(newname,dp->d_name,strlen(dp->d_name)) != 0)
+ if(rename(dp->d_name,newname) != -1)
+ retval &= true;
+ }
+ }
+
+ closedir(p_Dir);
+
+ chdir("../");
+
+ return retval;
+
+#endif
+}
+
short checkConsistencyofGameData(stGameData *p_GameData)
{
short ok = 0;
@@ -79,7 +127,14 @@ short checkConsistencyofGameData(stGameData *p_GameData)
sprintf(p_GameData->FileList[24],"sounds.ck%d",p_GameData->Episode);
}
- // Now check if they really exist!
+ // Rename all the the files in the directory to lower case
+ if(!renameFilenamesLowerCase(p_GameData->DataDirectory))
+ {
+ g_pLogFile->ftextOut(PURPLE,"WARNING: There was an error while trying to format correctly the game data.");
+ g_pLogFile->ftextOut(PURPLE,"Please check, if you have write permissions on the game data directory and it is accessible
");
+ }
+
+ // Finally check if they really exist!
char buf[MAX_STRING_LENGTH];
int c=0;
for(c = 0 ; c < MAX_NUMBER_OF_FILES ; c++)
@@ -94,7 +149,6 @@ short checkConsistencyofGameData(stGameData *p_GameData)
strcat(buf,"/");
strcat(buf,p_GameData->FileList[c]);
-
if((fp = fopen(buf,"r")) != NULL)
{
fclose(fp);
@@ -145,8 +199,50 @@ int o;
levelmarker: ;
if ((t&0x7fff) < 256 && pCKP->Control.levelcontrol.levels_completed[t&0x00ff])
{
- map.objectlayer[curmapx][curmapy] = 0;
- map.mapdata[curmapx][curmapy] = tiles[map.mapdata[curmapx][curmapy]].chgtile;
+ if(!options[OPT_LVLREPLAYABILITY].value)
+ map.objectlayer[curmapx][curmapy] = 0;
+ else
+ map.objectlayer[curmapx][curmapy] = t;
+
+ int newtile = tiles[map.mapdata[curmapx][curmapy]].chgtile;
+
+ // Consistency check! Some Mods have issues with that.
+ if(pCKP->Control.levelcontrol.episode == 1 || pCKP->Control.levelcontrol.episode == 2)
+ {
+ if(newtile<77 || newtile>81)
+ // something went wrong. Use default tile
+ newtile = 77;
+
+ // try to guess, if it is a 32x32 (4 16x16) Tile
+ if(map.mapdata[curmapx-1][curmapy-1] == (unsigned int) newtile &&
+ map.mapdata[curmapx][curmapy-1] == (unsigned int) newtile &&
+ map.mapdata[curmapx-1][curmapy] == (unsigned int) newtile)
+ {
+ map.mapdata[curmapx-1][curmapy-1] = 78; //ul
+ map.mapdata[curmapx][curmapy-1] = 79; //ur
+ map.mapdata[curmapx-1][curmapy] = 80; //bl
+ newtile = 81; // br. this one
+ }
+ }
+ else if(pCKP->Control.levelcontrol.episode == 3)
+ {
+ if(newtile<52 || newtile>56)
+ // something went wrong. Use default tile
+ newtile = 56;
+ // try to guess, if it is a 32x32 (4 16x16) Tile
+ if(map.mapdata[curmapx-1][curmapy-1] == (unsigned int) newtile &&
+ map.mapdata[curmapx][curmapy-1] == (unsigned int) newtile &&
+ map.mapdata[curmapx-1][curmapy] == (unsigned int) newtile)
+ {
+ map.mapdata[curmapx-1][curmapy-1] = 52; //bl
+ map.mapdata[curmapx][curmapy-1] = 53; //ur
+ map.mapdata[curmapx-1][curmapy] = 54; //ul
+ newtile = 55; // br. this one
+ }
+ }
+
+ map.mapdata[curmapx][curmapy] = newtile;
+
}
else
{
@@ -196,7 +292,6 @@ int o,x;
x = curmapx;
if (TileProperty[map.mapdata[x][curmapy+1]][BLEFT]) x--;
- //if (tiles[map.mapdata[x][curmapy+1]].solidl) x--;
spawn_object(x<<4<Control.levelcontrol.episode==3)
{
if(TileProperty[map.mapdata[curmapx][curmapy+1]][BLEFT])
- //if (tiles[map.mapdata[curmapx][curmapy+1]].solidl)
{
spawn_object(curmapx<<4<ftextOut("loadtileattributes() : Trying to read the tiles from \"%s\"
", fname);
-
- if( (fin = fopen(fname,"rb")) == NULL )
- {
- // No, try to read it from the exe-file
-
- sprintf(buf,"keen%d.exe",episode);
-
- formatPathString(fname,extrapath);
-
- strcat(fname,buf);
-
- g_pLogFile->ftextOut("loadtileattributes() : Extracting tile attributes from the exe file \"%s\"
", fname);
-
- if( (fin = fopen(fname,"rb")) != NULL )
- {
- int version;
- int offset;
-
- bufsize = unlzexe(fin, filebuf);
-
- rewind(fin);
-
- if ( bufsize == 0 ) // Program was not unpacked, so read it normally
- {
- for(i = 0; i < 512 ; i++) // I don't why this value (512), but it makes read mods correctly. At last Yorpius II
- getc(fin);
-
- while(!feof(fin))
- {
- filebuf[bufsize] = getc(fin);
- bufsize++;
- }
-
- bufsize--;
- }
-
-
- fclose(fin);
-
- version = getEXEVersion(episode, bufsize);
-
- g_pLogFile->ftextOut("Commander Keen Episode %d (Version %d.%d) was detected.
",episode,version/100,version%100);
-
- if(version < 0)
- {
- why_term_ptr = "loadtileattributes(): Unknown EXE-File. It is possible, that the exe-file is a mod. Please use an original exe-file.\nNot all Mods work with CKP";
- }
- else if(version == 134)
- {
- why_term_ptr = "loadtileattributes(): Sorry, but version 1.34 isn't supported! please use version 1.31";
- }
-
- if( episode == 1 && version == 110 )
- {
- offset = 0x131F8;
- numtiles = 611;
- }
- else if( episode == 1 && version == 131 )
- {
- offset = 0x130F8;
- numtiles = 611;
- }
- else if( episode == 1 && version == 134 )
- {
- offset = 0x00000;
- numtiles = 611;
- return -1;
- }
- else if( episode == 2 && version == 100 )
- {
- offset = 0x17938;
- numtiles = 689;
- }
- else if( episode == 2 && version == 131 )
- {
- offset = 0x17828;
- numtiles = 689;
- }
- else if( episode == 3 && version == 100 )
- {
- offset = 0x199F8;
- numtiles = 715;
- }
- else if( episode == 3 && version == 131 )
- {
- offset = 0x198C8;
- numtiles = 715;
- }
- else
- {
- crashflag = 1;
- why_term_ptr = "loadtileattributes(): Algorithm for extracting tiles is not supported for this version!";
- return 1;
- }
-
- memcpy(filebuf, filebuf + offset, 6*2*numtiles);
- }
- else
- {
- crashflag = 1;
- why_term_ptr = "loadtileattributes(): Error reading tiles!";
- return 1;
- }
- }
- else
- {
- // read from the tli file
- int bufsize;
-
- bufsize = 0;
-
- while(!feof(fin))
- {
- filebuf[bufsize] = getc(fin);
- bufsize++;
- }
- fclose(fin);
- }
-
- // Here we really start reading the tiles
- if(TileProperty != NULL)
- {
- for(i = 0 ; i < 1000 ; i++)
- {
- if(TileProperty[i] != NULL)
- free(TileProperty[i]);
- }
- free(TileProperty);
- }
-
- TileProperty = (int**) malloc(1000*sizeof(int*));
-
- for(i = 0 ; i < 1000 ; i++)
- {
- TileProperty[i] = NULL;
- TileProperty[i] = (int*) malloc(6*sizeof(int));
- }
-
- for(j=0 ; j < 1000 ; j++ )
- {
- for(i=0; i < 6 ; i++)
- TileProperty[j][i]=0;
- }
-
- if(TileProperty == NULL)
- {
- crashflag = 1;
- why_term_ptr = "loadtileattributes(): The memory couldn't be allocated for this version of game!";
- return 1;
- }
-
- for(i=0 ; i < 6 ; i++)
- {
- for(j=0 ; j < numtiles ; j++)
- {
- TileProperty[j][i] = filebuf[i*2*(numtiles)+2*j];
- TileProperty[j][i] += 256*filebuf[i*2*(numtiles)+2*j+1];
- }
- }
-
- free(filebuf);
-
- int value;
-
- for( j=0 ; j < (numtiles) ; j++ )
- {
- value = TileProperty[j][0];
-
- // stuff for animated tiles
- if(value == 1)
- {
- tiles[j].animOffset = 0; // starting offset from the base frame
- }
- else if( value == 2 )
- {
- tiles[j].animOffset = 0; // starting offset from the base frame
- j++;
- tiles[j].animOffset = 1; // starting offset from the base frame
- }
- else
- {
- tiles[j].animOffset = 0; // starting offset from the base frame
- j++;
- tiles[j].animOffset = 1; // starting offset from the base frame
- j++;
- tiles[j].animOffset = 2; // starting offset from the base frame
- j++;
- tiles[j].animOffset = 3; // starting offset from the base frame
- }
- }
-
- sprintf(fname, "ep%dattr.dat", episode);
-
-
- fp = fopen(fname, "rb");
- if (!fp)
- {
- crashflag = 1;
- crashflag2 = episode;
- why_term_ptr = "loadtileattributes(): Cannot open tile attribute file! Episode in flag2.";
- return 1;
- }
-
- // load in the tile attributes
- for(t=0;t numtiles)
- tiles[t].chgtile = 0;
- }
- fclose(fp);
-
- return 0;
-}
-
char loadstrings_AddAttr(char *attr, int stringIndex)
{
char stAttrName[80];
diff --git a/src/fileio/CExeFile.cpp b/src/fileio/CExeFile.cpp
new file mode 100644
index 000000000..8b4d56428
--- /dev/null
+++ b/src/fileio/CExeFile.cpp
@@ -0,0 +1,222 @@
+/*
+ * CExeFile.cpp
+ *
+ * Created on: 17.07.2009
+ * Author: gerstrong
+ */
+
+#include "CExeFile.h"
+#include
+#include
+#include
+using namespace std;
+
+CExeFile::CExeFile(int episode, char *datadirectory) {
+ m_episode = episode;
+ m_datadirectory = datadirectory;
+ m_data = NULL;
+}
+
+CExeFile::~CExeFile() {
+ if(m_data) delete m_data;
+}
+
+bool CExeFile::readData()
+{
+ char filename[256];
+ unsigned char *m_data_temp;
+
+ sprintf(filename, "data/%skeen%d.exe", m_datadirectory, m_episode);
+
+ ifstream File(filename,ios::binary);
+
+ if(!File) return false;
+
+ File.seekg(0,ios::end);
+ m_datasize = File.tellg();
+ File.seekg(0,ios::beg);
+
+ m_data_temp = new unsigned char[m_datasize];
+ File.read((char*)m_data_temp, m_datasize);
+
+ File.close();
+
+ vector *decdata;
+ decdata = new vector;
+
+ if(unlzexe(m_data_temp, decdata))
+ {
+ m_datasize = decdata->size();
+ m_data = new unsigned char[m_datasize];
+ memcpy(m_data, decdata->data(), m_datasize);
+ }
+ else
+ {
+ m_datasize -= 512; // if already decompressed subtract the header
+ m_data = new unsigned char[m_datasize];
+ memcpy(m_data, m_data_temp+512,m_datasize);
+ }
+ delete m_data_temp;
+
+ if(!decdata->empty()) decdata->clear();
+ delete decdata;
+
+ return true;
+}
+
+int CExeFile::get_bit(int *p_bit_count, unsigned char *fin, int *posin)
+{
+ static unsigned short bits;
+ int bit;
+
+ bit = bits & 1;
+ (*p_bit_count)--;
+
+ if ((*p_bit_count) <= 0)
+ {
+ unsigned short a,b;
+ a = (unsigned char) fin[(*posin)++];
+ b = (unsigned char) fin[(*posin)++] << 8;
+ bits = a | b;
+
+ if ((*p_bit_count) == -1) /* special case for first bit word */
+ {
+ bit = bits & 1;
+ bits >>= 1;
+ }
+
+ (*p_bit_count) += 16;
+ }
+ else
+ bits >>= 1;
+
+ return bit;
+}
+
+// return how much was unpacked or zero if nothing was unpacked
+int CExeFile::unlzexe(unsigned char *fin, vector *outbuffer)
+{
+ int bit_count;
+ short offset;
+ int pos, repeat;
+ int posin = 0; // position of input
+
+ pos = 0;
+ bit_count = 0;
+
+ /* skip header */
+ posin = 32;
+
+ while (1)
+ {
+
+ if (get_bit(&bit_count, fin, &posin))
+ {
+ outbuffer->push_back(fin[posin]);
+ //outbuffer[pos] = fin[posin];
+ pos++;
+ posin++;
+ }
+ else
+ {
+ if (get_bit(&bit_count, fin, &posin))
+ {
+ unsigned char tmp[2];
+ memcpy(tmp,fin+posin,2);
+ posin+=2;
+ repeat = (tmp[1] & 0x07);
+
+ offset = ((tmp[1] & ~0x07) << 5) | tmp[0] | 0xE000;
+
+ if (repeat == 0)
+ {
+ repeat = fin[posin++];
+
+ if (repeat == 0)
+ break;
+ else if (repeat == 1)
+ continue;
+ else
+ repeat++;
+ }
+ else
+ repeat += 2;
+
+
+
+ }
+ else
+ {
+ repeat = get_bit(&bit_count, fin, &posin) << 1;
+ repeat |= get_bit(&bit_count, fin, &posin);
+ repeat += 2;
+ offset = fin[posin++] | 0xFF00;
+ }
+
+ while (repeat > 0)
+ {
+ outbuffer->push_back(outbuffer->at(pos + offset));
+ //outbuffer[pos] = outbuffer[pos + offset];
+ pos++;
+ repeat--;
+ }
+ }
+ }
+
+ return pos;
+}
+
+int CExeFile::getEXEVersion()
+{
+ switch (m_datasize)
+ {
+ case 99762:
+ if(m_episode != 1)
+ return -1;
+ else
+ return 110;
+ case 99972:
+ if(m_episode != 1)
+ return -1;
+ else
+ return 131;
+
+ case 398:
+ if(m_episode != 1)
+ return -1;
+ else
+ return 134;
+
+ case 118114:
+ if(m_episode != 2)
+ return -1;
+ else
+ return 100;
+
+ case 118160:
+
+ if(m_episode != 2)
+ return -1;
+ else
+ return 131;
+
+ case 127086:
+
+ if(m_episode != 3)
+ return -1;
+ else
+ return 100;
+
+ case 127104:
+ if(m_episode != 3)
+ return -1;
+ else
+ return 131;
+
+ default: return -2;
+ }
+}
+
+unsigned char* CExeFile::getData()
+{ return m_data; }
+
diff --git a/src/fileio/CExeFile.h b/src/fileio/CExeFile.h
new file mode 100644
index 000000000..347c3074d
--- /dev/null
+++ b/src/fileio/CExeFile.h
@@ -0,0 +1,36 @@
+/*
+ * CExeFile.h
+ *
+ * Created on: 17.07.2009
+ * Author: gerstrong
+ *
+ * This special class reads the whole exe-file
+ * into the memory and decompresses if necessary
+ */
+
+#ifndef CEXEFILE_H_
+#define CEXEFILE_H_
+
+#include
+using namespace std;
+
+class CExeFile {
+public:
+ CExeFile(int episode, char *datadirectory);
+ virtual ~CExeFile();
+
+ bool readData();
+ int getEXEVersion();
+ unsigned char* getData();
+
+private:
+ int m_datasize;
+ int m_episode;
+ unsigned char *m_data;
+ char *m_datadirectory;
+
+ int get_bit(int *p_bit_count, unsigned char *fin, int *posin);
+ int unlzexe(unsigned char *fin, vector *outbuffer);
+};
+
+#endif /* CEXEFILE_H_ */
diff --git a/src/fileio/CParser.cpp b/src/fileio/CParser.cpp
index 201bae93b..c717d8de8 100644
--- a/src/fileio/CParser.cpp
+++ b/src/fileio/CParser.cpp
@@ -60,7 +60,7 @@ bool CParser::loadParseFile(void) // Open, read the list and close the file
while(!feof(fp))
{
line = (char*) calloc(256,sizeof(char));
- fgets(line,256,fp);
+ fgets(line,256,fp); // No return value assigned. Be careful!
//fscanf(fp,"%s\n",line);
m_filebuffer.push_back(line);
m_isOpen = true;
diff --git a/src/fileio/CPatcher.cpp b/src/fileio/CPatcher.cpp
new file mode 100644
index 000000000..5fd930460
--- /dev/null
+++ b/src/fileio/CPatcher.cpp
@@ -0,0 +1,182 @@
+/*
+ * CPatcher.cpp
+ *
+ * Created on: 19.07.2009
+ * Author: gerstrong
+ */
+
+#include "CPatcher.h"
+#include
+#include
+#include
+
+CPatcher::CPatcher(int episode, int version,unsigned char *data, char *datadir) {
+ m_episode = episode;
+ m_version = version;
+ m_data = data;
+ strcpy(m_datadirectory, datadir);
+}
+
+CPatcher::~CPatcher() {
+ while(!m_TextList.empty())
+ {
+ delete *(m_TextList.begin());
+ m_TextList.pop_front();
+ }
+}
+
+void CPatcher::patchMemory()
+{
+ if(!loadPatchfile()) return;
+
+ // If the file was found and read into the m_TextList,
+ // then read out of the list the patch commands and apply them to the
+ // Exe-file data m_data
+
+ // change to the proper directory
+ chdir("data");
+ chdir(m_datadirectory);
+
+ // TODO: Extend this part further with more commands
+ while(!m_TextList.empty())
+ {
+ char line[256];
+
+ strcpy(line,*(m_TextList.begin()));
+
+ if(strncmp(line,"\%version",strlen("\%version")) == 0)
+ {
+ char *verstring;
+ char detected_version[5];
+
+ verstring = line + strlen("\%version");
+
+ sscanf(verstring,"%s",detected_version);
+
+ if((!strcmp(detected_version,"1.31") && m_version == 131 )
+ || (!strcmp(detected_version,"1.1") && m_version == 110 )
+ || !strcmp(detected_version,"ALL"))
+ {
+ while(!m_TextList.empty())
+ {
+ // Get the next line
+ strcpy(line,*(m_TextList.begin()));
+
+ // Now we really start to process the commands
+ if( strncmp(line,"\%patchfile",strlen("\%patchfile")) == 0 )
+ {
+ unsigned long offset;
+ char *newbuf;
+ char patch_file_name[256];
+ newbuf = line + strlen("\%patchfile");
+ sscanf(newbuf,"%lx %s",&offset,patch_file_name); // Only hexadecimal numbers supported
+ patchMemfromFile((const char*)patch_file_name,offset);
+ }
+
+ if(!m_TextList.empty())
+ {
+ delete *(m_TextList.begin());
+ m_TextList.pop_front();
+ }
+ }
+ }
+ }
+
+ if(!m_TextList.empty())
+ {
+ delete *(m_TextList.begin());
+ m_TextList.pop_front();
+ }
+ }
+
+ // change back to "data" dir
+ char curdir[256];
+ while(1)
+ {
+ char *reldir;
+ getcwd(curdir,256);
+ reldir = curdir+strlen(curdir)-strlen("data");
+ if(strcmp(reldir,"data"))
+ chdir("..");
+ else
+ break;
+ }
+ chdir("..");
+}
+
+bool CPatcher::loadPatchfile()
+{
+ bool ret = false;
+ chdir("data");
+ chdir(m_datadirectory);
+ // Detect the patchfile
+ DIR *dir = opendir(".");
+ struct dirent *dp;
+
+ if(dir)
+ {
+ while( ( dp = readdir(dir) ) )
+ {
+ if(strstr(dp->d_name,".pat"))
+ {
+ // The file was found! now read it into the memory!
+
+ char* buf;
+ ifstream Patchfile(dp->d_name);
+
+ while(!Patchfile.eof())
+ {
+ buf = new char[256];
+ Patchfile.getline(buf,256);
+ m_TextList.push_back(buf);
+ }
+
+ Patchfile.close();
+
+ ret = true;
+ break;
+ }
+ }
+ }
+
+ char curdir[256];
+ while(1)
+ {
+ char *reldir;
+ getcwd(curdir,256);
+ reldir = curdir+strlen(curdir)-strlen("data");
+ if(strcmp(reldir,"data"))
+ chdir("..");
+ else
+ break;
+ }
+
+ chdir("..");
+ closedir(dir);
+
+ return ret;
+}
+
+void CPatcher::patchMemfromFile(const char *patch_file_name, int offset)
+{
+ unsigned char *buf_to_patch;
+ unsigned char byte;
+
+ ifstream Patchfile(patch_file_name, ios::binary);
+
+ if(!Patchfile) return;
+
+ buf_to_patch = m_data + offset;
+
+ // TODO: Add a routine which checks the sizes of the file.
+ long counter = 0;
+
+ while(!Patchfile.eof())
+ {
+ byte = (unsigned char) Patchfile.get();
+ memcpy(buf_to_patch+counter,&byte,1); // one byte every time ;-)
+ counter++;
+ }
+
+ Patchfile.close();
+}
diff --git a/src/fileio/CPatcher.h b/src/fileio/CPatcher.h
new file mode 100644
index 000000000..b47565619
--- /dev/null
+++ b/src/fileio/CPatcher.h
@@ -0,0 +1,35 @@
+/*
+ * CPatcher.h
+ *
+ * Created on: 19.07.2009
+ * Author: gerstrong
+ */
+
+#ifndef CPATCHER_H_
+#define CPATCHER_H_
+
+#include
+using namespace std;
+
+class CPatcher {
+public:
+ CPatcher(int episode, int version,unsigned char *data, char *datadir);
+ virtual ~CPatcher();
+
+ void patchMemory();
+ void patchMemfromFile(const char *patch_file_name, int offset);
+
+private:
+
+ bool loadPatchfile();
+
+ int m_episode;
+ int m_version;
+ unsigned char *m_data;
+ char m_datadirectory[256];
+
+ list m_TextList;
+
+};
+
+#endif /* CPATCHER_H_ */
diff --git a/src/fileio/CTileLoader.cpp b/src/fileio/CTileLoader.cpp
new file mode 100644
index 000000000..a71e93363
--- /dev/null
+++ b/src/fileio/CTileLoader.cpp
@@ -0,0 +1,203 @@
+/*
+ * CTileLoader.cpp
+ *
+ * Created on: 19.07.2009
+ * Author: gerstrong
+ */
+
+#include "CTileLoader.h"
+#include "../CLogFile.h"
+
+#include
+
+#define MAX_STRING_LENGTH 256
+extern stTile tiles[MAX_TILES+1];
+
+CTileLoader::CTileLoader(int episode, int version, unsigned char *data) {
+ TileProperty = NULL;
+ m_episode = episode;
+ m_version = version;
+ m_data = data;
+ m_offset = 0;
+}
+
+CTileLoader::~CTileLoader() {
+ // Here we really start reading the tiles
+ if(TileProperty != NULL)
+ {
+ for(int i = 0 ; i < 1000 ; i++)
+ {
+ if(TileProperty[i] != NULL)
+ {
+ delete [] TileProperty[i];
+ TileProperty[i] = NULL;
+ }
+ }
+ delete [] TileProperty;
+ TileProperty = NULL;
+ }
+}
+
+bool CTileLoader::setProperOffset()
+{
+ // Identify the offset
+ switch (m_episode)
+ {
+ case 1:
+ {
+ numtiles = 611;
+ switch(m_version)
+ {
+ case 110: m_offset = 0x131F8; break;
+ case 131: m_offset = 0x130F8; break;
+ case 134: m_offset = 0x130F8; // This is incorrect!
+ g_pLogFile->textOut(PURPLE,"If you want to use Episode 1 Version 1.34, assure that is was unpacked before (with unpklite for example).
");
+ break;
+ }
+ break;
+ }
+ case 2:
+ {
+ numtiles = 689;
+ switch(m_version)
+ {
+ case 100: m_offset = 0x17938; break;
+ case 131: m_offset = 0x17828; break;
+ }
+ break;
+ }
+ case 3:
+ {
+ numtiles = 715;
+ switch(m_version)
+ {
+ case 100: m_offset = 0x199F8; break;
+ case 131: m_offset = 0x198C8; break;
+ }
+ break;
+ }
+ default:
+ {
+ g_pLogFile->textOut(PURPLE,"CAUTION: The version was not detected correctly. The game muy be unplayable!
");
+ return false;
+ }
+ }
+ m_data += m_offset;
+
+ return true;
+}
+
+bool CTileLoader::load()
+{
+ int t,a,b;
+ char fname[MAX_STRING_LENGTH];
+ int i,j; // standard counters
+
+ if(!setProperOffset()) return false;
+
+ //TileProperty = (int**) malloc(1000*sizeof(int*));
+ TileProperty = new int*[1000];
+
+ for(i = 0 ; i < 1000 ; i++)
+ {
+ TileProperty[i] = NULL;
+ TileProperty[i] = new int[6];
+ }
+
+ for(j=0 ; j < 1000 ; j++ )
+ {
+ for(i=0; i < 6 ; i++)
+ TileProperty[j][i]=0;
+ }
+
+ if(TileProperty == NULL)
+ {
+ g_pLogFile->textOut(RED,"TileLoader: The memory couldn't be allocated for this version of game!
");
+ return false;
+ }
+
+ for(i=0 ; i < 6 ; i++)
+ {
+ for(j=0 ; j < numtiles ; j++)
+ {
+ TileProperty[j][i] = m_data[i*2*(numtiles)+2*j];
+ TileProperty[j][i] += m_data[i*2*(numtiles)+2*j+1]<<8;
+ }
+ }
+
+ int value;
+
+ for( j=0 ; j < numtiles ; j++ )
+ {
+ value = TileProperty[j][0];
+
+ // stuff for animated tiles
+ if(value == 1)
+ {
+ tiles[j].animOffset = 0; // starting offset from the base frame
+ }
+ else if( value == 2 )
+ {
+ tiles[j++].animOffset = 0; // starting offset from the base frame
+ tiles[j].animOffset = 1; // starting offset from the base frame
+ }
+ else
+ {
+ tiles[j++].animOffset = 0; // starting offset from the base frame
+ tiles[j++].animOffset = 1; // starting offset from the base frame
+ tiles[j++].animOffset = 2; // starting offset from the base frame
+ tiles[j].animOffset = 3; // starting offset from the base frame
+ }
+ }
+
+ sprintf(fname, "ep%dattr.dat", m_episode);
+
+ FILE *fp;
+ fp = fopen(fname, "rb");
+ if (!fp)
+ {
+ g_pLogFile->textOut(RED,"TileLoader: Cannot open tile attribute file!
");
+ return false;
+ }
+
+ // load additional information the tiles
+ for(t=0;t numtiles)
+ tiles[t].chgtile = 0;
+ }
+ fclose(fp);
+
+ // Those Tile data files are an good option, but they are not very well seen.
+ // Especially in mods. The one of Episode 2 has an error with items already
+ // I'm to lazy to write a program which fixes the file so a new assignTilePointer is
+ // used, which in future will replace the files making them obsolete
+ assignChangeTileAttribute(tiles);
+
+ return true;
+}
+
+void CTileLoader::assignChangeTileAttribute(stTile *tile)
+{
+ // This special call is used for workarounds which are wrong in the tiles attributes file of CG.
+ // I hope those attributes can be read out of the exe-files in future.
+ switch(m_episode)
+ {
+ case 1:
+ {
+ break;
+ }
+ case 2:
+ {
+ for(int i=306 ; i<=311 ; i++) // Workaround in Level 12 of Episode 2, where the tiles are solid after a taken item.
+ tile[i].chgtile = 276;
+ break;
+ }
+ case 3:
+ {
+ break;
+ }
+ }
+}
diff --git a/src/fileio/CTileLoader.h b/src/fileio/CTileLoader.h
new file mode 100644
index 000000000..ee6f976fb
--- /dev/null
+++ b/src/fileio/CTileLoader.h
@@ -0,0 +1,41 @@
+/*
+ * CTileLoader.h
+ *
+ * Created on: 19.07.2009
+ * Author: gerstrong
+ */
+
+#ifndef CTILELOADER_H_
+#define CTILELOADER_H_
+
+#define MAX_TILES 800
+
+extern int numtiles;
+extern int **TileProperty; // This version will replace the old stTile Structure and save memory
+
+typedef struct
+{
+ int masktile; // if nonzero, specifies a mask for this tile
+ int chgtile; // tile to change to when level completed (for wm)
+ // or tile to change to when picked up (in-level)
+ unsigned int animOffset; // starting offset from the base frame
+} stTile;
+
+class CTileLoader {
+public:
+ CTileLoader(int episode, int version, unsigned char *data);
+ virtual ~CTileLoader();
+
+ bool load();
+
+private:
+ int m_episode;
+ int m_version;
+ long m_offset;
+ unsigned char *m_data;
+
+ void assignChangeTileAttribute(stTile *tile);
+ bool setProperOffset();
+};
+
+#endif /* CTILELOADER_H_ */
diff --git a/src/fileio/lzexe.cpp b/src/fileio/lzexe.cpp
deleted file mode 100644
index d8d2530cf..000000000
--- a/src/fileio/lzexe.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * lzexe.c
- *
- * Created on: 24.01.2009
- * Author: gerstrong
- */
-
-#include
-#include
-
-int get_bit(int *p_bit_count, FILE **fin)
-{
- static unsigned short bits;
- int bit;
-
- bit = bits & 1;
- (*p_bit_count)--;
-
- if ((*p_bit_count) <= 0)
- {
- bits = getc(*fin) | getc(*fin) << 8;
-
- if ((*p_bit_count) == -1) /* special case for first bit word */
- {
- bit = bits & 1;
- bits >>= 1;
- }
-
- (*p_bit_count) += 16;
- }
- else
- bits >>= 1;
-
- return bit;
-}
-
-int getEXEVersion(int episode, int bufsize)
-{
- switch (bufsize)
- {
- case 99762:
- if(episode != 1)
- return -1;
- else
- return 110;
- case 99972:
- if(episode != 1)
- return -1;
- else
- return 131;
-
- case 398:
- if(episode != 1)
- return -1;
- else
- return 134;
-
- case 118114:
- if(episode != 2)
- return -1;
- else
- return 100;
-
- case 118160:
-
- if(episode != 2)
- return -1;
- else
- return 131;
-
- case 127086:
-
- if(episode != 3)
- return -1;
- else
- return 100;
-
- case 127104:
- if(episode != 3)
- return -1;
- else
- return 131;
-
- default: return -2;
- }
-
-}
-
-// return how much was unpacked or zero if nothing was unpacked
-int unlzexe(FILE *fin, unsigned char *outbuffer)
-{
- int bit_count;
- short offset;
- int pos, repeat;
-
- pos = 0;
- bit_count = 0;
-
- /* skip header */
- fseek(fin, 32, SEEK_SET);
-
- while (1)
- {
-
- if (get_bit(&bit_count, &fin))
- {
- outbuffer[pos++] = getc(fin);
- }
- else
- {
- if (get_bit(&bit_count, &fin))
- {
- unsigned char tmp[2];
- fread(tmp, 1, 2, fin);
- repeat = (tmp[1] & 0x07);
-
- offset = ((tmp[1] & ~0x07) << 5) | tmp[0] | 0xE000;
-
- if (repeat == 0)
- {
- repeat = getc (fin);
-
-
- if (repeat == 0)
- break;
- else if (repeat == 1)
- continue;
- else
- repeat++;
- }
- else
- repeat += 2;
- }
- else
- {
- repeat = ((get_bit(&bit_count, &fin) << 1) | get_bit(&bit_count, &fin)) + 2;
- offset = getc(fin) | 0xFF00;
- }
-
- while (repeat > 0)
- {
- outbuffer[pos] = outbuffer[pos + offset];
- pos++;
- repeat--;
- }
- }
- }
-
- return pos;
-}
diff --git a/src/fileio/story.cpp b/src/fileio/story.cpp
index 41324761f..dddb22231 100644
--- a/src/fileio/story.cpp
+++ b/src/fileio/story.cpp
@@ -9,8 +9,8 @@
*/
#include "../keen.h"
-#include "../include/fileio/lzexe.h"
#include "../include/fileio.h"
+#include "../fileio/CExeFile.h"
#include "../CLogFile.h"
int readStoryText(char **ptext, int episode, char *path)
@@ -32,27 +32,11 @@ int readStoryText(char **ptext, int episode, char *path)
if((fp=fopen(buf,"rb"))!=NULL)
{
unsigned char *filebuf;
- int bufsize;
+ int startflag=0, endflag=0; // where story begins and ends!
- filebuf = (unsigned char*) malloc(500000*sizeof(unsigned char));
-
- bufsize = unlzexe(fp, filebuf);
-
- rewind(fp);
-
- if ( bufsize == 0 ) // Program was not unpacked, so read it normally
- {
- while(!feof(fp))
- {
- filebuf[bufsize] = getc(fp);
- bufsize++;
- }
- }
- fclose(fp);
-
- int startflag=0, endflag=0, version=0; // where story begins and ends!
-
- version = getEXEVersion(episode, bufsize);
+ CExeFile *ExeFile = new CExeFile(episode, buf2);
+ ExeFile->readData();
+ filebuf = ExeFile->getData();
if(episode == 2)
{
@@ -74,8 +58,7 @@ int readStoryText(char **ptext, int episode, char *path)
*ptext = (char*) malloc((endflag-startflag+10)*sizeof(char));
strncpy((*ptext),(char*)filebuf+startflag,(endflag-startflag)*sizeof(char));
}
-
- free(filebuf);
+ delete ExeFile;
return (endflag-startflag);
}
diff --git a/src/funcdefs.h b/src/funcdefs.h
index 9d380326d..5098f8c2c 100644
--- a/src/funcdefs.h
+++ b/src/funcdefs.h
@@ -19,7 +19,7 @@ void gamedo_fades(void);
//void gamepdo_wm_HandlePlayer(int cp);
//void gamepdo_InertiaAndFriction_Y(int cp);
//void gamepdo_wm_AllowEnterLevel(int cp);
-char wm_issolid(int xb, int yb);
+char wm_issolid(int xb, int yb, int *levels_completed);
// game.c
//void SetGameOver(void);
@@ -110,11 +110,8 @@ void sb_font_draw_inverse(unsigned char *text, int xoff, int yoff);
//unsigned long fgetl(FILE *fp);
//unsigned int loadmap(char *filename, char *path, int lvlnum, int isworldmap);
#include "fileio.h"
-char loadtiles(char *fname);
-char loadsprites(char *spritename);
-char loadfont(char *fontname);
-//char loadstrings(const char *fname);
-char loadtileattributes(int episode, char *extrapath);
+
+bool loadtileattributes(int episode, int version, unsigned char *filebuf);
int freestrings(void);
char* getstring(const char *name);
int GetStringAttribute(const char *stringName, const char *attrName);
diff --git a/src/game.cpp b/src/game.cpp
index a682fb5f2..1c49f410b 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -1,1497 +1,1490 @@
-/* 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;
-short usedinfobox;
-
-// 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/*,o,x,y,c*/;
-
- int enter,lastquit;
- //char buf[256];
- /*unsigned long oldtimer;
- unsigned int temp;
- char spacedownlasttime=0;
- char mpskiptimer=0,mpskip=200;*/
-
- if (player[0].x==0 || player[0].y==0)
-
- {
- crashflag=1;
- crashflag2 = pCKP->Control.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)
- {
- usedinfobox = 0;
- 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)
-{
-/*int i;*/
- g_pSound->playSound(SOUND_GET_CARD, PLAY_NOW);
- if (doortile==DOOR_YELLOW) player[p].inventory.HasCardYellow = 1;
- else if (doortile==DOOR_RED) player[p].inventory.HasCardRed = 1;
- else if (doortile==DOOR_GREEN) player[p].inventory.HasCardGreen = 1;
- else if (doortile==DOOR_BLUE) player[p].inventory.HasCardBlue = 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)
-{
-/*int i;*/
- if (doortile==DOOR_YELLOW) player[p].inventory.HasCardYellow = 0;
- else if (doortile==DOOR_RED) player[p].inventory.HasCardRed = 0;
- else if (doortile==DOOR_GREEN) player[p].inventory.HasCardGreen = 0;
- else if (doortile==DOOR_BLUE) 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);
-
- if(options[OPT_KEYCARDSTACK].value != 1)
- 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;iResources.GameSelected == 0)
- {
- if (loadtileattributes(pCKP->Control.levelcontrol.episode, pCKP->GameData[0].DataDirectory)) return 1;
- }
- else
- {
- if (loadtileattributes(pCKP->Control.levelcontrol.episode, pCKP->GameData[pCKP->Resources.GameSelected-1].DataDirectory)) return 1;
- }
-
- map.firsttime = 1;
-
- memset(player, 0, sizeof(player));
-
- 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 = 0;
-}
-
-
-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 = 0;
-
- 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: //crashflag = 1;
- //crashflag2 = t;
- 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];
+
+ // 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;
+ }
+
+}
diff --git a/src/gamepdo.cpp b/src/gamepdo.cpp
index 62ce91d7b..f87ff8c19 100644
--- a/src/gamepdo.cpp
+++ b/src/gamepdo.cpp
@@ -59,7 +59,6 @@ char doFall;
gamepdo_keencicle(cp, pCKP);
-
if(!player[cp].pjumping && !player[cp].pfalling)
{
gamepdo_walking(cp, pCKP);
@@ -373,7 +372,7 @@ void gamepdo_setblockedlru(unsigned int cp, stCloneKeenPlus *pCKP)
}
// set psliding if we're on ice
- if (TileProperty[getmaptileat(tx,ty+PLAYERHEIGHT)][BUP] == 3)
+ if (TileProperty[getmaptileat(tx,ty+PLAYERHEIGHT)][BUP] == 3 && !player[cp].ppogostick)
{
player[cp].psliding = 1;
player[cp].pshowdir = player[cp].pdir;
@@ -520,7 +519,7 @@ void gamepdo_walkinganim(int cp, stCloneKeenPlus *pCKP)
// make walk noise
if (!player[cp].pjumping && !player[cp].pfalling)
{
- if (!player[cp].pfrozentime)
+ if (!player[cp].pfrozentime && player[cp].pwalking)
{
if (player[cp].pwalkframea&1)
{
@@ -620,7 +619,6 @@ void gamepdo_playpushed(int cp, stCloneKeenPlus *pCKP)
// (this is where the inertia/playpushed_x is actually applied to playx)
void gamepdo_InertiaAndFriction_X(unsigned int cp, stCloneKeenPlus *pCKP)
{
-
stLevelControl *p_levelcontrol;
int friction_rate;
@@ -640,7 +638,7 @@ void gamepdo_InertiaAndFriction_X(unsigned int cp, stCloneKeenPlus *pCKP)
// Check walking boost and pogoing. It is similar to inertia
if(player[cp].pjumping || player[cp].pfalling)
{
- if (player[cp].playcontrol[PA_X] < 0)
+ if (player[cp].playcontrol[PA_X] < 0 && !player[cp].pfrozentime)
{
if(player[cp].pboost_x > 0 && !player[cp].ppogostick)
{
@@ -649,10 +647,10 @@ void gamepdo_InertiaAndFriction_X(unsigned int cp, stCloneKeenPlus *pCKP)
}
else
{
- player[cp].pboost_x--;
+ player[cp].pboost_x-= player[cp].ppogostick ? 2 : 1;
}
}
- if (player[cp].playcontrol[PA_X] > 0)
+ if (player[cp].playcontrol[PA_X] > 0 && !player[cp].pfrozentime)
{
if(player[cp].pboost_x < 0 && !player[cp].ppogostick)
{
@@ -661,7 +659,7 @@ void gamepdo_InertiaAndFriction_X(unsigned int cp, stCloneKeenPlus *pCKP)
}
else
{
- player[cp].pboost_x++;
+ player[cp].pboost_x+= player[cp].ppogostick ? 2 : 1;
}
}
@@ -696,7 +694,8 @@ void gamepdo_InertiaAndFriction_X(unsigned int cp, stCloneKeenPlus *pCKP)
}
// Calculate Threshold of your analog device for walking animation speed!
- player[cp].treshold = player[cp].playcontrol[PA_X];
+ if(!player[cp].pfrozentime)
+ player[cp].treshold = player[cp].playcontrol[PA_X];
int pmaxspeed = 0;
@@ -818,7 +817,7 @@ void gamepdo_InertiaAndFriction_X(unsigned int cp, stCloneKeenPlus *pCKP)
}
}
-void gamepdo_Jump(int cp, stCloneKeenPlus *pCKP)
+void gamepdo_Jump(int cp)
{
// handle the JUMP key, both for normal jumps and (high) pogo jumps
if (!player[cp].pjumping && !player[cp].pfalling && !player[cp].pfiring)
@@ -907,87 +906,80 @@ p_levelcontrol = &(pCKP->Control.levelcontrol);
// toggle pogo when KPOGO key is pressed
if (player[cp].playcontrol[PA_POGO] && !player[cp].lastplaycontrol[PA_POGO] && !player[cp].pfrozentime)
{
- if (p_levelcontrol->episode==2)
- {
- // if we are at a switch hit the switch instead
- mx = (player[cp].x>>CSF)+8;
- my = (player[cp].y>>CSF)+9;
- try2 = 0;
- retry: ;
- t = getmaptileat(mx, my);
- if (player[cp].ppogostick==0 && (t==TILE_SWITCH_UP || t==TILE_SWITCH_DOWN))
- { // switch to extend platform
+ // if we are at a switch hit the switch instead
+ mx = (player[cp].x>>CSF)+8;
+ my = (player[cp].y>>CSF)+9;
+ try2 = 0;
+ retry: ;
+ t = getmaptileat(mx, my);
+ if (!player[cp].ppogostick && (t==TILE_SWITCH_UP || t==TILE_SWITCH_DOWN))
+ { // switch to extend platform
- // figure out where the platform is supposed to extend
- // (this is coded in the object layer...high byte is the Y offset
- // and the low byte is the X offset)
- l = getlevelat(mx, my);
- // if zero it's the switch on a tantalus ray!
- if (l==0)
- {
- g_pSound->playStereofromCoord(SOUND_SWITCH_TOGGLE, PLAY_NOW, objects[player[cp].useObject].scrx);
+ // figure out where the platform is supposed to extend
+ // (this is coded in the object layer...high byte is the Y offset
+ // and the low byte is the X offset)
+ l = getlevelat(mx, my);
+ // if zero it's the switch on a tantalus ray!
+ if (l==0)
+ {
+ g_pSound->playStereofromCoord(SOUND_SWITCH_TOGGLE, PLAY_NOW, objects[player[cp].useObject].scrx);
- map_chgtile(mx>>4,my>>4,TILE_SWITCH_DOWN);
- p_levelcontrol->success = 0;
- p_levelcontrol->command = LVLC_TANTALUS_RAY;
- return;
- }
- pxoff = (l & 0x00ff);
- pyoff = (l & 0xff00) >> 8;
- platx = (mx >> 4) + pxoff;
- platy = (my >> 4) + pyoff;
+ map_chgtile(mx>>4,my>>4,TILE_SWITCH_DOWN);
+ p_levelcontrol->success = 0;
+ p_levelcontrol->command = LVLC_TANTALUS_RAY;
+ return;
+ }
+ pxoff = (l & 0x00ff);
+ pyoff = (l & 0xff00) >> 8;
+ platx = (mx >> 4) + pxoff;
+ platy = (my >> 4) + pyoff;
- if (PlatExtending) // don't allow player to hit switch again while
- { // plat is moving as this will glitch the plat
- return;
- }
- else PlatExtending = 1;
+ if (PlatExtending) // don't allow player to hit switch again while
+ { // plat is moving as this will glitch the plat
+ return;
+ }
+ else PlatExtending = 1;
- g_pSound->playStereofromCoord(SOUND_SWITCH_TOGGLE, PLAY_NOW, objects[player[cp].useObject].scrx);
+ g_pSound->playStereofromCoord(SOUND_SWITCH_TOGGLE, PLAY_NOW, objects[player[cp].useObject].scrx);
- if (t==TILE_SWITCH_UP)
- { // switch toggled from up to down--extend platform
- map_chgtile(mx>>4,my>>4,TILE_SWITCH_DOWN);
- o = spawn_object((mx>>4<<4)<>4<<4)<>4,my>>4,TILE_SWITCH_UP);
- o = spawn_object((mx>>4<<4)<>4<<4)<dark ^= 1;
- g_pGraphics->initPalette(p_levelcontrol->dark);
- g_pGraphics->fadePalette(PAL_FADE_SHADES);
- g_pSound->playStereofromCoord(SOUND_SWITCH_TOGGLE, PLAY_NOW, objects[player[cp].useObject].scrx);
- }
- else
- { // toggle pogo stick
- if (!try2)
- {
- my = (player[cp].y>>CSF)+1;
- try2 = 1;
- goto retry;
- }
-
- player[cp].ppogostick = 1 - player[cp].ppogostick;
- }
- }
- else
- { // not episode 2...don't bother with all of this
- if (player[cp].inventory.HasPogo)
- {
- player[cp].ppogostick = 1 - player[cp].ppogostick;
- }
- }
+ if (t==TILE_SWITCH_UP)
+ { // switch toggled from up to down--extend platform
+ map_chgtile(mx>>4,my>>4,TILE_SWITCH_DOWN);
+ o = spawn_object((mx>>4<<4)<>4<<4)<>4,my>>4,TILE_SWITCH_UP);
+ o = spawn_object((mx>>4<<4)<>4<<4)<dark ^= 1;
+ g_pGraphics->initPalette(p_levelcontrol->dark);
+ g_pGraphics->fadePalette(PAL_FADE_SHADES);
+ g_pSound->playStereofromCoord(SOUND_SWITCH_TOGGLE, PLAY_NOW, objects[player[cp].useObject].scrx);
+ }
+ else
+ {
+ if (!try2)
+ {
+ my = (player[cp].y>>CSF)+1;
+ try2 = 1;
+ goto retry;
+ }
+ // toggle pogo
+ if (player[cp].inventory.HasPogo)
+ {
+ player[cp].ppogostick = !player[cp].ppogostick;
+ }
+ }
}
// handle the JUMP key, both for normal jumps and (high) pogo jumps
@@ -1036,7 +1028,7 @@ p_levelcontrol = &(pCKP->Control.levelcontrol);
}
else
{
- if(player[cp].ppogostick != 0)
+ if(player[cp].ppogostick)
{
player[cp].pjumpupspeed = PJUMPUP_SPEED;
player[cp].pjumptime = PJUMP_NORMALTIME_POGO_SHORT;
@@ -1053,10 +1045,20 @@ p_levelcontrol = &(pCKP->Control.levelcontrol);
case PPREPAREJUMP:
player[cp].widejump = true;
- if(g_pInput->getHoldedCommand(IC_LEFT))
- player[cp].chargedjump-=2;
- else if(g_pInput->getHoldedCommand(IC_RIGHT))
- player[cp].chargedjump+=2;
+ if(player[cp].psliding)
+ {
+ if(player[cp].pdir == LEFT)
+ player[cp].chargedjump-=2;
+ else if(player[cp].pdir == RIGHT)
+ player[cp].chargedjump+=2;
+ }
+ else
+ {
+ if(g_pInput->getHoldedCommand(IC_LEFT))
+ player[cp].chargedjump-=2;
+ else if(g_pInput->getHoldedCommand(IC_RIGHT))
+ player[cp].chargedjump+=2;
+ }
player[cp].pinertia_x = 0; // prevent moving while preparing to jump
if (player[cp].pjumpanimtimer > PJUMP_PREPARE_ANIM_RATE)
@@ -1070,31 +1072,31 @@ p_levelcontrol = &(pCKP->Control.levelcontrol);
case PPREPAREJUMPFRAME:
player[cp].pjumptime = PJUMP_NORMALTIME_6;
player[cp].pjumpupdecreaserate = PJUMP_UPDECREASERATE_6;
- player[cp].pjumpupspeed = 6;
+ player[cp].pjumpupspeed = 1;
player[cp].chargedjump = player[cp].chargedjump >> 5;
break;
case PPREPAREJUMPFRAME+1:
player[cp].pjumptime = PJUMP_NORMALTIME_5;
player[cp].pjumpupdecreaserate = PJUMP_UPDECREASERATE_5;
- player[cp].pjumpupspeed = 8;
+ player[cp].pjumpupspeed = 2;
player[cp].chargedjump = player[cp].chargedjump >> 4;
break;
case PPREPAREJUMPFRAME+2:
player[cp].pjumptime = PJUMP_NORMALTIME_4;
player[cp].pjumpupdecreaserate = PJUMP_UPDECREASERATE_4;
- player[cp].pjumpupspeed = 10;
+ player[cp].pjumpupspeed = 4;
player[cp].chargedjump = player[cp].chargedjump >> 3;
break;
case PPREPAREJUMPFRAME+3:
player[cp].pjumptime = PJUMP_NORMALTIME_3;
player[cp].pjumpupdecreaserate = PJUMP_UPDECREASERATE_3;
- player[cp].pjumpupspeed = 14;
+ player[cp].pjumpupspeed = 8;
player[cp].chargedjump = player[cp].chargedjump >> 2;
break;
case PPREPAREJUMPFRAME+4:
player[cp].pjumptime = PJUMP_NORMALTIME_2;
player[cp].pjumpupdecreaserate = PJUMP_UPDECREASERATE_2;
- player[cp].pjumpupspeed = 18;
+ player[cp].pjumpupspeed = 16;
player[cp].chargedjump = player[cp].chargedjump >> 1;
break;
default:
@@ -1349,7 +1351,7 @@ int canRefire;
{
player[cp].inhibitwalking = 1; // prevent moving
player[cp].pfiring = 1; // flag that we're firing
- player[cp].ppogostick = 0; // put away pogo stick if out
+ player[cp].ppogostick = false; // put away pogo stick if out
if (!player[cp].lastplaycontrol[PA_FIRE] || pCKP->Option[OPT_FULLYAUTOMATIC].value)
{ // fire is newly pressed
@@ -1509,7 +1511,7 @@ void gamepdo_walking(int cp, stCloneKeenPlus *pCKP)
}
// if we fall onto a semislide tile with no inertia
- // start moving a little
+ // don't move!.
if (player[cp].pjustfell && player[cp].psemisliding)
{
if (player[cp].pdir==RIGHT)
@@ -1521,7 +1523,6 @@ void gamepdo_walking(int cp, stCloneKeenPlus *pCKP)
}
else
{
- if (!player[cp].pinertia_x) player[cp].pinertia_x = 1;
player[cp].pshowdir = player[cp].pdir;
}
}
@@ -1534,7 +1535,6 @@ void gamepdo_walking(int cp, stCloneKeenPlus *pCKP)
}
else
{
- if (!player[cp].pinertia_x) player[cp].pinertia_x = -1;
player[cp].pshowdir = player[cp].pdir;
}
}
diff --git a/src/gm_pdowm.cpp b/src/gm_pdowm.cpp
index 86e365994..c3fdd9e01 100644
--- a/src/gm_pdowm.cpp
+++ b/src/gm_pdowm.cpp
@@ -84,35 +84,35 @@ void gamepdo_wm_setblockedlrud(int cp, stCloneKeenPlus *pCKP)
if ((pCKP->Option[OPT_CHEATS].value && g_pInput->getHoldedKey(KTAB)) || player[cp].godmode) return;
// R
- if (wm_issolid((player[cp].x>>CSF)+8, (player[cp].y>>CSF)+1))
+ if (wm_issolid((player[cp].x>>CSF)+8, (player[cp].y>>CSF)+1, pCKP->Control.levelcontrol.levels_completed))
{ player[cp].blockedr = 1; }
- else if (wm_issolid((player[cp].x>>CSF)+8, (player[cp].y>>CSF)+8))
+ else if (wm_issolid((player[cp].x>>CSF)+8, (player[cp].y>>CSF)+8, pCKP->Control.levelcontrol.levels_completed))
{ player[cp].blockedr = 1; }
- else if (wm_issolid((player[cp].x>>CSF)+8, (player[cp].y>>CSF)+13))
+ else if (wm_issolid((player[cp].x>>CSF)+8, (player[cp].y>>CSF)+13, pCKP->Control.levelcontrol.levels_completed))
{ player[cp].blockedr = 1; }
// L
- if (wm_issolid((player[cp].x>>CSF)+0, (player[cp].y>>CSF)+1))
+ if (wm_issolid((player[cp].x>>CSF)+0, (player[cp].y>>CSF)+1, pCKP->Control.levelcontrol.levels_completed))
{ player[cp].blockedl = 1; }
- else if (wm_issolid((player[cp].x>>CSF)+0, (player[cp].y>>CSF)+8))
+ else if (wm_issolid((player[cp].x>>CSF)+0, (player[cp].y>>CSF)+8, pCKP->Control.levelcontrol.levels_completed))
{ player[cp].blockedl = 1; }
- else if (wm_issolid((player[cp].x>>CSF)+0, (player[cp].y>>CSF)+13))
+ else if (wm_issolid((player[cp].x>>CSF)+0, (player[cp].y>>CSF)+13, pCKP->Control.levelcontrol.levels_completed))
{ player[cp].blockedl = 1; }
// U
- if (wm_issolid((player[cp].x>>CSF)+1, (player[cp].y>>CSF)-1))
+ if (wm_issolid((player[cp].x>>CSF)+1, (player[cp].y>>CSF)-1, pCKP->Control.levelcontrol.levels_completed))
{ player[cp].blockedu = 1; }
- else if (wm_issolid((player[cp].x>>CSF)+4, (player[cp].y>>CSF)-1))
+ else if (wm_issolid((player[cp].x>>CSF)+4, (player[cp].y>>CSF)-1, pCKP->Control.levelcontrol.levels_completed))
{ player[cp].blockedu = 1; }
- else if (wm_issolid((player[cp].x>>CSF)+7, (player[cp].y>>CSF)-1))
+ else if (wm_issolid((player[cp].x>>CSF)+7, (player[cp].y>>CSF)-1, pCKP->Control.levelcontrol.levels_completed))
{ player[cp].blockedu = 1; }
// D
- if (wm_issolid((player[cp].x>>CSF)+1, (player[cp].y>>CSF)+14))
+ if (wm_issolid((player[cp].x>>CSF)+1, (player[cp].y>>CSF)+14, pCKP->Control.levelcontrol.levels_completed))
{ player[cp].blockedd = 1; }
- else if (wm_issolid((player[cp].x>>CSF)+4, (player[cp].y>>CSF)+14))
+ else if (wm_issolid((player[cp].x>>CSF)+4, (player[cp].y>>CSF)+14, pCKP->Control.levelcontrol.levels_completed))
{ player[cp].blockedd = 1; }
- else if (wm_issolid((player[cp].x>>CSF)+7, (player[cp].y>>CSF)+14))
+ else if (wm_issolid((player[cp].x>>CSF)+7, (player[cp].y>>CSF)+14, pCKP->Control.levelcontrol.levels_completed))
{ player[cp].blockedd = 1; }
}
@@ -314,7 +314,7 @@ p_levelcontrol = &(pCKP->Control.levelcontrol);
break;
default: // a regular level
- p_levelcontrol->chglevelto = (lvl & 0x7fff);
+ p_levelcontrol->chglevelto = (lvl & 0x7fff);
endlevel(1, pCKP);
g_pMusicPlayer->stop();
g_pSound->playStereofromCoord(SOUND_ENTER_LEVEL, PLAY_NOW, objects[player[cp].useObject].scrx);
@@ -329,14 +329,22 @@ p_levelcontrol = &(pCKP->Control.levelcontrol);
player[cp].wm_lastenterstate = (player[cp].playcontrol[PA_JUMP] || player[cp].playcontrol[PA_POGO]);
}
-char wm_issolid(int xb, int yb)
+char wm_issolid(int xb, int yb, int *levels_completed)
{
+
// for map tiles solidl and solidr are always gonna be the same...
// so we can get away with this.
if ( TileProperty[getmaptileat(xb, yb)][BLEFT] ) return 1;
//if (tiles[getmaptileat(xb, yb)].solidl) return 1;
- if (getlevelat(xb, yb) & 0x8000)
+
+ unsigned int level;
+ level = getlevelat(xb, yb);
+
+ if (level & 0x8000)
{
+ if(levels_completed[map.objectlayer[xb>>4][yb>>4] & 0x7fff] && options[OPT_LVLREPLAYABILITY].value) // check if level is done, but can be replayed
+ return 0;
+
if(g_pInput->getHoldedKey(KTAB) && g_pInput->getHoldedKey(KLSHIFT))
{
return 0;
@@ -392,19 +400,19 @@ int objmarker;
// is he trying to mount?
if (player[cp].y>>CSF>>4 < map.ysize>>2)
{ // at mortimer's castle mount point
- /*if ( (player[cp].keytable[KRIGHT] && player[cp].blockedr) || \
- (player[cp].keytable[KDOWN] && player[cp].blockedd))
+ if ( (player[cp].playcontrol[PA_X] > 0 && player[cp].blockedr) ||
+ (player[cp].playcontrol[PA_Y] > 0 && player[cp].blockedd))
{
// YES! if nessie is at that mount point, mount her!!
MountNessieIfAvailable(cp);
- }*/
+ }
}
else
{ // at secret island mount point
- /*if (player[cp].keytable[KUP] && player[cp].blockedu)
+ if (player[cp].playcontrol[PA_Y] < 0 && player[cp].blockedu)
{
MountNessieIfAvailable(cp);
- }*/
+ }
}
}
else
@@ -413,17 +421,17 @@ int objmarker;
{ // nessie is paused
if (objects[NessieObjectHandle].y>>CSF>>4 < map.ysize>>2)
{ // nessie is at mortimer's castle mount point
- /*if (player[cp].keytable[KUP])
+ if (player[cp].playcontrol[PA_Y] < 0)
{
// unmount nessie
objects[NessieObjectHandle].ai.nessie.mounted[cp] = 0;
player[cp].mounted = 0;
player[cp].hideplayer = 0;
- }*/
+ }
}
else if (objects[NessieObjectHandle].y>>CSF>>4 > map.ysize>>1)
{ // nessie is at secret island mount point
- /*if (player[cp].keytable[KDOWN])
+ if (player[cp].playcontrol[PA_Y] > 0)
{
// unmount nessie
objects[NessieObjectHandle].ai.nessie.mounted[cp] = 0;
@@ -431,7 +439,7 @@ int objmarker;
player[cp].hideplayer = 0;
player[cp].y += (18<h>>4) > hsize) || ((m_scrimg->w>>4) > wsize) )
+ if((m_scrimg = SDL_DisplayFormat(BitmapSurface)))
{
- g_pLogFile->textOut(PURPLE,"HQBitmapLoader : The dimensions of the bitmap don't match to the dimensions of the level.
");
- g_pLogFile->ftextOut("Please use a proper bitmap with %dx%d dimensions.
", m_scrimg->w, m_scrimg->h);
- g_pLogFile->ftextOut("Your bitmap is of %dx%d.
", wsize, hsize);
- g_pLogFile->textOut(BLUE,"HQBitmapLoader : Loading the level without HQBitmap.
");
+ SDL_FreeSurface(BitmapSurface);
+
+ if( ((m_scrimg->h>>4) > hsize) || ((m_scrimg->w>>4) > wsize) )
+ {
+ g_pLogFile->textOut(PURPLE,"HQBitmapLoader : The dimensions of the bitmap don't match to the dimensions of the level.
");
+ g_pLogFile->ftextOut("Please use a proper bitmap with %dx%d dimensions.
", m_scrimg->w, m_scrimg->h);
+ g_pLogFile->ftextOut("Your bitmap is of %dx%d.
", wsize, hsize);
+ g_pLogFile->textOut(BLUE,"HQBitmapLoader : Loading the level without HQBitmap.
");
+ }
+ else
+ {
+ m_active = true;
+ // Create a empty black surface for alpha blending with black
+ SDL_Surface *BlackScreenCreation = SDL_CreateRGBSurface(0, 320,240,32,0,0,0,0);
+ m_blackscreen = SDL_DisplayFormat(BlackScreenCreation);
+ SDL_FreeSurface(BlackScreenCreation);
+ }
}
else
{
- m_active = true;
- // Create a empty black surface for alpha blending with black
- m_blackscreen = SDL_CreateRGBSurface(SDL_SWSURFACE,
- 320,240,32,0,0,0,0);
+ g_pLogFile->textOut(PURPLE,"Error: The HQBitmap could not be loaded to the memory!");
+ return m_active;
}
+
}
+ else
+ {
+
+ }
+
return m_active;
}
-void CHQBitmap::updateHQBitmap(SDL_Surface *m_surface, unsigned int x, unsigned int y)
+void CHQBitmap::updateHQBitmap(SDL_Surface *m_surface, SDL_Rect *p_srcrect, SDL_Rect *p_dstrect)
{
- m_imagerect.x = x;
- m_imagerect.y = y;
- m_imagerect.w = m_surface->w;
- m_imagerect.h = m_surface->h;
-
- SDL_BlitSurface(m_scrimg, &m_imagerect, m_surface, NULL);
+ SDL_BlitSurface(m_scrimg, p_srcrect, m_surface, p_dstrect);
if(m_alpha == 255)
return;
diff --git a/src/hqp/CHQBitmap.h b/src/hqp/CHQBitmap.h
index 26329eb00..2e80aecf9 100644
--- a/src/hqp/CHQBitmap.h
+++ b/src/hqp/CHQBitmap.h
@@ -16,7 +16,7 @@ public:
virtual ~CHQBitmap();
void setScrollposition(unsigned int xpos, unsigned int ypos);
- void updateHQBitmap(SDL_Surface *m_surface, unsigned int x, unsigned int y);
+ void updateHQBitmap(SDL_Surface *m_surface, SDL_Rect *p_srcrect, SDL_Rect *p_dstrect);
bool loadImage(const char *pFilename, int wsize, int hsize);
void setAlphaBlend(Uint8 alpha);
void offsetAlphaBlend(Uint8 alpha);
diff --git a/src/hqp/CMusic.cpp b/src/hqp/CMusic.cpp
index e7b0f637a..675a98f86 100644
--- a/src/hqp/CMusic.cpp
+++ b/src/hqp/CMusic.cpp
@@ -41,7 +41,7 @@ int CMusic::load(SDL_AudioSpec AudioSpec, char *musicfile)
return -1;
}
- if(openOGGSound(fp, &AudioFileSpec, &pOggAudio) != 0)
+ if(openOGGSound(fp, &AudioFileSpec, AudioSpec.format, &pOggAudio) != 0)
{
g_pLogFile->textOut(PURPLE,"Music Driver(): OGG file could not be opened: \"%s\". File is damaged or something is wrong with your soundcard!
", musicfile);
return 1;
@@ -50,7 +50,8 @@ int CMusic::load(SDL_AudioSpec AudioSpec, char *musicfile)
g_pLogFile->ftextOut("Music Driver(): File \"%s\" opened successfully!
", musicfile);
int ret;
- ret = SDL_BuildAudioCVT(&Audio_cvt,
+
+ ret = SDL_BuildAudioCVT(&Audio_cvt,
AudioFileSpec.format, AudioFileSpec.channels, AudioFileSpec.freq,
AudioSpec.format, AudioSpec.channels, AudioSpec.freq);
@@ -65,8 +66,7 @@ int CMusic::load(SDL_AudioSpec AudioSpec, char *musicfile)
}
music_len = pOggAudio.sound_len;
-
- Audio_cvt.buf = (Uint8*) malloc(music_len * Audio_cvt.len_mult * sizeof(Uint8));
+ Audio_cvt.buf = (Uint8*) malloc(music_len * (Audio_cvt.len_mult) * sizeof(Uint8));
Audio_cvt.len = music_len;
memcpy(Audio_cvt.buf, pOggAudio.sound_buffer, music_len*sizeof(Uint8));
diff --git a/src/hqp/hq_sound.cpp b/src/hqp/hq_sound.cpp
index 789bb311f..99df5a280 100644
--- a/src/hqp/hq_sound.cpp
+++ b/src/hqp/hq_sound.cpp
@@ -24,7 +24,7 @@ short HQSndDrv_Load(SDL_AudioSpec *AudioSpec, stHQSound *psound, const char *sou
if((fp = fopen(buf,"rb")) != NULL)
{
#ifdef BUILD_WITH_OGG
- if(openOGGSound(fp, &AudioFileSpec, psound) != 0)
+ if(openOGGSound(fp, &AudioFileSpec, AudioSpec->format, psound) != 0)
{
g_pLogFile->textOut(PURPLE,"OGG file could not be opened: \"%s\". The file was detected, but appears to be damaged. Trying to load the classical sound
", soundfile);
return 1;
diff --git a/src/include/fileio.h b/src/include/fileio.h
index 61f7cd077..6991c57f6 100644
--- a/src/include/fileio.h
+++ b/src/include/fileio.h
@@ -10,3 +10,5 @@ void addmaptile(unsigned int t);
void addenemytile(unsigned int t, stCloneKeenPlus *pCKP);
short checkConsistencyofGameData(stGameData *p_GameData);
void formatPathString(char *output, const char *path);
+bool renameFilenamesLowerCase(const char *dir_name);
+void assignChangeTileAttribute(stTile *tile, int episode);
diff --git a/src/include/fileio/lzexe.h b/src/include/fileio/lzexe.h
deleted file mode 100644
index 9fd436abc..000000000
--- a/src/include/fileio/lzexe.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * lzexe.h
- *
- * Created on: 24.01.2009
- * Author: gerstrong
- */
-
-#include
-
-int get_bit(int *p_bit_count, FILE **fin); /* only used for the conversion of sounds from episode 2 and 3 by sound_extraction_of_exe_files */
-
-int unlzexe(FILE *fin, unsigned char *outbuffer);
-
-int getEXEVersion(int episode, int bufsize);
diff --git a/src/include/gamepdo.h b/src/include/gamepdo.h
index 50480e898..9db538c46 100644
--- a/src/include/gamepdo.h
+++ b/src/include/gamepdo.h
@@ -16,7 +16,7 @@ void gamepdo_walkinganim(int cp, stCloneKeenPlus *pCKP);
void gamepdo_walking(int cp, stCloneKeenPlus *pCKP);
void gamepdo_playpushed(int cp, stCloneKeenPlus *pCKP);
void gamepdo_JumpAndPogo(int cp, stCloneKeenPlus *pCKP);
-void gamepdo_Jump(int cp, stCloneKeenPlus *pCKP);
+void gamepdo_Jump(int cp);
//void gamepdo_falling(int cp, stCommand command[MAX_COMMANDS]);
void gamepdo_raygun(int cp, stCloneKeenPlus *pCKP);
void gamepdo_special(int cp, stCloneKeenPlus *pCKP);
diff --git a/src/include/vorbis/oggsupport.h b/src/include/vorbis/oggsupport.h
index c4e5e909b..73206311f 100644
--- a/src/include/vorbis/oggsupport.h
+++ b/src/include/vorbis/oggsupport.h
@@ -7,6 +7,6 @@
#ifdef BUILD_WITH_OGG
-short openOGGSound(FILE *fp, SDL_AudioSpec *pspec, stHQSound *psound);
+short openOGGSound(FILE *fp, SDL_AudioSpec *pspec, Uint16 format, stHQSound *psound);
#endif
diff --git a/src/keen.h b/src/keen.h
index a5d24de80..77d06723b 100644
--- a/src/keen.h
+++ b/src/keen.h
@@ -16,7 +16,7 @@
#include "vorticon/sounds.h"
#include "funcdefs.h"
-#include "CLatch.h"
+#include "fileio/CTileLoader.h"
#include "include/playeraction.h"
@@ -35,7 +35,6 @@
#define WM_MAP_NUM 80
-#define MAX_TILES 700
#define MAX_SPRITES 300
#define MAX_FONT 256
#define MAX_BITMAPS 20
@@ -110,13 +109,6 @@ typedef struct stMap
unsigned int objectlayer[256][256];
char firsttime; // used when generating multiplayer positions on world map
} stMap;
-typedef struct stTile
-{
- int masktile; // if nonzero, specifies a mask for this tile
- int chgtile; // tile to change to when level completed (for wm)
- // or tile to change to when picked up (in-level)
- unsigned int animOffset; // starting offset from the base frame
-} stTile;
// Tile information planes
@@ -134,6 +126,7 @@ typedef struct stBitmap
unsigned char *bmptr;
char name[9];
} stBitmap;
+
typedef struct stSprite
{
char xsize, ysize;
@@ -712,7 +705,7 @@ typedef struct stPlayer
int psupportingtile, psupportingobject, lastsupportingobject;
char psliding;
char psemisliding;
- char ppogostick;
+ bool ppogostick;
int pfrozentime,pfrozenframe,pfrozenanimtimer;
unsigned char keytable[50];
diff --git a/src/keenext.h b/src/keenext.h
index f64ba9631..23513a11d 100644
--- a/src/keenext.h
+++ b/src/keenext.h
@@ -6,7 +6,7 @@ extern stMap map;
extern unsigned int AnimTileInUse[ATILEINUSE_SIZEX][ATILEINUSE_SIZEY];
extern stTile tiles[MAX_TILES+1];
extern unsigned char tiledata[MAX_TILES+1][16][16];
-extern stSprite sprites[MAX_SPRITES+1];
+extern stSprite *sprites;
extern stBitmap bitmaps[MAX_BITMAPS+1];
extern stAnimTile animtiles[MAX_ANIMTILES+1];
extern char font[MAX_FONT+1][8][8];
@@ -68,17 +68,10 @@ extern int blockedby;
extern int gunfiretimer, gunfirefreq;
extern char cheatmode;
-extern int numtiles;
-extern int **TileProperty; // This version will replace the old stTile Structure and save memory
-
-extern short usedinfobox; // If statue was used...
-
-
extern int NessieObjectHandle;
extern int DemoObjectHandle;
extern int BlankSprite;
extern int DemoSprite;
-//extern EgaHead LatchHeader;
extern stShipQueue shipqueue[32];
extern int ShipQueuePtr;
diff --git a/src/lz.cpp b/src/lz.cpp
index d7d40725c..4efd628b0 100644
--- a/src/lz.cpp
+++ b/src/lz.cpp
@@ -6,12 +6,10 @@
#include "CLogFile.h"
#define LZ_STARTBITS 9
-#define LZ_MAXBITS 12
#define LZ_ERRORCODE 256
#define LZ_EOFCODE 257
#define LZ_DICTSTARTCODE 258
-#define LZ_MAXDICTSIZE ((1<stringlen;i++)
{
*lz_outbuffer = lzdict[entry]->string[i];
@@ -77,128 +81,142 @@ int i;
// returns nonzero if an error occurs
char lz_decompress(FILE *lzfile, unsigned char *outbuffer)
{
-int i;
-int numbits;
-unsigned int dictindex, maxdictindex;
-unsigned int lzcode,lzcode_save,lastcode;
-char addtodict;
+ unsigned int i;
+ unsigned int numbits;
+ unsigned int decsize;
+ unsigned short maxdictcodewords;
+ unsigned int maxdictsize;
+ unsigned int dictindex, maxdictindex;
+ unsigned int lzcode,lzcode_save,lastcode;
+ char addtodict;
- /* allocate memory for the LZ dictionary */
- for(i=0;itextOut("lz_decompress(): unable to allocate memory for dictionary!
");
- return 1;
- }
- }
+ // Get the decompressed file-size
+ decsize = fgetc(lzfile);
+ decsize += fgetc(lzfile) << 8;
+ decsize += fgetc(lzfile) << 16;
+ decsize += fgetc(lzfile) << 24;
- /* initilize the dictionary */
+ // Get the length of the maximum dictionary size
- // entries 0-255 start with a single character corresponding
- // to their entry number
- for(i=0;i<256;i++)
- {
- lzdict[i]->stringlen = 1;
- lzdict[i]->string[0] = i;
- }
- // 256+ start undefined
- for(i=256;istringlen = 0;
- }
+ maxdictcodewords = fgetc(lzfile);
+ maxdictcodewords += fgetc(lzfile) << 8;
- // reset readbits
- lz_readbits(NULL, 0, 1);
+ maxdictsize = ((1<textOut("lz_decompress(): unable to allocate memory for dictionary!
");
+ return 1;
+ }
+ }
- // point the global pointer to the buffer we were passed
- lz_outbuffer = outbuffer;
+ /* initilize the dictionary */
- // setup where to start adding strings to the dictionary
- dictindex = LZ_DICTSTARTCODE;
- addtodict = 1; // enable adding to dictionary
+ // entries 0-255 start with a single character corresponding
+ // to their entry number
+ for(i=0;i<256;i++)
+ {
+ lzdict[i]->stringlen = 1;
+ lzdict[i]->string[0] = i;
+ }
+ // 256+ start undefined
+ for(i=256;istringlen = 0;
+ }
- // read first code
- lastcode = lz_readbits(lzfile, numbits, 0);
- lz_outputdict(lastcode);
- do
- {
- // read the next code from the compressed data stream
- lzcode = lz_readbits(lzfile, numbits, 0);
- lzcode_save = lzcode;
+ // reset readbits
+ lz_readbits(NULL, 0, 1);
- if (lzcode==LZ_ERRORCODE || lzcode==LZ_EOFCODE)
- {
- break;
- }
+ // set starting # of bits-per-code
+ numbits = LZ_STARTBITS;
+ maxdictindex = (1 << numbits) - 1;
- // if the code is present in the dictionary,
- // lookup and write the string for that code, then add the
- // last string + the first char of the just-looked-up string
- // to the dictionary at dictindex
+ // point the global pointer to the buffer we were passed
+ lz_outbuffer = outbuffer;
- // if not in dict, add the last string + the first char of the
- // last string to the dictionary at dictindex (which will be equal
- // to lzcode), then lookup and write string lzcode.
+ // setup where to start adding strings to the dictionary
+ dictindex = LZ_DICTSTARTCODE;
+ addtodict = 1; // enable adding to dictionary
- if (lzdict[lzcode]->stringlen==0)
- { // code is not present in dictionary
- lzcode = lastcode;
- }
+ // read first code
+ lastcode = lz_readbits(lzfile, numbits, 0);
+ lz_outputdict(lastcode);
+ do
+ {
+ // read the next code from the compressed data stream
+ lzcode = lz_readbits(lzfile, numbits, 0);
+ lzcode_save = lzcode;
- if (addtodict) // room to add more entries to the dictionary?
- {
- // copies string lastcode to string dictindex, then
- // concatenates the first character of string lzcode.
- for(i=0;istringlen;i++)
- {
- lzdict[dictindex]->string[i] = lzdict[lastcode]->string[i];
- }
- lzdict[dictindex]->string[i] = lzdict[lzcode]->string[0];
- lzdict[dictindex]->stringlen = (lzdict[lastcode]->stringlen + 1);
+ if (lzcode==LZ_ERRORCODE || lzcode==LZ_EOFCODE)
+ break;
- // ensure we haven't overflowed the buffer
- if (lzdict[dictindex]->stringlen >= (LZ_MAXSTRINGSIZE-1))
- {
- g_pLogFile->ftextOut("lz_decompress(): lzdict[%d]->stringlen is too long...max length is %d
", dictindex, LZ_MAXSTRINGSIZE);
- return 1;
- }
+ // if the code is present in the dictionary,
+ // lookup and write the string for that code, then add the
+ // last string + the first char of the just-looked-up string
+ // to the dictionary at dictindex
- dictindex++;
- if (dictindex >= maxdictindex)
- { // no more entries can be specified with current code bit-width
- if (numbits < LZ_MAXBITS)
- { // increase width of codes
- numbits++;
- maxdictindex = (1 << numbits) - 1;
- }
- else
- {
- // reached maximum bit width, can't increase.
- // use the final entry (4095) before we shut off
- // adding items to the dictionary.
- if (dictindex>=(LZ_MAXDICTSIZE-1)) addtodict = 0;
- }
- }
- }
+ // if not in dict, add the last string + the first char of the
+ // last string to the dictionary at dictindex (which will be equal
+ // to lzcode), then lookup and write string lzcode.
- // write the string associated with the original code read.
- // if the code wasn't present, it now should have been added.
- lz_outputdict(lzcode_save);
+ if (lzdict[lzcode]->stringlen==0)
+ // code is not present in dictionary
+ lzcode = lastcode;
- lastcode = lzcode_save;
- } while(1);
+ if (addtodict) // room to add more entries to the dictionary?
+ {
+ // copies string lastcode to string dictindex, then
+ // concatenates the first character of string lzcode.
+ for(i=0 ; i< (unsigned int) lzdict[lastcode]->stringlen ; i++)
+ lzdict[dictindex]->string[i] = lzdict[lastcode]->string[i];
- /* free the memory used by the LZ dictionary */
- for(i=0;istring[i] = lzdict[lzcode]->string[0];
+ lzdict[dictindex]->stringlen = (lzdict[lastcode]->stringlen + 1);
+
+ // ensure we haven't overflowed the buffer
+ if (lzdict[dictindex]->stringlen >= (LZ_MAXSTRINGSIZE-1))
+ {
+ g_pLogFile->ftextOut("lz_decompress(): lzdict[%d]->stringlen is too long...max length is %d
", dictindex, LZ_MAXSTRINGSIZE);
+ return 1;
+ }
+
+ dictindex++;
+ if (dictindex >= maxdictindex)
+ { // no more entries can be specified with current code bit-width
+ if (numbits < maxdictcodewords)
+ { // increase width of codes
+ numbits++;
+ maxdictindex = (1 << numbits) - 1;
+ }
+ else
+ {
+ // reached maximum bit width, can't increase.
+ // use the final entry (4095) before we shut off
+ // adding items to the dictionary.
+ if (dictindex>=(maxdictsize-1)) addtodict = 0;
+ }
+ }
+ }
+
+ // write the string associated with the original code read.
+ // if the code wasn't present, it now should have been added.
+ lz_outputdict(lzcode_save);
+
+ lastcode = lzcode_save;
+ } while(1);
+
+ /* free the memory used by the LZ dictionary */
+ for(i=0;isuccess = 0;
map.firsttime = 1;
- usedinfobox = 0;
-
do
{
initgame(pCKP);
@@ -382,6 +379,7 @@ void playgame_levelmanager(stCloneKeenPlus *pCKP)
// Now load HQ Stuff, because the game could have been loaded too.
g_pGraphics->loadHQGraphics(p_levelcontrol->episode,p_levelcontrol->chglevelto,pCKP->GameData[pCKP->Resources.GameSelected-1].DataDirectory);
+ g_pInput->flushAll();
if (wm)
{ // entering map from normal level, or first time around
@@ -654,14 +652,6 @@ short readCommandLine(int argc, char *argv[], stCloneKeenPlus *pCKP)
{
g_pVideoDriver->setZoom(2);
}
- else if (strcmp(tempbuf, "-acc")==0) // Hardware Acceleration
- {
- //pCKP->Device.Display.Mode = VIDEO_MODE_SOFTWARE;
- }
- else if (strcmp(tempbuf, "-ogl")==0) // Early OpenGL Support
- {
- //pCKP->Device.Display.Mode = VIDEO_MODE_OPENGL;
- }
else if (strcmp(tempbuf, "-stereo")==0) // Enable Stereo Sound
{
g_pSound->setSoundmode(0,true);
diff --git a/src/map.cpp b/src/map.cpp
index 40eff713f..1b3887fa7 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -223,13 +223,10 @@ int y;
// changes the tile at (x,y) in real time
void map_chgtile(unsigned int x, unsigned int y, int newtile)
{
-/*char buf[80];*/
map.mapdata[x][y] = newtile;
if (x>=mapx && y>=mapy && xdrawTile(((mapxstripepos+((x-mapx)<<4))&511), ((mapystripepos+((y-mapy)<<4))&511), newtile);
- }
}
// searches for animated tiles at the map position (X,Y) and
@@ -242,6 +239,8 @@ int i;
px = ((mapxstripepos+((x-mapx)<<4))&511);
py = ((mapystripepos+((y-mapy)<<4))&511);
+ TileProperty[map.mapdata[x][y]][ANIMATION] = 1;
+
// find it!
for(i=1;i 1 )
+ if ( TileProperty[c][ANIMATION] == 1 ) // In case the tile mustn't be animated
{
- /*crashflag = 1;
- crashflag2 = x;
- crashflag3 = y;
- why_term_ptr = "map_animate(): you told me to animate x/y=crashflag1/2 but that tile isn't supposed to be animated!";*/
+ crashflag = x;
+ crashflag2 = y;
+ why_term_ptr = "sorry, but tile at x/y=crashflag1/2 isn't supposed to be animated!";
+ crashflag = 0;
+ crashflag2 = 0;
+ // TODO: Try to remove the crashflags. They really mess up the system!
+
return;
}
+
// don't reanimate a tile that's already registered--then we'd
// have multiple entries for it in animtiles[] (that's not good).
if (AnimTileInUse[px>>4][py>>4])
- {
return;
- }
// find an unused slot in animtiles
for(i=1;iControl.levelcontrol.episode = pCKP->GameData[pCKP->Resources.GameSelected-1].Episode;
//if (latch_loadgraphics(pCKP->Control.levelcontrol.episode, pCKP->GameData[0].DataDirectory)) return abortCKP(pCKP);
- if (Game->getLatch()->loadGraphics(pCKP->Control.levelcontrol.episode, pCKP->GameData[0].DataDirectory)) return abortCKP(pCKP);
+ //if (Game->getLatch()->loadGraphics(pCKP->Control.levelcontrol.episode, pCKP->GameData[0].DataDirectory)) return abortCKP(pCKP);
+ Game->loadResources(pCKP->Control.levelcontrol.episode, pCKP->GameData[0].DataDirectory);
player[0].x = player[0].y = 0;
if(initgamefirsttime(pCKP, 0) != 0)
@@ -563,7 +564,7 @@ void OptionsDlg(stCloneKeenPlus *pCKP)
// Prepare the Games Menu
OptionsMenu = new CDialog();
- OptionsMenu->setDimensions(4,4,32,11);
+ OptionsMenu->setDimensions(3,3,34,12);
for( i = 0 ; i < NUM_OPTIONS ; i++ )
{
@@ -773,35 +774,10 @@ short GraphicsDlg(stCloneKeenPlus *pCKP)
if(selection == 0)
{
// Now the part of the resolution list
- switch(width)
- {
- case 320:
- width = 640;
- height = 480;
- break;
- case 640:
- width = 800;
- height = 600;
- break;
- case 800:
- width = 1024;
- height = 768;
- break;
- case 1024:
- width = 1280;
- height = 1024;
- break;
- case 1280:
- width = 1680;
- height = 1050;
- break;
- default:
- width = 320;
- height = 240;
- break;
- }
+ st_resolution Resolution;
+ Resolution = g_pVideoDriver->setNextResolution();
- sprintf(buf,"Resolution: %dx%dx%d",width,height,depth);
+ sprintf(buf,"Resolution: %dx%dx%d", Resolution.width, Resolution.height, Resolution.depth);
DisplayMenu->setOptionText(selection,buf);
}
else if(selection == 1)
@@ -878,7 +854,7 @@ short GraphicsDlg(stCloneKeenPlus *pCKP)
}
else if(selection == 6)
{
- if(autoframeskip < 70 && autoframeskip >= 0)
+ if(autoframeskip < 70)
{
autoframeskip += 10;
sprintf(buf,"Auto-Frameskip : %d fps", autoframeskip);
@@ -912,23 +888,23 @@ short GraphicsDlg(stCloneKeenPlus *pCKP)
g_pVideoDriver->enableOpenGL(opengl);
g_pVideoDriver->setOGLFilter(gl_filter);
- g_pVideoDriver->setMode(width,height,depth);
g_pVideoDriver->setZoom(zoom);
g_pVideoDriver->setFilter(filter);
g_pVideoDriver->setFrameskip(frameskip);
g_pVideoDriver->setTargetFPS(autoframeskip);
g_pVideoDriver->setAspectCorrection(aspect);
- CSettings *Settings;
- Settings = new CSettings();
- Settings->saveDrvCfg();
- delete Settings; Settings = NULL;
-
// initialize/activate all drivers
g_pLogFile->ftextOut("Restarting graphics driver... (Menu)
");
if (g_pVideoDriver->start())
retval = 1;
+ CSettings *Settings;
+ Settings = new CSettings();
+
+ Settings->saveDrvCfg();
+ delete Settings; Settings = NULL;
+
showmapatpos(90, MAINMENU_X, MENUS_Y, 0, pCKP);
fade.mode = FADE_GO;
diff --git a/src/misc.cpp b/src/misc.cpp
index 5dee33eb8..7106f8872 100644
--- a/src/misc.cpp
+++ b/src/misc.cpp
@@ -39,7 +39,7 @@ char buf[80];
printf("%s", buf);
printf(" (%d bit)", static_cast (sizeof(int*)*8));
- printf("\nby Caitlin Shaw, 2003-2005\nand Gerstrong 2008-2009\n");
+ printf("\nby The CloneKeenPlus Team 2009\n");
printf("\n");
printf("BY A FAN, FOR FANS. ALL \"COMMANDER KEEN\" GRAPHICS,\n");
printf("SOUND, AND LEVEL FILES ARE THE PROPERTY OF ID SOFTWARE.\n");
@@ -165,11 +165,6 @@ int i;
if(map.mapdata[mpx][mpy] >= 435 && map.mapdata[mpx][mpy] <= 438)
isgarg = true;
- for(i=0; i < 4 ; i++)
- {
- player[0].playcontrol[PA_JUMP+i] = 0;
- }
-
if (!isgarg)
{
if(!map_isanimated(mpx, mpy))
@@ -181,10 +176,12 @@ int i;
return;
}
- #define TWIRL_SPEED 50
+ for(i=0; i < 4 ; i++)
+ {
+ player[0].playcontrol[PA_JUMP+i] = 0;
+ }
-
- //sound_pause();
+ const int twirl_speed = 100;
// get the name of the string we need to display
sprintf(strname, "EP1_YSIYM_LVL%d", pCKP->Control.levelcontrol.curlevel);
@@ -200,14 +197,11 @@ int i;
g_pGraphics->drawFont((unsigned char*) getstring(strname), (dlgX+1)<<3, (dlgY+1)<<3,0);
twirlframe = 0;
- twirltimer = TWIRL_SPEED+1;
+ twirltimer = twirl_speed+1;
// wait for enter
do
{
-
-
-
- if (twirltimer>TWIRL_SPEED)
+ if (twirltimer>twirl_speed)
{
g_pGraphics->drawCharacter((dlgX+twirlX)<<3, (dlgY+twirlY)<<3, 9+twirlframe);
g_pVideoDriver->update_screen();
@@ -232,27 +226,19 @@ int i;
map_chgtile(mpx, mpy, 434);
map_deanimate(mpx, mpy);
}
-
- //sound_resume();
-
}
void VorticonElder(int mpx, int mpy, stCloneKeenPlus *pCKP)
{
-int twirlframe, twirltimer;
-int dlgX,dlgY,dlgW,dlgH,twirlX,twirlY;
-const char *strName;
+ int twirlframe, twirltimer;
+ int dlgX,dlgY,dlgW,dlgH,twirlX,twirlY;
+ const char *strName;
+ const int twirl_speed = 100;
-int i;
-for(i=0; i < 4 ; i++)
-{
- player[0].playcontrol[PA_JUMP+i] = 0;
-}
-
- #define TWIRL_SPEED 50
-
- if(usedinfobox == 1)
- return;
+ for(int i=0; i < 4 ; i++)
+ {
+ player[0].playcontrol[PA_JUMP+i] = 0;
+ }
g_pSound->pauseSound();
@@ -282,11 +268,11 @@ for(i=0; i < 4 ; i++)
g_pGraphics->drawFont( (unsigned char*) getstring(strName), (dlgX+1)<<3, (dlgY+1)<<3,0);
twirlframe = 0;
- twirltimer = TWIRL_SPEED+1;
+ twirltimer = twirl_speed+1;
// wait for enter
do
{
- if (twirltimer>TWIRL_SPEED)
+ if (twirltimer>twirl_speed)
{
g_pGraphics->drawCharacter((dlgX+twirlX)<<3, (dlgY+twirlY)<<3, 9+twirlframe);
g_pVideoDriver->update_screen();
@@ -297,17 +283,14 @@ for(i=0; i < 4 ; i++)
g_pInput->pollEvents();
g_pTimer->SpeedThrottle();
g_pVideoDriver->update_screen();
- } while(!g_pInput->getPressedKey(KENTER) /*&& !immediate_keytable[KQUIT] && !getanyevent(pCKP)*/);
+ } while(!g_pInput->getPressedKey(KENTER) );
// make the switch stop glowing
map_chgtile(mpx, mpy+1, 432);
- //tiles[432].isAnimated = 0;
map_deanimate(mpx, mpy+1);
g_pSound->resumeSounds();
-
- usedinfobox = 1;
}
@@ -335,10 +318,47 @@ int dlgX,dlgY,dlgW,dlgH;
// pogo
if (player[p].inventory.HasPogo) g_pGraphics->drawTile_direct(((dlgX+12)<<3)+4, ((dlgY+9)<<3)+3, 415);
// cards
- if (player[p].inventory.HasCardYellow) g_pGraphics->drawTile_direct((dlgX+21)<<3, ((dlgY+8)<<3)+3, 424);
- if (player[p].inventory.HasCardRed) g_pGraphics->drawTile_direct((dlgX+25)<<3, ((dlgY+8)<<3)+3, 425);
- if (player[p].inventory.HasCardGreen) g_pGraphics->drawTile_direct((dlgX+21)<<3, ((dlgY+10)<<3)+4, 426);
- if (player[p].inventory.HasCardBlue) g_pGraphics->drawTile_direct((dlgX+25)<<3, ((dlgY+10)<<3)+4, 427);
+ if (player[p].inventory.HasCardYellow)
+ {
+ g_pGraphics->drawTile_direct((dlgX+21)<<3, ((dlgY+8)<<3)+3, 424);
+ if(player[p].inventory.HasCardYellow > 1)
+ {
+ char buf[10];
+ sprintf(buf,"%d",player[p].inventory.HasCardYellow);
+ g_pGraphics->drawFont((unsigned char*)buf,(dlgX+20)<<3,((dlgY+8)<<3)+3,0);
+ }
+ }
+ if (player[p].inventory.HasCardRed)
+ {
+ g_pGraphics->drawTile_direct((dlgX+25)<<3, ((dlgY+8)<<3)+3, 425);
+ if(player[p].inventory.HasCardRed > 1)
+ {
+ char buf[10];
+ sprintf(buf,"%d",player[p].inventory.HasCardRed);
+ g_pGraphics->drawFont((unsigned char*) buf,(dlgX+24)<<3,((dlgY+8)<<3)+3,0);
+ }
+ }
+ if (player[p].inventory.HasCardGreen)
+ {
+ g_pGraphics->drawTile_direct((dlgX+21)<<3, ((dlgY+10)<<3)+4, 426);
+
+ if (player[p].inventory.HasCardGreen > 1)
+ {
+ char buf[10];
+ sprintf(buf,"%d",player[p].inventory.HasCardGreen);
+ g_pGraphics->drawFont((unsigned char*) buf,(dlgX+20)<<3,((dlgY+10)<<3)+3,0);
+ }
+ }
+ if (player[p].inventory.HasCardBlue)
+ {
+ g_pGraphics->drawTile_direct((dlgX+25)<<3, ((dlgY+10)<<3)+4, 427);
+ if(player[p].inventory.HasCardBlue > 1)
+ {
+ char buf[10];
+ sprintf(buf,"%d",player[p].inventory.HasCardBlue);
+ g_pGraphics->drawFont((unsigned char*) buf,(dlgX+24)<<3,((dlgY+10)<<3)+3,0);
+ }
+ }
// ship parts
if (player[p].inventory.HasJoystick) t=448; else t=321;
g_pGraphics->drawTile_direct((dlgX+18)<<3, ((dlgY+4)<<3)+3, t);
@@ -392,10 +412,46 @@ int dlgX,dlgY,dlgW,dlgH;
g_pGraphics->drawFont( (unsigned char*) getstring("EP2_StatusBox"), (dlgX+1)<<3, (dlgY+1)<<3, 0);
// cards
- if (player[p].inventory.HasCardYellow) g_pGraphics->drawTile_direct(((dlgX+21)<<3)-4, ((dlgY+8)<<3)+3, 424);
- if (player[p].inventory.HasCardRed) g_pGraphics->drawTile_direct(((dlgX+25)<<3)-4, ((dlgY+8)<<3)+3, 425);
- if (player[p].inventory.HasCardGreen) g_pGraphics->drawTile_direct(((dlgX+21)<<3)-4, ((dlgY+10)<<3)+4, 426);
- if (player[p].inventory.HasCardBlue) g_pGraphics->drawTile_direct(((dlgX+25)<<3)-4, ((dlgY+10)<<3)+4, 427);
+ if (player[p].inventory.HasCardYellow)
+ {
+ g_pGraphics->drawTile_direct(((dlgX+21)<<3)-4, ((dlgY+8)<<3)+3, 424);
+ if(player[p].inventory.HasCardYellow > 1)
+ {
+ char buf[10];
+ sprintf(buf,"%d",player[p].inventory.HasCardYellow);
+ g_pGraphics->drawFont((unsigned char*)buf,(dlgX+20)<<3,((dlgY+8)<<3)+3,0);
+ }
+ }
+ if (player[p].inventory.HasCardRed)
+ {
+ g_pGraphics->drawTile_direct(((dlgX+25)<<3)-4, ((dlgY+8)<<3)+3, 425);
+ if(player[p].inventory.HasCardRed > 1)
+ {
+ char buf[10];
+ sprintf(buf,"%d",player[p].inventory.HasCardRed);
+ g_pGraphics->drawFont((unsigned char*)buf,(dlgX+24)<<3,((dlgY+8)<<3)+3,0);
+ }
+ }
+ if (player[p].inventory.HasCardGreen)
+ {
+ g_pGraphics->drawTile_direct(((dlgX+21)<<3)-4, ((dlgY+10)<<3)+4, 426);
+ if(player[p].inventory.HasCardGreen > 1)
+ {
+ char buf[10];
+ sprintf(buf,"%d",player[p].inventory.HasCardGreen);
+ g_pGraphics->drawFont((unsigned char*)buf,(dlgX+20)<<3,((dlgY+10)<<3)+3,0);
+ }
+ }
+ if (player[p].inventory.HasCardBlue)
+ {
+ g_pGraphics->drawTile_direct(((dlgX+25)<<3)-4, ((dlgY+10)<<3)+4, 427);
+ if(player[p].inventory.HasCardBlue > 1)
+ {
+ char buf[10];
+ sprintf(buf,"%d",player[p].inventory.HasCardBlue);
+ g_pGraphics->drawFont((unsigned char*)buf,(dlgX+24)<<3,((dlgY+10)<<3)+3,0);
+ }
+ }
// cities saved
if (p_levelcontrol->levels_completed[4]) g_pGraphics->drawFont( (unsigned char*) getstring("EP2_LVL4_TargetName"), (dlgX+1)<<3, (dlgY+8)<<3, 0);
if (p_levelcontrol->levels_completed[6]) g_pGraphics->drawFont( (unsigned char*) getstring("EP2_LVL6_TargetName"), (dlgX+8)<<3, (dlgY+8)<<3, 0);
@@ -468,10 +524,46 @@ int dlgX,dlgY,dlgW,dlgH;
g_pGraphics->drawFont( (unsigned char*) tempbuf, (dlgX+26)<<3, ((dlgY+5)<<3)-1, 0);
// cards
- if (player[p].inventory.HasCardYellow) g_pGraphics->drawTile_direct(((dlgX+14)<<3)+4, ((dlgY+8)<<3)+4, 217);
- if (player[p].inventory.HasCardRed) g_pGraphics->drawTile_direct(((dlgX+18)<<3)+4, ((dlgY+8)<<3)+4, 218);
- if (player[p].inventory.HasCardGreen) g_pGraphics->drawTile_direct(((dlgX+22)<<3)+4, ((dlgY+8)<<3)+4, 219);
- if (player[p].inventory.HasCardBlue) g_pGraphics->drawTile_direct(((dlgX+26)<<3)+4, ((dlgY+8)<<3)+4, 220);
+ if (player[p].inventory.HasCardYellow)
+ {
+ g_pGraphics->drawTile_direct(((dlgX+14)<<3)+4, ((dlgY+8)<<3)+4, 217);
+ if(player[p].inventory.HasCardYellow > 1)
+ {
+ char buf[10];
+ sprintf(buf,"%d",player[p].inventory.HasCardYellow);
+ g_pGraphics->drawFont((unsigned char*)buf,(dlgX+13)<<3,((dlgY+8)<<3)+3,0);
+ }
+ }
+ if (player[p].inventory.HasCardRed)
+ {
+ g_pGraphics->drawTile_direct(((dlgX+18)<<3)+4, ((dlgY+8)<<3)+4, 218);
+ if(player[p].inventory.HasCardRed > 1)
+ {
+ char buf[10];
+ sprintf(buf,"%d",player[p].inventory.HasCardRed);
+ g_pGraphics->drawFont((unsigned char*)buf,(dlgX+17)<<3,((dlgY+8)<<3)+3,0);
+ }
+ }
+ if (player[p].inventory.HasCardGreen)
+ {
+ g_pGraphics->drawTile_direct(((dlgX+22)<<3)+4, ((dlgY+8)<<3)+4, 219);
+ if(player[p].inventory.HasCardGreen > 1)
+ {
+ char buf[10];
+ sprintf(buf,"%d",player[p].inventory.HasCardGreen);
+ g_pGraphics->drawFont((unsigned char*)buf,(dlgX+21)<<3,((dlgY+8)<<3)+3,0);
+ }
+ }
+ if (player[p].inventory.HasCardBlue)
+ {
+ g_pGraphics->drawTile_direct(((dlgX+26)<<3)+4, ((dlgY+8)<<3)+4, 220);
+ if(player[p].inventory.HasCardBlue > 1)
+ {
+ char buf[10];
+ sprintf(buf,"%d",player[p].inventory.HasCardBlue);
+ g_pGraphics->drawFont((unsigned char*)buf,(dlgX+25)<<3,((dlgY+8)<<3)+3,0);
+ }
+ }
// score
i = player[p].inventory.score;
@@ -565,7 +657,7 @@ int x,y;
void YourShipNeedsTheseParts(stCloneKeenPlus *pCKP)
{
-int cp;
+int cp = 0;
int dlgX,dlgY,dlgW,dlgH;
dlgX = GetStringAttribute("EP1_SHIP", "LEFT");
@@ -573,8 +665,6 @@ int dlgX,dlgY,dlgW,dlgH;
dlgW = GetStringAttribute("EP1_SHIP", "WIDTH");
dlgH = GetStringAttribute("EP1_SHIP", "HEIGHT");
- cp = 0; // Fixme
-
dialogbox(dlgX,dlgY,dlgW,dlgH);
g_pGraphics->drawFont( (unsigned char*) getstring("EP1_SHIP"), (dlgX+1)<<3, (dlgY+1)<<3,0);
@@ -610,8 +700,7 @@ void ShipEp3(stCloneKeenPlus *pCKP)
char strname[80];
int twirlframe, twirltimer;
int dlgX,dlgY,dlgW,dlgH,twirlX,twirlY;
-
- g_pSound->pauseSound();
+const int twirlspeed = 100;
// display one of four random strings
sprintf(strname, "EP3_SHIP%d", (rand()%4)+1);
@@ -628,14 +717,15 @@ int dlgX,dlgY,dlgW,dlgH,twirlX,twirlY;
g_pVideoDriver->update_screen();
- // wait for ctrl/space/enter released then pressed again then released
+ g_pInput->flushAll();
+
twirlframe = 0;
- twirltimer = TWIRL_SPEED+1;
+ twirltimer = twirlspeed+1;
g_pInput->flushKeys();
- // wait for any key
+ // wait for any command or key
do
{
- if (twirltimer>TWIRL_SPEED)
+ if (twirltimer>twirlspeed)
{
g_pGraphics->drawCharacter((dlgX+twirlX)<<3, (dlgY+twirlY)<<3, twirlframe+9);
g_pVideoDriver->update_screen();
@@ -647,8 +737,6 @@ int dlgX,dlgY,dlgW,dlgH,twirlX,twirlY;
g_pInput->pollEvents();
g_pTimer->SpeedThrottle();
} while(!g_pInput->getPressedAnyKey());
-
- g_pSound->resumeSounds();
}
void game_save(char *fname, stCloneKeenPlus *pCKP)
@@ -1265,15 +1353,7 @@ void showTextMB(int lines, char **text, stCloneKeenPlus *pCKP)
twirlframe = 0;
twirltimer = TWIRL_SPEED+1;
- while(g_pInput->getPressedKey(KENTER))
- {
- //poll_events(pCKP);
-
- /*if (immediate_keytable[KQUIT])
- {
- return;
- }*/
- }
+ g_pInput->flushAll();
// wait for enter
do
@@ -1289,5 +1369,5 @@ void showTextMB(int lines, char **text, stCloneKeenPlus *pCKP)
g_pInput->pollEvents();
g_pTimer->SpeedThrottle();
g_pVideoDriver->update_screen();
- } while(!g_pInput->getPressedKey(KENTER)/* && !immediate_keytable[KQUIT]*/);
+ } while(!g_pInput->getPressedKey(KENTER));
}
diff --git a/src/patch2 b/src/patch2
new file mode 100644
index 000000000..24fb8a960
--- /dev/null
+++ b/src/patch2
@@ -0,0 +1,29 @@
+Index: src/sdl/CVideoDriver.cpp
+===================================================================
+--- src/sdl/CVideoDriver.cpp (revision 30)
++++ src/sdl/CVideoDriver.cpp (working copy)
+@@ -161,7 +161,9 @@
+ Mode = SDL_HWPALETTE;
+
+ // Support for doublebuffering
++#ifndef WIZ
+ Mode |= SDL_DOUBLEBUF;
++#endif
+
+ // Enable OpenGL
+ #ifdef USE_OPENGL
+Index: src/sdl/CVideoDriver.h
+===================================================================
+--- src/sdl/CVideoDriver.h (revision 30)
++++ src/sdl/CVideoDriver.h (working copy)
+@@ -69,9 +69,9 @@
+ void setFrameskip(unsigned short value);
+ void setFilter(short value);
+ void setZoom(short vale);
++ bool initOpenGL();
+ #ifdef USE_OPENGL
+ void enableOpenGL(bool value) { m_opengl = value; }
+- bool initOpenGL();
+ void setOGLFilter(unsigned char value) { m_opengl_filter = (value==1) ? GL_LINEAR : GL_NEAREST ; }
+ #else
+ void enableOpenGL(bool value) { m_opengl = false; }
diff --git a/src/patch20092006 b/src/patch20092006
new file mode 100644
index 000000000..24fb8a960
--- /dev/null
+++ b/src/patch20092006
@@ -0,0 +1,29 @@
+Index: src/sdl/CVideoDriver.cpp
+===================================================================
+--- src/sdl/CVideoDriver.cpp (revision 30)
++++ src/sdl/CVideoDriver.cpp (working copy)
+@@ -161,7 +161,9 @@
+ Mode = SDL_HWPALETTE;
+
+ // Support for doublebuffering
++#ifndef WIZ
+ Mode |= SDL_DOUBLEBUF;
++#endif
+
+ // Enable OpenGL
+ #ifdef USE_OPENGL
+Index: src/sdl/CVideoDriver.h
+===================================================================
+--- src/sdl/CVideoDriver.h (revision 30)
++++ src/sdl/CVideoDriver.h (working copy)
+@@ -69,9 +69,9 @@
+ void setFrameskip(unsigned short value);
+ void setFilter(short value);
+ void setZoom(short vale);
++ bool initOpenGL();
+ #ifdef USE_OPENGL
+ void enableOpenGL(bool value) { m_opengl = value; }
+- bool initOpenGL();
+ void setOGLFilter(unsigned char value) { m_opengl_filter = (value==1) ? GL_LINEAR : GL_NEAREST ; }
+ #else
+ void enableOpenGL(bool value) { m_opengl = false; }
diff --git a/src/sdl/CSettings.cpp b/src/sdl/CSettings.cpp
index 5bafe7526..a89d6b710 100644
--- a/src/sdl/CSettings.cpp
+++ b/src/sdl/CSettings.cpp
@@ -40,7 +40,6 @@ short CSettings::saveDrvCfg(void)
else
Parser.saveIntValue("OpenGL","Video",0);
-
Parser.saveIntValue("width","Video",g_pVideoDriver->getWidth());
Parser.saveIntValue("height","Video",g_pVideoDriver->getHeight());
Parser.saveIntValue("scale","Video",g_pVideoDriver->getZoomValue());
@@ -79,8 +78,7 @@ short CSettings::loadDrvCfg(void)
if(depth*width*height < 0)
g_pLogFile->ftextOut(RED,"Error reading the configuration file. It appears to be damaged!");
- g_pVideoDriver->setMode(width, height, depth);
-
+ g_pVideoDriver->setMode(width,height,depth);
g_pVideoDriver->setFrameskip(Parser.getIntValue("frameskip","Video"));
if((Parser.getIntValue("fullscreen","Video")) == 1)
@@ -123,6 +121,7 @@ void CSettings::loadDefaultGameCfg(stOption *Option)
setOption(Option,OPT_TWOBUTTON, "two-button-firing", 0);
setOption(Option,OPT_KEYCARDSTACK, "keycard-stacking", 0);
setOption(Option,OPT_ANALOGJOYSTICK, "analog-joystick", 1);
+ setOption(Option,OPT_LVLREPLAYABILITY, "level replayability", 0);
}
short CSettings::loadGameCfg(stOption *Option)
diff --git a/src/sdl/CSettings.h b/src/sdl/CSettings.h
index 4fc2d974e..f60dd206e 100644
--- a/src/sdl/CSettings.h
+++ b/src/sdl/CSettings.h
@@ -8,15 +8,13 @@
#ifndef CSETTINGS_H_
#define CSETTINGS_H_
-#define OPT_FULLYAUTOMATIC 0
-#define OPT_SUPERPOGO 1
-#define OPT_ALLOWPKING 2
-#define OPT_CHEATS 3
-#define OPT_TWOBUTTON 4
-#define OPT_KEYCARDSTACK 5
-#define OPT_ANALOGJOYSTICK 6
+enum e_OptionKeywords
+{ OPT_FULLYAUTOMATIC, OPT_SUPERPOGO,
+ OPT_ALLOWPKING, OPT_CHEATS,
+ OPT_TWOBUTTON, OPT_KEYCARDSTACK,
+OPT_ANALOGJOYSTICK, OPT_LVLREPLAYABILITY };
-#define NUM_OPTIONS 7
+#define NUM_OPTIONS 8
typedef struct stOption
{
diff --git a/src/sdl/CVideoDriver.cpp b/src/sdl/CVideoDriver.cpp
index 259044818..58f0f1244 100644
--- a/src/sdl/CVideoDriver.cpp
+++ b/src/sdl/CVideoDriver.cpp
@@ -14,6 +14,9 @@
#include "../scale2x/scalebit.h"
#include "../CLogFile.h"
#include "../CGraphics.h"
+#include
+#include
+using namespace std;
#define CKLOGFILENAME "genius.log"
@@ -48,9 +51,9 @@ CVideoDriver::CVideoDriver() {
showfps=true;
#ifdef WIZ
- Width=320;
- Height=240;
- Depth=16;
+ m_Resolution.width=320;
+ m_Resolution.height=240;
+ m_Resolution.depth=16;
Mode=0;
Fullscreen=true;
Filtermode=0;
@@ -58,9 +61,9 @@ CVideoDriver::CVideoDriver() {
FrameSkip=0;
m_targetfps = 30; // Enable automatic frameskipping by default at 30
#else
- Width=640;
- Height=480;
- Depth=0;
+ m_Resolution.width=640;
+ m_Resolution.height=480;
+ m_Resolution.depth=0;
Mode=0;
Fullscreen=false;
Filtermode=1;
@@ -84,12 +87,79 @@ CVideoDriver::CVideoDriver() {
FGLayerSurface=NULL; // Scroll buffer for Messages
BGLayerSurface=NULL;
BlitSurface=NULL;
+
+ m_Resolution_pos = m_Resolutionlist.begin();
+
+ initResolutionList();
}
CVideoDriver::~CVideoDriver() {
stop();
}
+void CVideoDriver::initResolutionList()
+{
+ st_resolution resolution;
+ char buf[256];
+
+ ifstream ResolutionFile("resolutions.cfg");
+ if(!ResolutionFile)
+ {
+ g_pLogFile->textOut(PURPLE,"Warning: resolutions.cfg could not be read! Maybe your files weren't extracted correctly!
");
+
+ resolution.width = 320;
+ resolution.height = 240;
+ resolution.depth = 16;
+ m_Resolutionlist.push_back(resolution);
+
+ resolution.depth = 32;
+ m_Resolutionlist.push_back(resolution);
+ }
+ else
+ {
+ while(!ResolutionFile.eof())
+ {
+ ResolutionFile.getline(buf,256);
+ if(sscanf(buf,"%hdx%hdx%hd", &resolution.width,
+ &resolution.height,
+ &resolution.depth) == 3)
+ m_Resolutionlist.push_back(resolution);
+ }
+ }
+ ResolutionFile.close();
+}
+
+st_resolution CVideoDriver::setNextResolution()
+{
+ m_Resolution_pos++;
+
+ if(m_Resolution_pos == m_Resolutionlist.end())
+ m_Resolution_pos = m_Resolutionlist.begin();
+
+ return *m_Resolution_pos;
+}
+
+void CVideoDriver::setMode(int width, int height,int depth)
+{
+ m_Resolution.width = width;
+ m_Resolution.height = height;
+ m_Resolution.depth = depth;
+
+ // TODO: Cycle through the list until the matching resolution is matched. If it doesn't exist
+ // add it;
+ for(m_Resolution_pos = m_Resolutionlist.begin() ; m_Resolution_pos != m_Resolutionlist.end() ; m_Resolution_pos++)
+ if( m_Resolution_pos->width == width )
+ if( m_Resolution_pos->height == height )
+ if( m_Resolution_pos->depth == depth )
+ break;
+
+ if(m_Resolution_pos == m_Resolutionlist.end())
+ {
+ m_Resolutionlist.push_back(m_Resolution);
+ m_Resolution_pos--;
+ }
+}
+
void CVideoDriver::stop(void)
{
if(screen) { SDL_FreeSurface(screen); g_pLogFile->textOut("freed screen
"); screen = NULL; }
@@ -137,7 +207,8 @@ bool CVideoDriver::initOpenGL()
if(m_opengl) // If OpenGL could be set, initialize the matrices
{
mp_OpenGL = new COpenGL();
- if(!(mp_OpenGL->initGL(Width, Height, Depth, m_opengl_filter, Filtermode+1, m_aspect_correction)))
+ if(!(mp_OpenGL->initGL(m_Resolution.width, m_Resolution.height, m_Resolution.depth,
+ m_opengl_filter, Filtermode+1, m_aspect_correction)))
{
delete mp_OpenGL;
mp_OpenGL = NULL;
@@ -155,12 +226,15 @@ bool CVideoDriver::applyMode(void)
{
// Check if some zoom/filter modes are illogical
// TODO: Make this call clearer to understand
+ // TODO: Improve this function.
+ // It must be able to change the resolution, and if it fails, roll back.
if( (Zoom == 3 && Filtermode == 1) && !m_opengl )
Zoom = 2;
// Grab a surface on the screen
- Mode = SDL_HWPALETTE;
+ Mode = SDL_HWPALETTE | SDL_HWSURFACE;
+ m_Resolution = *m_Resolution_pos;
#ifndef WIZ
// Support for doublebuffering
@@ -182,24 +256,26 @@ bool CVideoDriver::applyMode(void)
Mode |= SDL_FULLSCREEN;
// Before the resolution is set, check, if the zoom factor is too high!
- while(((Width/GAME_STD_WIDTH) < Zoom || (Height/GAME_STD_HEIGHT) < Zoom) && (Zoom > 1))
+ while(((m_Resolution.width/GAME_STD_WIDTH) < Zoom || (m_Resolution.height/GAME_STD_HEIGHT) < Zoom) && (Zoom > 1))
Zoom--;
// Try to center the screen!
screenrect.w = blitrect.w = GAME_STD_WIDTH*Zoom;
screenrect.h = blitrect.h = GAME_STD_HEIGHT*Zoom;
- screenrect.x = (Width-screenrect.w)>>1;
- if(Width == 320)
+ screenrect.x = (m_Resolution.width-screenrect.w)>>1;
+
+ if(m_Resolution.width == 320)
screenrect.y = 0;
else
- screenrect.y = (Height-screenrect.h)>>1;
+ screenrect.y = (m_Resolution.height-screenrect.h)>>1;
blitrect.x = 0;
blitrect.y = 0;
// And Display can be setup.
- screen = SDL_SetVideoMode(Width,Height,Depth,Mode);
+ screen = SDL_SetVideoMode(m_Resolution.width,m_Resolution.height,m_Resolution.depth,Mode);
+
+ m_Resolution.depth = screen->format->BitsPerPixel;
- Depth = screen->format->BitsPerPixel;
if( !screen )
{
@@ -214,14 +290,6 @@ bool CVideoDriver::applyMode(void)
return true;
}
-
-void CVideoDriver::setMode(unsigned int srcW, unsigned int srcH,
- unsigned short srcD)
-{
- Width = srcW;
- Height = srcH;
- Depth = srcD;
-}
void CVideoDriver::setFrameskip(unsigned short value)
{
FrameSkip = value;
@@ -250,7 +318,7 @@ bool CVideoDriver::createSurfaces(void)
return false;
}
- BGLayerSurface = SDL_CreateRGBSurface(Mode,320, 200, Depth, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
+ BGLayerSurface = SDL_CreateRGBSurface(Mode,320, 200, m_Resolution.depth, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
if (!BGLayerSurface)
{
g_pLogFile->textOut(RED,"VideoDriver: Couldn't create BGLayerSurface!
");
@@ -258,7 +326,7 @@ bool CVideoDriver::createSurfaces(void)
}
- FGLayerSurface = SDL_CreateRGBSurface(Mode,320, 200, Depth, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
+ FGLayerSurface = SDL_CreateRGBSurface(Mode,320, 200, m_Resolution.depth, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
if (!FGLayerSurface)
{
g_pLogFile->textOut(RED,"VideoDriver: Couldn't create FGLayerSurface!
");
@@ -270,24 +338,26 @@ bool CVideoDriver::createSurfaces(void)
//Set surface alpha
SDL_SetAlpha( FGLayerSurface, SDL_SRCALPHA, 225 );
- if(Width == 320 && !m_opengl)
+ if(m_Resolution.width == 320 && !m_opengl)
{
g_pLogFile->textOut("Blitsurface = Screen
");
BlitSurface = screen;
blitsurface_alloc = 0;
- VRAMPtr = (unsigned char*)screen->pixels + ((Width * stretch_blit_yoff * Depth)>>3)+screenrect.y*screen->pitch + (screenrect.x*Depth>>3);
+ VRAMPtr = (unsigned char*)screen->pixels +
+ ((m_Resolution.width * stretch_blit_yoff * m_Resolution.depth)>>3)+
+ screenrect.y*screen->pitch + (screenrect.x*m_Resolution.depth>>3);
}
else
{
g_pLogFile->textOut("Blitsurface = creatergbsurfacefrom
");
- BlitSurface = SDL_CreateRGBSurface(Mode,GAME_STD_WIDTH, GAME_STD_HEIGHT, Depth, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
+ BlitSurface = SDL_CreateRGBSurface(Mode,GAME_STD_WIDTH, GAME_STD_HEIGHT, m_Resolution.depth, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
if (!BlitSurface)
{
g_pLogFile->textOut(RED,"VidDrv_Start(): Couldn't create BlitSurface!
");
return false;
}
blitsurface_alloc = 1;
- VRAMPtr = (unsigned char*)screen->pixels + ((Width * stretch_blit_yoff * Depth)>>3)+screenrect.y*screen->pitch + (screenrect.x*Depth>>3);
+ VRAMPtr = (unsigned char*)screen->pixels + ((m_Resolution.width * stretch_blit_yoff * m_Resolution.depth)>>3)+screenrect.y*screen->pitch + (screenrect.x*m_Resolution.depth>>3);
}
dstrect.x = 0; dstrect.y = 0;
@@ -324,13 +394,14 @@ char wraphoz, wrapvrt;
int save_dstx, save_dstw, save_srcx, save_srcw;
char tempbuf[80];
- blitBGLayer();
-
dstrect.x = 0; dstrect.y = 0;
dstrect.w = 320; dstrect.h = 200;
srcrect.x = scrollx_buf;
srcrect.y = scrolly_buf;
+
+ blitBGLayer();
+
if (scrollx_buf > (512-320))
{ // need to wrap right side
srcrect.w = (512-scrollx_buf);
@@ -367,6 +438,7 @@ char tempbuf[80];
srcrect.x = 0;
srcrect.w = (320 - srcrect.w);
SDL_BlitSurface(ScrollSurface, &srcrect, BlitSurface, &dstrect);
+
// now repeat for the bottom
// (lower-right square)
dstrect.y = srcrect.h;
@@ -440,14 +512,14 @@ void CVideoDriver::update_screen(void)
// if we're doing zoom then we have copied the scroll buffer into
// another offscreen buffer, and must now stretchblit it to the screen
- if (Zoom == 1 && Width != 320 )
+ if (Zoom == 1 && m_Resolution.width != 320 )
{
LockSurface(BlitSurface);
LockSurface(screen);
if(Filtermode == 0)
{
- noscale((char*)VRAMPtr, (char*)BlitSurface->pixels, (Depth>>3));
+ noscale((char*)VRAMPtr, (char*)BlitSurface->pixels, (m_Resolution.depth>>3));
}
else
{
@@ -465,12 +537,12 @@ void CVideoDriver::update_screen(void)
if(Filtermode == 0)
{
- scale2xnofilter((char*)VRAMPtr, (char*)BlitSurface->pixels, (Depth>>3));
+ scale2xnofilter((char*)VRAMPtr, (char*)BlitSurface->pixels, (m_Resolution.depth>>3));
}
else if(Filtermode == 1)
{
- scale(2, VRAMPtr, Width*(Depth>>3), BlitSurface->pixels,
- GAME_STD_WIDTH*(Depth>>3), (Depth>>3), GAME_STD_WIDTH, GAME_STD_HEIGHT);
+ scale(2, VRAMPtr, m_Resolution.width*(m_Resolution.depth>>3), BlitSurface->pixels,
+ GAME_STD_WIDTH*(m_Resolution.depth>>3), (m_Resolution.depth>>3), GAME_STD_WIDTH, GAME_STD_HEIGHT);
}
else
{
@@ -489,17 +561,17 @@ void CVideoDriver::update_screen(void)
if(Filtermode == 0)
{
- scale3xnofilter((char*)VRAMPtr, (char*)BlitSurface->pixels, (Depth>>3));
+ scale3xnofilter((char*)VRAMPtr, (char*)BlitSurface->pixels, (m_Resolution.depth>>3));
}
else if(Filtermode == 1)
{
- scale(2, VRAMPtr, Width*(Depth>>3), BlitSurface->pixels,
- GAME_STD_WIDTH*(Depth>>3), (Depth>>3), GAME_STD_WIDTH, GAME_STD_HEIGHT);
+ scale(2, VRAMPtr, m_Resolution.width*(m_Resolution.depth>>3), BlitSurface->pixels,
+ GAME_STD_WIDTH*(m_Resolution.depth>>3), (m_Resolution.depth>>3), GAME_STD_WIDTH, GAME_STD_HEIGHT);
}
else if(Filtermode == 2)
{
- scale(3, VRAMPtr, Width*(Depth>>3), BlitSurface->pixels,
- GAME_STD_WIDTH*(Depth>>3), (Depth>>3), GAME_STD_WIDTH, GAME_STD_HEIGHT);
+ scale(3, VRAMPtr, m_Resolution.width*(m_Resolution.depth>>3), BlitSurface->pixels,
+ GAME_STD_WIDTH*(m_Resolution.depth>>3), (m_Resolution.depth>>3), GAME_STD_WIDTH, GAME_STD_HEIGHT);
}
else
{
@@ -517,22 +589,22 @@ void CVideoDriver::update_screen(void)
if(Filtermode == 0)
{
- scale4xnofilter((char*)VRAMPtr, (char*)BlitSurface->pixels, (Depth>>3));
+ scale4xnofilter((char*)VRAMPtr, (char*)BlitSurface->pixels, (m_Resolution.depth>>3));
}
else if(Filtermode == 1)
{
- scale(2, VRAMPtr, Width*(Depth>>3), BlitSurface->pixels,
- GAME_STD_WIDTH*(Depth>>3), (Depth>>3), GAME_STD_WIDTH, GAME_STD_HEIGHT);
+ scale(2, VRAMPtr, m_Resolution.width*(m_Resolution.depth>>3), BlitSurface->pixels,
+ GAME_STD_WIDTH*(m_Resolution.depth>>3), (m_Resolution.depth>>3), GAME_STD_WIDTH, GAME_STD_HEIGHT);
}
else if(Filtermode == 2)
{
- scale(3, VRAMPtr, Width*(Depth>>3), BlitSurface->pixels,
- GAME_STD_WIDTH*(Depth>>3), (Depth>>3), GAME_STD_WIDTH, GAME_STD_HEIGHT);
+ scale(3, VRAMPtr, m_Resolution.width*(m_Resolution.depth>>3), BlitSurface->pixels,
+ GAME_STD_WIDTH*(m_Resolution.depth>>3), (m_Resolution.depth>>3), GAME_STD_WIDTH, GAME_STD_HEIGHT);
}
else if(Filtermode == 3)
{
- scale(4, VRAMPtr, Width*(Depth>>3), BlitSurface->pixels,
- GAME_STD_WIDTH*(Depth>>3), (Depth>>3), GAME_STD_WIDTH, GAME_STD_HEIGHT);
+ scale(4, VRAMPtr, m_Resolution.width*(m_Resolution.depth>>3), BlitSurface->pixels,
+ GAME_STD_WIDTH*(m_Resolution.depth>>3), (m_Resolution.depth>>3), GAME_STD_WIDTH, GAME_STD_HEIGHT);
}
else
{
@@ -562,7 +634,7 @@ void CVideoDriver::noscale(char *dest, char *src, short bbp)
// just passes a blitsurface to the screen
int i;
for(i=0 ; i < 200 ; i++)
- memcpy(dest+(i*Width)*bbp,src+(i*GAME_STD_WIDTH)*bbp,320*bbp);
+ memcpy(dest+(i*m_Resolution.width)*bbp,src+(i*GAME_STD_WIDTH)*bbp,320*bbp);
}
void CVideoDriver::scale2xnofilter(char *dest, char *src, short bbp)
@@ -577,10 +649,10 @@ void CVideoDriver::scale2xnofilter(char *dest, char *src, short bbp)
{
for(j = 0; j < 320 ; j++)
{
- memcpy(dest+((j<<1)<textOut("freed screen
"); screen = NULL; }
+ if(ScrollSurface && (ScrollSurface->map != NULL)) { SDL_FreeSurface(ScrollSurface); g_pLogFile->textOut("freed scrollsurface
"); ScrollSurface = NULL; }
+ if(blitsurface_alloc) { blitsurface_alloc = 0; SDL_FreeSurface(BlitSurface); g_pLogFile->textOut("freed blitsurface
"); BlitSurface=NULL; }
+#ifdef USE_OPENGL
+ if(mp_OpenGL) { delete mp_OpenGL; mp_OpenGL = NULL; }
+#endif
+ g_pLogFile->textOut(GREEN,"CVideoDriver Close%s
", SDL_GetError());
+}
+
+
+bool CVideoDriver::start(void)
+{
+ bool retval = false;
+
+ if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_AUDIO) < 0)
+ {
+ g_pLogFile->textOut(RED,"Could not initialize SDL: %s
", SDL_GetError());
+ return false;
+ }
+ else
+ g_pLogFile->textOut(GREEN,"SDL was successfully initialized!
");
+
+ SDL_WM_SetCaption("Commander Genius (CKP)", NULL);
+ // When the program is through executing, call SDL_Quit
+ atexit(SDL_Quit);
+
+ if(!applyMode())
+ {
+ g_pLogFile->textOut(RED,"VideoDriver: Error applying mode! Your Videocard doesn't seem to work on CKP
");
+ g_pLogFile->textOut(RED,"Check, if you have the most recent drivers installed!
");
+ return false;
+ }
+
+ retval = createSurfaces();
+ initOpenGL();
+
+ return retval;
+}
+
+bool CVideoDriver::initOpenGL()
+{
+#ifdef USE_OPENGL
+ if(m_opengl) // If OpenGL could be set, initialize the matrices
+ {
+ mp_OpenGL = new COpenGL();
+ if(!(mp_OpenGL->initGL(Width, Height, Depth, m_opengl_filter, Filtermode+1, m_aspect_correction)))
+ {
+ delete mp_OpenGL;
+ mp_OpenGL = NULL;
+ m_opengl = false;
+ }
+ else
+ mp_OpenGL->setSurface(BlitSurface);
+ }
+#endif
+
+ return m_opengl;
+}
+
+bool CVideoDriver::applyMode(void)
+{
+ // Check if some zoom/filter modes are illogical
+ // TODO: Make this call clearer to understand
+ if( (Zoom == 3 && Filtermode == 1) && !m_opengl )
+ Zoom = 2;
+
+ // Grab a surface on the screen
+ Mode = SDL_HWPALETTE;
+
+ // Support for doublebuffering
+ Mode |= SDL_DOUBLEBUF;
+
+ // Enable OpenGL
+#ifdef USE_OPENGL
+ if(m_opengl)
+ {
+ SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
+ SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
+ Mode |= SDL_OPENGL;
+ }
+#endif
+
+ // Now we decide if it will be fullscreen or windowed mode.
+ if(Fullscreen)
+ Mode |= SDL_FULLSCREEN;
+
+ // Before the resolution is set, check, if the zoom factor is too high!
+ while(((Width/GAME_STD_WIDTH) < Zoom || (Height/GAME_STD_HEIGHT) < Zoom) && (Zoom > 1))
+ Zoom--;
+
+ // Try to center the screen!
+ screenrect.w = blitrect.w = GAME_STD_WIDTH*Zoom;
+ screenrect.h = blitrect.h = GAME_STD_HEIGHT*Zoom;
+ screenrect.x = (Width-screenrect.w)>>1;
+ if(Width == 320)
+ screenrect.y = 0;
+ else
+ screenrect.y = (Height-screenrect.h)>>1;
+ blitrect.x = 0;
+ blitrect.y = 0;
+
+ // And Display can be setup.
+ screen = SDL_SetVideoMode(Width,Height,Depth,Mode);
+
+ Depth = screen->format->BitsPerPixel;
+
+ if( !screen )
+ {
+ g_pLogFile->textOut(RED,"VidDrv_Start(): Couldn't create a SDL surface: %s
", SDL_GetError());
+ return false;
+ }
+
+ if(!Fullscreen)
+ SDL_ShowCursor(SDL_ENABLE);
+ else
+ SDL_ShowCursor(SDL_DISABLE);
+
+ return true;
+}
+
+void CVideoDriver::setMode(unsigned int srcW, unsigned int srcH,
+ unsigned short srcD)
+{
+ Width = srcW;
+ Height = srcH;
+ Depth = srcD;
+}
+void CVideoDriver::setFrameskip(unsigned short value)
+{
+ FrameSkip = value;
+}
+void CVideoDriver::setFilter(short value)
+{
+ Filtermode = value;
+}
+void CVideoDriver::setZoom(short value)
+{
+ Zoom = value;
+}
+
+bool CVideoDriver::createSurfaces(void)
+{
+ // This function creates the surfaces which are needed for the game.
+ unsigned stretch_blit_yoff;
+
+ stretch_blit_yoff = 0;
+
+ ScrollSurface = SDL_CreateRGBSurfaceFrom(g_pGraphics->getScrollbuffer(), 512, 512, 8, 512, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
+ SDL_SetColorKey(ScrollSurface, SDL_SRCCOLORKEY, COLOUR_MASK);
+ if (!ScrollSurface)
+ {
+ g_pLogFile->textOut(RED,"VideoDriver: Couldn't create ScrollSurface!
");
+ return false;
+ }
+
+ BGLayerSurface = SDL_CreateRGBSurface(Mode,320, 200, Depth, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
+ if (!BGLayerSurface)
+ {
+ g_pLogFile->textOut(RED,"VideoDriver: Couldn't create BGLayerSurface!
");
+ return false;
+ }
+
+
+ FGLayerSurface = SDL_CreateRGBSurface(Mode,320, 200, Depth, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
+ if (!FGLayerSurface)
+ {
+ g_pLogFile->textOut(RED,"VideoDriver: Couldn't create FGLayerSurface!
");
+ return false;
+ }
+ SDL_SetColorKey( FGLayerSurface, SDL_SRCCOLORKEY,
+ SDL_MapRGB(FGLayerSurface->format, 0, 0, 0) );
+
+ //Set surface alpha
+ SDL_SetAlpha( FGLayerSurface, SDL_SRCALPHA, 225 );
+
+ if(Width == 320 && !m_opengl)
+ {
+ g_pLogFile->textOut("Blitsurface = Screen
");
+ BlitSurface = screen;
+ blitsurface_alloc = 0;
+ VRAMPtr = (unsigned char*)screen->pixels + ((Width * stretch_blit_yoff * Depth)>>3)+screenrect.y*screen->pitch + (screenrect.x*Depth>>3);
+ }
+ else
+ {
+ g_pLogFile->textOut("Blitsurface = creatergbsurfacefrom
");
+ BlitSurface = SDL_CreateRGBSurface(Mode,GAME_STD_WIDTH, GAME_STD_HEIGHT, Depth, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
+ if (!BlitSurface)
+ {
+ g_pLogFile->textOut(RED,"VidDrv_Start(): Couldn't create BlitSurface!
");
+ return false;
+ }
+ blitsurface_alloc = 1;
+ VRAMPtr = (unsigned char*)screen->pixels + ((Width * stretch_blit_yoff * Depth)>>3)+screenrect.y*screen->pitch + (screenrect.x*Depth>>3);
+ }
+
+ dstrect.x = 0; dstrect.y = 0;
+ dstrect.w = GAME_STD_WIDTH;
+ dstrect.h = GAME_STD_HEIGHT;
+
+ return true;
+}
+
+// alter the color palette. the palette is not actually altered
+// on-screen until pal_apply() is called.
+void CVideoDriver::pal_set(short colour, char red, char green, char blue)
+{
+ MyPalette[colour].r = red;
+ MyPalette[colour].g = green;
+ MyPalette[colour].b = blue;
+}
+
+// applies all changes to the palette made with pal_set
+void CVideoDriver::pal_apply(void)
+{
+ SDL_SetColors(screen, (SDL_Color *) &MyPalette, 0, 256);
+ SDL_SetColors(ScrollSurface, (SDL_Color *) &MyPalette, 0, 256);
+ if (blitsurface_alloc)
+ {
+ SDL_SetColors(BlitSurface, (SDL_Color *) &MyPalette, 0, 256);
+ }
+}
+
+void CVideoDriver::sb_blit(void)
+{
+SDL_Rect srcrect;
+char wraphoz, wrapvrt;
+int save_dstx, save_dstw, save_srcx, save_srcw;
+char tempbuf[80];
+
+ blitBGLayer();
+
+ dstrect.x = 0; dstrect.y = 0;
+ dstrect.w = 320; dstrect.h = 200;
+
+ srcrect.x = scrollx_buf;
+ srcrect.y = scrolly_buf;
+ if (scrollx_buf > (512-320))
+ { // need to wrap right side
+ srcrect.w = (512-scrollx_buf);
+ wraphoz = 1;
+ }
+ else
+ { // single blit for whole horizontal copy
+ srcrect.w = 320;
+ wraphoz = 0;
+ }
+
+ if (scrolly_buf > (512-200))
+ { // need to wrap on bottom
+ srcrect.h = (512-scrolly_buf);
+ wrapvrt = 1;
+ }
+ else
+ { // single blit for whole bottom copy
+ srcrect.h = 200;
+ wrapvrt = 0;
+ }
+
+ SDL_BlitSurface(ScrollSurface, &srcrect, BlitSurface, &dstrect);
+
+ if (wraphoz && wrapvrt)
+ {
+ // first do same thing we do for wraphoz
+ save_dstx = dstrect.x;
+ save_dstw = dstrect.w;
+ save_srcx = srcrect.x;
+ save_srcw = srcrect.w;
+ dstrect.x = srcrect.w;
+ dstrect.w = 320 - dstrect.x;
+ srcrect.x = 0;
+ srcrect.w = (320 - srcrect.w);
+ SDL_BlitSurface(ScrollSurface, &srcrect, BlitSurface, &dstrect);
+ // now repeat for the bottom
+ // (lower-right square)
+ dstrect.y = srcrect.h;
+ dstrect.h = 200 - dstrect.y;
+ srcrect.y = 0;
+ srcrect.h = (200 - srcrect.h);
+ SDL_BlitSurface(ScrollSurface, &srcrect, BlitSurface, &dstrect);
+ // (lower-left square)
+ dstrect.x = save_dstx;
+ dstrect.w = save_dstw;
+ srcrect.x = save_srcx;
+ srcrect.w = save_srcw;
+ SDL_BlitSurface(ScrollSurface, &srcrect, BlitSurface, &dstrect);
+ }
+ else if (wraphoz)
+ {
+ dstrect.x = srcrect.w;
+ dstrect.w = 320 - dstrect.x;
+ srcrect.x = 0;
+ srcrect.w = (320 - srcrect.w);
+ SDL_BlitSurface(ScrollSurface, &srcrect, BlitSurface, &dstrect);
+ }
+ else if (wrapvrt)
+ {
+ dstrect.y = srcrect.h;
+ dstrect.h = 200 - dstrect.y;
+ srcrect.y = 0;
+ srcrect.h = (200 - srcrect.h);
+ SDL_BlitSurface(ScrollSurface, &srcrect, BlitSurface, &dstrect);
+ }
+
+ drawConsoleMessages();
+ if (showfps)
+ {
+
+#ifdef DEBUG
+ sprintf(tempbuf, "FPS: %03d; x = %ld ; y = %d", fps, player[0].x >>CSF, player[0].y >>CSF);
+
+#else
+ sprintf(tempbuf, "FPS: %03d", fps);
+#endif
+ g_pGraphics->drawFont( (unsigned char *) tempbuf, 320-3-(strlen( (char *) tempbuf)<<3), 3, 1);
+ }
+
+ update_screen();
+}
+void CVideoDriver::blitBGLayer(void)
+{
+ SDL_BlitSurface(BGLayerSurface, NULL, BlitSurface, NULL);
+}
+
+void CVideoDriver::update_screen(void)
+{
+#ifdef USE_OPENGL
+ if(m_opengl)
+ {
+ SDL_BlitSurface(FGLayerSurface, NULL, BlitSurface, NULL);
+
+ mp_OpenGL->render();
+
+ SDL_LockSurface(FGLayerSurface);
+ // Flush the layers
+ memset(FGLayerSurface->pixels,SDL_MapRGB(FGLayerSurface->format, 0, 0, 0),
+ GAME_STD_WIDTH*GAME_STD_HEIGHT*FGLayerSurface->format->BytesPerPixel);
+ SDL_UnlockSurface(FGLayerSurface);
+ }
+ else // No OpenGL but Software Rendering
+ {
+#endif
+ SDL_BlitSurface(FGLayerSurface, NULL, BlitSurface, NULL);
+
+ // if we're doing zoom then we have copied the scroll buffer into
+ // another offscreen buffer, and must now stretchblit it to the screen
+ if (Zoom == 1 && Width != 320 )
+ {
+ SDL_LockSurface(BlitSurface);
+ SDL_LockSurface(screen);
+
+ if(Filtermode == 0)
+ {
+ noscale((char*)VRAMPtr, (char*)BlitSurface->pixels, (Depth>>3));
+ }
+ else
+ {
+ g_pLogFile->textOut(PURPLE,"Sorry, but this filter doesn't work at that zoom mode
");
+ g_pLogFile->textOut(PURPLE,"Try to use a higher zoom factor. Switching to no-filter
");
+ Filtermode = 0;
+ }
+ SDL_UnlockSurface(screen);
+ SDL_UnlockSurface(BlitSurface);
+ }
+ if (Zoom == 2)
+ {
+ SDL_LockSurface(BlitSurface);
+ SDL_LockSurface(screen);
+
+ if(Filtermode == 0)
+ {
+ scale2xnofilter((char*)VRAMPtr, (char*)BlitSurface->pixels, (Depth>>3));
+ }
+ else if(Filtermode == 1)
+ {
+ scale(2, VRAMPtr, Width*(Depth>>3), BlitSurface->pixels,
+ GAME_STD_WIDTH*(Depth>>3), (Depth>>3), GAME_STD_WIDTH, GAME_STD_HEIGHT);
+ }
+ else
+ {
+ g_pLogFile->textOut(PURPLE,"Sorry, but this filter doesn't work at that zoom mode
");
+ g_pLogFile->textOut(PURPLE,"Try to use a higher zoom factor. Switching to no-filter
");
+ Filtermode = 0;
+ }
+
+ SDL_UnlockSurface(screen);
+ SDL_UnlockSurface(BlitSurface);
+ }
+ else if (Zoom == 3)
+ {
+ SDL_LockSurface(BlitSurface);
+ SDL_LockSurface(screen);
+
+ if(Filtermode == 0)
+ {
+ scale3xnofilter((char*)VRAMPtr, (char*)BlitSurface->pixels, (Depth>>3));
+ }
+ else if(Filtermode == 1)
+ {
+ scale(2, VRAMPtr, Width*(Depth>>3), BlitSurface->pixels,
+ GAME_STD_WIDTH*(Depth>>3), (Depth>>3), GAME_STD_WIDTH, GAME_STD_HEIGHT);
+ }
+ else if(Filtermode == 2)
+ {
+ scale(3, VRAMPtr, Width*(Depth>>3), BlitSurface->pixels,
+ GAME_STD_WIDTH*(Depth>>3), (Depth>>3), GAME_STD_WIDTH, GAME_STD_HEIGHT);
+ }
+ else
+ {
+ g_pLogFile->textOut(PURPLE,"Sorry, but this filter doesn't work at that zoom mode
");
+ g_pLogFile->textOut(PURPLE,"Try to use a higher zoom factor. Switching to no-filter
");
+ Filtermode = 0;
+ }
+ SDL_UnlockSurface(screen);
+ SDL_UnlockSurface(BlitSurface);
+ }
+ else if (Zoom == 4)
+ {
+ SDL_LockSurface(BlitSurface);
+ SDL_LockSurface(screen);
+
+ if(Filtermode == 0)
+ {
+ scale4xnofilter((char*)VRAMPtr, (char*)BlitSurface->pixels, (Depth>>3));
+ }
+ else if(Filtermode == 1)
+ {
+ scale(2, VRAMPtr, Width*(Depth>>3), BlitSurface->pixels,
+ GAME_STD_WIDTH*(Depth>>3), (Depth>>3), GAME_STD_WIDTH, GAME_STD_HEIGHT);
+ }
+ else if(Filtermode == 2)
+ {
+ scale(3, VRAMPtr, Width*(Depth>>3), BlitSurface->pixels,
+ GAME_STD_WIDTH*(Depth>>3), (Depth>>3), GAME_STD_WIDTH, GAME_STD_HEIGHT);
+ }
+ else if(Filtermode == 3)
+ {
+ scale(4, VRAMPtr, Width*(Depth>>3), BlitSurface->pixels,
+ GAME_STD_WIDTH*(Depth>>3), (Depth>>3), GAME_STD_WIDTH, GAME_STD_HEIGHT);
+ }
+ else
+ {
+ g_pLogFile->textOut(PURPLE,"Sorry, but this filter doesn't work at that zoom mode
");
+ g_pLogFile->textOut(PURPLE,"Try to use a higher zoom factor. Switching to no-filter
");
+ Filtermode = 0;
+ }
+ SDL_UnlockSurface(screen);
+ SDL_UnlockSurface(BlitSurface);
+ }
+
+ SDL_Flip(screen);
+ //SDL_UpdateRect(screen, screenrect.x, screenrect.y, screenrect.w, screenrect.h);
+
+ SDL_LockSurface(FGLayerSurface);
+ // Flush the layers
+ memset(FGLayerSurface->pixels,SDL_MapRGB(FGLayerSurface->format, 0, 0, 0),
+ GAME_STD_WIDTH*GAME_STD_HEIGHT*FGLayerSurface->format->BytesPerPixel);
+ SDL_UnlockSurface(FGLayerSurface);
+#ifdef USE_OPENGL
+ }
+#endif
+}
+
+void CVideoDriver::noscale(char *dest, char *src, short bbp)
+{
+ // just passes a blitsurface to the screen
+ int i;
+ for(i=0 ; i < 200 ; i++)
+ memcpy(dest+(i*Width)*bbp,src+(i*GAME_STD_WIDTH)*bbp,320*bbp);
+}
+
+void CVideoDriver::scale2xnofilter(char *dest, char *src, short bbp)
+{
+ // workaround for copying correctly stuff to the screen, so the screen is scaled normally
+ // to 2x (without filter). This applies to 16 and 32-bit colour depth.
+ // use bit shifting method for faster blit!
+ bbp >>= 1;
+
+ int i,j;
+ for(i=0 ; i < 200 ; i++)
+ {
+ for(j = 0; j < 320 ; j++)
+ {
+ memcpy(dest+((j<<1)<>= 1;
+
+ int i,j;
+ for(i=0 ; i < 200 ; i++)
+ {
+ for(j = 0; j < 320 ; j++)
+ {
+ // j*3 = (j<<1) + j
+ memcpy(dest+(((j<<1)+j)<>= 1;
+
+ char *srctemp;
+ char *desttemp;
+ int size;
+
+ int i,j;
+ for(i=0 ; i < GAME_STD_HEIGHT ; i++)
+ {
+ for(j = 0; j < GAME_STD_WIDTH ; j++)
+ {
+ // j*4 = (j<<2)
+ srctemp = src+((j+(i*GAME_STD_WIDTH))< Width || y > Height )
+ return;
+
+
+ if(BlitSurface->format->BitsPerPixel == 16)
+ {
+ Uint16 *ubuff16;
+ ubuff16 = (Uint16*) FGLayerSurface->pixels;
+ ubuff16 += (y * 320) + x;
+ *ubuff16 = convert4to16BPPcolor(c, BlitSurface);
+ }
+ else if(BlitSurface->format->BitsPerPixel == 32)
+ {
+ Uint32 *ubuff32;
+ ubuff32 = (Uint32*) FGLayerSurface->pixels;
+ ubuff32 += (y * 320) + x;
+ *ubuff32 = convert4to32BPPcolor(c, BlitSurface);
+ }
+ else
+ {
+ Uint8 *ubuff8;
+ ubuff8 = (Uint8*) FGLayerSurface->pixels;
+ ubuff8 += (y * 320) + x;
+ *ubuff8 = (Uint8) c;
+ }
+}
+unsigned char CVideoDriver::getpixel(int x, int y)
+{
+ return 0;
+}
+
+// "Console" here refers to the capability to pop up in-game messages
+// in the upper-left corner during game play ala Doom.
+void CVideoDriver::drawConsoleMessages(void)
+{
+int i;
+int y;
+
+ if (!NumConsoleMessages) return;
+ if (!ConsoleExpireTimer)
+ {
+ NumConsoleMessages--;
+ if (!NumConsoleMessages) return;
+ ConsoleExpireTimer = CONSOLE_EXPIRE_RATE;
+ }
+ else ConsoleExpireTimer--;
+
+ y = CONSOLE_MESSAGE_Y;
+ for(i=0;idrawFont( (unsigned char *) cmsg[i].msg, CONSOLE_MESSAGE_X, y, 1);
+ y += CONSOLE_MESSAGE_SPACING;
+ }
+}
+
+// removes all console messages
+void CVideoDriver::DeleteConsoleMsgs(void)
+{
+ NumConsoleMessages = 0;
+}
+
+// adds a console msg to the top of the screen and scrolls any
+// other existing messages downwards
+void CVideoDriver::AddConsoleMsg(const char *the_msg)
+{
+int i;
+ for(i=MAX_CONSOLE_MESSAGES-2;i>=0;i--)
+ {
+ strcpy(cmsg[i+1].msg, cmsg[i].msg);
+ }
+ strcpy(cmsg[0].msg, the_msg);
+
+ if (NumConsoleMessages < MAX_CONSOLE_MESSAGES) NumConsoleMessages++;
+ ConsoleExpireTimer = CONSOLE_EXPIRE_RATE;
+}
+
+short CVideoDriver::getZoomValue(void){ return Zoom; }
+
+void CVideoDriver::showFPS(bool value){ showfps = value; }
+
+void CVideoDriver::isFullscreen(bool value)
+{
+ Fullscreen = value;
+ return;
+}
+
+unsigned short CVideoDriver::getFrameskip(void)
+{
+ return FrameSkip;
+}
+bool CVideoDriver::getShowFPS(void)
+{
+ return showfps;
+}
+short CVideoDriver::getFiltermode(void)
+{
+ if(Filtermode < 0)
+ Filtermode = 0;
+ return Filtermode;
+}
+bool CVideoDriver::getFullscreen(void)
+{ return Fullscreen; }
+unsigned int CVideoDriver::getWidth(void)
+{ return Width; }
+unsigned int CVideoDriver::getHeight(void)
+{ return Height; }
+unsigned short CVideoDriver::getDepth(void)
+{ return Depth; }
+SDL_Surface *CVideoDriver::getScrollSurface(void)
+{ return ScrollSurface; }
+SDL_Surface *CVideoDriver::getBGLayerSurface(void)
+{ return BGLayerSurface; }
+
+
diff --git a/src/sdl/CVideoDriver.h b/src/sdl/CVideoDriver.h
index 8b5068962..39f07aec1 100644
--- a/src/sdl/CVideoDriver.h
+++ b/src/sdl/CVideoDriver.h
@@ -11,11 +11,17 @@
#include "../CSingleton.h"
#define g_pVideoDriver CVideoDriver::Get()
+struct st_resolution
+{ short width,height,depth; };
+
#ifdef USE_OPENGL
#include "COpenGL.h"
#endif
#include
+#include
+#include
+using namespace std;
inline bool LockSurface(SDL_Surface * bmp) {
if (SDL_MUSTLOCK(bmp))
@@ -38,11 +44,9 @@ public:
bool createSurfaces(void);
void stop(void);
bool start(void);
- void setMode(unsigned int srcW, unsigned int srcH,
- unsigned short srcD);
void isFullscreen(bool value);
- //void reset(void);
void drawConsoleMessages(void);
+ void initResolutionList();
void pal_set(short colour, char red, char green, char blue);
void pal_apply(void);
@@ -78,6 +82,7 @@ public:
SDL_Surface *getScrollSurface(void);
SDL_Surface *getBGLayerSurface(void);
+ void setMode(int width, int height,int depth);
void setFrameskip(unsigned short value);
void setFilter(short value);
void setZoom(short vale);
@@ -91,6 +96,7 @@ public:
#endif
void setTargetFPS(unsigned int targetfps){ if( targetfps >= 0 && targetfps <= 70 ) m_targetfps = targetfps; }
unsigned char getTargetFPS(void){ return m_targetfps; }
+ st_resolution setNextResolution();
void showFPS(bool value);
@@ -102,33 +108,37 @@ private:
COpenGL *mp_OpenGL;
#endif
- unsigned int Width;
- unsigned int Height;
- unsigned short Depth;
- unsigned int Mode;
- bool Fullscreen;
- short Filtermode;
- unsigned short Zoom;
- unsigned short FrameSkip;
- unsigned int m_targetfps; // Used for automatic frame skipping
- bool showfps;
- bool m_opengl;
- int m_opengl_filter;
- bool m_aspect_correction;
+ st_resolution m_Resolution;
- SDL_Rect screenrect;
- SDL_Rect blitrect;
+ list m_Resolutionlist;
+ list :: iterator m_Resolution_pos;
- SDL_Color MyPalette[256];
+ unsigned int Mode;
+ bool Fullscreen;
+ short Filtermode;
+ unsigned short Zoom;
+ unsigned short FrameSkip;
+ unsigned int m_targetfps; // Used for automatic frame skipping
+ bool showfps;
+ bool m_opengl;
+ int m_opengl_filter;
+ bool m_aspect_correction;
- SDL_Surface *screen; // the actual video memory/window
- SDL_Surface *BGLayerSurface; // Special surface which support more colors than the scrollsurface
+ SDL_Rect screenrect;
+ SDL_Rect blitrect;
+
+ SDL_Color MyPalette[256];
+
+ SDL_Surface *FGLayerSurface; // Scroll buffer for Messages
+ // This one is not allowed here! Used only for tests!
+ SDL_Surface *screen; // the actual video memory/window
+ SDL_Surface *BGLayerSurface; // Special surface which support more colors than the scrollsurface
//for (Ex. HQ-Images)
- SDL_Surface *ScrollSurface; // 512x512 scroll buffer
- SDL_Surface *FGLayerSurface; // Scroll buffer for Messages
- // pointer to the surface that sb_blit is to assemble the scroll buffer into.
- // if zoom=1 this is the same as "screen", else it's allocated as it's own
- // buffer of 320x200.
- SDL_Surface *BlitSurface;
+ SDL_Surface *ScrollSurface; // 512x512 scroll buffer
+ // pointer to the surface that sb_blit is to assemble the scroll buffer into.
+ // if zoom=1 this is the same as "screen", else it's allocated as it's own
+ // buffer of 320x200.
+ SDL_Surface *BlitSurface;
+
};
#endif /* CVIDEODRIVER_H_ */
diff --git a/src/sdl/sound/CSound.cpp b/src/sdl/sound/CSound.cpp
index b20ebcde5..4a37a1c53 100644
--- a/src/sdl/sound/CSound.cpp
+++ b/src/sdl/sound/CSound.cpp
@@ -6,12 +6,12 @@
*/
#include "../../keen.h"
-#include "../../include/fileio/lzexe.h"
#include "CSound.h"
#include "../../include/fileio.h"
#include "../../CLogFile.h"
#include "../../hqp/CMusic.h"
#include "../../vorticon/sounds.h"
+#include "../../fileio/CExeFile.h"
#define SAFE_DELETE_ARRAY(x) if(x) delete[] x; x=NULL
@@ -398,34 +398,22 @@ char CSound::loadSoundData(unsigned short Episode, char *DataDirectory)
Utility to extract the embedded sounds from Commander Keen
Episode 2 (keen2.exe) and Episode 3 (keen3.exe)
- Implemented by Gerhard Stein (2008)
+ Implemented by Gerhard Stein (2008,2009)
Copyright (C) 2007 Hans de Goede
Many thanks to Mitugu(Kou) Kurizono for the decompression algorithm.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Modification by Gerstrong 2009
+ The new version uses a class named CExeFile which is able to manage compressed or
+ uncompressed files. The function simply let the class do its job and then copy
+ the sound data.
*/
char CSound::extractOfExeFile(char *inputpath, int episode)
{
const char *outputfname;
int bit_count;
- FILE *fin, *fout;
- unsigned char buf[131072];
- short offset;
- int pos, repeat, sounds_start, sounds_end, ret = 0;
+ int pos, sounds_start, sounds_end, ret = 0;
char buffer[MAX_STRING_LENGTH];
char inputfname[MAX_STRING_LENGTH];
@@ -434,6 +422,7 @@ char CSound::extractOfExeFile(char *inputpath, int episode)
memset(buffer,0, MAX_STRING_LENGTH*sizeof(char));
memset(inputfname,0, MAX_STRING_LENGTH*sizeof(char));
+ // Set Offsets. Episode 1 already provides this
if (episode == 2)
{
outputfname = "sounds.ck2";
@@ -452,112 +441,21 @@ char CSound::extractOfExeFile(char *inputpath, int episode)
return 1;
}
- strcpy(buffer,inputpath);
- sprintf(inputfname,"%skeen%d.exe", inputpath, episode);
-
- fin = fopen(inputfname, "rb");
-
- if (!fin)
- {
- g_pLogFile->ftextOut( "Error opening input file %s: ", inputfname);
- perror(NULL);
- return 2;
- }
+ CExeFile *ExeFile = new CExeFile(episode, inputfname);
+ if(!ExeFile->readData()) ret = 1;
else
{
- sprintf(buffer,"%s%s", inputpath, outputfname);
-
- fout = fopen(buffer, "wb");
- if (!fout)
+ FILE *fout;
+ if(!(fout = fopen(outputfname,"wb"))) ret = 1;
+ else
{
- g_pLogFile->ftextOut( "Error opening output file %s: ", outputfname);
- perror(NULL);
- fclose(fin);
+ fwrite( ExeFile->getData()+sounds_start, 1, (sounds_end-sounds_start), fout);
+ fclose(fout);
}
-
- /* skip header */
- fseek(fin, 32, SEEK_SET);
-
- while (1)
- {
- if (ferror(fin))
- {
- g_pLogFile->ftextOut( "Error reading from input file %s:", inputfname);
- perror(NULL);
- fclose(fin);
- fclose(fout);
- return 1;
- }
-
- if (get_bit(&bit_count, &fin))
- {
- buf[pos++] = getc(fin);
- }
- else
- {
- if (get_bit(&bit_count, &fin))
- {
- unsigned char tmp[2];
- if(!fread(tmp, 1, 2, fin))
- {
- g_pLogFile->ftextOut(RED,"Read-Error!");
- return 1;
- }
-
- repeat = (tmp[1] & 0x07);
-
- offset = ((tmp[1] & ~0x07) << 5) | tmp[0] | 0xE000;
-
- if (repeat == 0)
- {
- repeat = getc (fin);
-
-
- if (repeat == 0)
- break;
- else if (repeat == 1)
- continue;
- else
- repeat++;
- }
- else
- repeat += 2;
- }
- else
- {
- repeat = ((get_bit(&bit_count, &fin) << 1) | get_bit(&bit_count, &fin)) + 2;
- offset = getc(fin) | 0xFF00;
- }
-
- while (repeat > 0)
- {
- buf[pos] = buf[pos + offset];
- pos++;
- repeat--;
- }
- }
- }
- g_pLogFile->ftextOut("Decompression (unlzexe) of %s done
", inputfname);
-
- if (strcmp((char *)(&buf[sounds_start]), "SND"))
- {
- g_pLogFile->ftextOut( "Error: Beginning of sound data not found at expected offset
");
- ret = 1;
- }
- else if ((int)fwrite(&buf[sounds_start], 1, sounds_end - sounds_start, fout) !=
- (sounds_end - sounds_start))
- {
- g_pLogFile->ftextOut( "error writing to output file %s: ", outputfname);
- perror(NULL);
- ret = 1;
- }
- g_pLogFile->ftextOut("%s has been successfully written
", outputfname);
-
- fclose(fin);
- fclose(fout);
-
}
+ delete ExeFile;
+
return ret;
}
void CSound::setSoundmode(int freq, bool stereo)
diff --git a/src/vorbis/oggsupport.cpp b/src/vorbis/oggsupport.cpp
index a193045e7..7c8174db3 100644
--- a/src/vorbis/oggsupport.cpp
+++ b/src/vorbis/oggsupport.cpp
@@ -9,89 +9,68 @@
#include
#include
+#include
+#include
+#include
#define MAX_LEVELS 100 // Stupid! But you need it!
+#define BUFFER_SIZE 32768 // 32 KB buffers
#include "../include/declarations.h"
#include "../hqp/hq_sound.h"
#include "../sdl/CVideoDriver.h"
#include "../CLogFile.h"
-short openOGGSound(FILE *fp, SDL_AudioSpec *pspec, stHQSound *psound)
+short openOGGSound(FILE *fp, SDL_AudioSpec *pspec, Uint16 format, stHQSound *psound)
{
- // it is an ogg file
- // If Ogg detected, decode it into the stream psound->sound_buffer. It must fit to Audio_cvt structure, so that
- // it can be converted
+ // If Ogg detected, decode it into the stream psound->sound_buffer.
+ // It must fit into the Audio_cvt structure, so that it can be converted
int result;
OggVorbis_File oggStream; // stream handle
- vorbis_info* vorbisInfo; // some formatting data
- vorbis_comment* vorbisComment; // user comments
- if((result = ov_open(fp, &oggStream, NULL, 0)) < 0)
+ if((result = ov_open_callbacks(fp, &oggStream, NULL, 0, OV_CALLBACKS_DEFAULT)) < 0)
{
fclose(fp);
return 1;
}
else
{
+ long bytes;
+ char array[BUFFER_SIZE];
+ vector buffer;
+ vorbis_info* vorbisInfo; // some formatting data
+ vorbis_comment* vorbisComment; // user comments
+
+ int bitStream;
vorbisInfo = ov_info(&oggStream, -1);
vorbisComment = ov_comment(&oggStream, -1);
- pspec->format = 32784; // Not sure, if this works with any ogg file
+ pspec->format = AUDIO_S16LSB; // Ogg Audio seems to always use this format
+ //pspec->format = (AUDIO_S16LSB*147)/160; // Ogg Audio seems to always use this format
+
pspec->channels = vorbisInfo->channels;
pspec->freq = vorbisInfo->rate;
+
+ psound->sound_len = 0;
+ do {
+ // Read up to a buffer's worth of decoded sound data
+ bytes = ov_read(&oggStream, array, BUFFER_SIZE, 0, 2, 1, &bitStream);
+ // Append to end of buffer
+ buffer.insert(buffer.end(), array, array + bytes);
+ } while (bytes > 0);
+
+ ov_clear(&oggStream);
+
+ psound->sound_len = buffer.size();
+
+ psound->sound_buffer = new Uint8[psound->sound_len];
+ for(Uint32 i=0; isound_len ; i++ )
+ {
+ memcpy( &(psound->sound_buffer[i]), &(buffer[i]), 1);
+ }
+
+ return 0;
}
-
- long length;
- int section;
- long pos=0;
- long ret;
- char *stream;
-
- length = 4 * (long)ov_pcm_total(&oggStream,-1);
-
- stream = (char*) malloc(length*sizeof(char));
-
- if(stream == NULL)
- {
- g_pLogFile->textOut(RED,"Error! Out of memory! in Loading the Ogg file
");
- return 1;
- }
-
- int eof=0;
-
- while(!eof){
- ret=ov_read(&oggStream,stream + pos,sizeof(stream),0,2,1,§ion);
- if (ret == 0) {
- /* EOF */
- eof=1;
- } else if (ret < 0) {
- /* error in the stream. Not a problem, just reporting it in
- case we (the app) cares. In this case, we don't. */
- } else {
- /* we don't bother dealing with sample rate changes, etc, but
- you'll have to*/
- if(pos > length)
- {
- // Something went wrong here! Stream is already full!
- g_pLogFile->ftextOut("WARNING: Stream overflow while reading the ogg-file!
");
- ret = 0;
- break;
- }
- pos += ret;
- }
- }
-
- psound->sound_buffer = (Uint8*) malloc(length);
- psound->sound_len = pos;
-
- memcpy( psound->sound_buffer, stream, psound->sound_len);
-
- free(stream);
-
- ov_clear(&oggStream); // This also closes fp
-
- return 0;
}
#endif
diff --git a/src/vorticon/CCredits.cpp b/src/vorticon/CCredits.cpp
index d395d99e8..76ea1be58 100644
--- a/src/vorticon/CCredits.cpp
+++ b/src/vorticon/CCredits.cpp
@@ -14,8 +14,6 @@
#include "../include/gamedo.h"
CCredits::CCredits() {
- // TODO Auto-generated constructor stub
-
}
CCredits::~CCredits() {
@@ -94,7 +92,7 @@ void CCredits::Render(stCloneKeenPlus *pCKP)
strcpy(scrolltext[25]," Pickle");
strcpy(scrolltext[26],"Resources:");
strcpy(scrolltext[27]," Tulip");
- strcpy(scrolltext[28],"");
+ strcpy(scrolltext[28]," DaVince");
strcpy(scrolltext[29],"");
strcpy(scrolltext[30],"");
strcpy(scrolltext[31],"");
diff --git a/src/vorticon/CEGAGraphics.cpp b/src/vorticon/CEGAGraphics.cpp
new file mode 100644
index 000000000..ac3a86fa7
--- /dev/null
+++ b/src/vorticon/CEGAGraphics.cpp
@@ -0,0 +1,137 @@
+/*
+ * CEGAGraphics.cpp
+ *
+ * Created on: 11.07.2009
+ * Author: gerstrong
+ */
+
+#include "CEGAGraphics.h"
+
+#ifdef TARGET_WIN32
+#include
+#endif
+#include
+#include
+using namespace std;
+
+CEGAGraphics::CEGAGraphics(short episode, const char *path) {
+ m_episode = episode;
+ strcpy(m_path, path);
+
+ // EGAHEAD Structure
+ LatchPlaneSize = 0;
+ SpritePlaneSize = 0;
+ BitmapTableStart = 0;
+ SpriteStart = 0;
+
+ FontTiles = 0;
+ FontLocation = 0;
+ ScreenTiles = 0;
+ ScreenLocation = 0;
+ Num16Tiles = 0;
+ Tiles16Location = 0;
+ NumBitmaps = 0;
+ BitmapLocation = 0;
+ NumSprites = 0;
+ SpriteLocation = 0;
+ compressed = 0;
+
+ m_Latch = NULL;
+ m_Sprit = NULL;
+ m_FontSurface = NULL;
+ m_BigTileSurface = NULL;
+ m_TileSurface = NULL;
+ m_BitmapsSurface = NULL;
+}
+
+CEGAGraphics::~CEGAGraphics() {
+ if(m_Latch) delete m_Latch;
+ if(m_Sprit) delete m_Sprit;
+}
+
+bool CEGAGraphics::loadData()
+{
+ char buf[256];
+ vector databuf;
+
+ chdir("data"); // TODO: You must be able to use another directory
+ if(m_path[0] == 0)
+ sprintf(buf,"egahead.ck%hd",m_episode);
+ else
+ sprintf(buf,"%s/egahead.ck%hd",m_path,m_episode);
+ ifstream HeadFile(buf,ios::binary);
+
+ if(!HeadFile)
+ return false;
+
+ char byte;
+ while(!HeadFile.eof())
+ {
+ HeadFile.read(&byte,1);
+ databuf.push_back(byte);
+ }
+ HeadFile.close();
+
+ char *data;
+ data = new char[databuf.size()];
+
+ memcpy(data, databuf.data(), databuf.size());
+
+ // Now copy the data to the EGAHEAD Structure
+ memcpy(&LatchPlaneSize,data,4);
+ memcpy(&SpritePlaneSize,data+4,4);
+ memcpy(&BitmapTableStart,data+8,4);
+ memcpy(&SpriteStart,data+12,4);
+
+ memcpy(&FontTiles,data+16,2);
+ memcpy(&FontLocation,data+18,4);
+ memcpy(&ScreenTiles,data+22,2);
+ memcpy(&ScreenLocation,data+24,4);
+ memcpy(&Num16Tiles,data+28,2);
+ memcpy(&Tiles16Location,data+30,4);
+ memcpy(&NumBitmaps,data+34,4);
+ memcpy(&BitmapLocation,data+36,4);
+ memcpy(&NumSprites,data+40,4);
+ memcpy(&SpriteLocation,data+42,4);
+ memcpy(&compressed,data+46,4);
+
+ m_Latch = new CEGALatch(LatchPlaneSize,
+ BitmapTableStart,
+ FontTiles,
+ FontLocation,
+ ScreenTiles,
+ ScreenLocation,
+ Num16Tiles,
+ Tiles16Location,
+ NumBitmaps,
+ BitmapLocation);
+
+ m_Latch->loadHead(data);
+
+ if(m_path[0] == 0)
+ sprintf(buf,"egalatch.ck%hd",m_episode);
+ else
+ sprintf(buf,"%s/egalatch.ck%hd",m_path,m_episode);
+ m_Latch->loadData(buf,(compressed>>1)); // The second bit tells, if latch is compressed.
+
+
+ m_Sprit = new CEGASprit(SpritePlaneSize,
+ SpriteStart,
+ NumSprites,
+ SpriteLocation);
+ m_Sprit->loadHead(data);
+
+ if(m_path[0] == 0)
+ sprintf(buf,"egasprit.ck%hd",m_episode);
+ else
+ sprintf(buf,"%s/egasprit.ck%hd",m_path,m_episode);
+ m_Sprit->loadData(buf,(compressed>>1));
+
+ chdir("../");
+
+ return true;
+}
+
+int CEGAGraphics::getNumSprites() { return NumSprites; }
+
+
diff --git a/src/vorticon/CEGAGraphics.h b/src/vorticon/CEGAGraphics.h
new file mode 100644
index 000000000..7c8287c4e
--- /dev/null
+++ b/src/vorticon/CEGAGraphics.h
@@ -0,0 +1,63 @@
+/*
+ * CEGAGraphics.h
+ *
+ * Created on: 11.07.2009
+ * Author: gerstrong
+ *
+ * This Class carries the head of graphics
+ * which are generally read from EGAHEAD.CK?
+ * It also has uses two other clases, which
+ * have the individual task to read its stuff
+ * (EGASPRIT and EGALATCH)
+ */
+
+#ifndef CEGAGRAPHICS_H_
+#define CEGAGRAPHICS_H_
+
+#include "CEGALatch.h"
+#include "CEGASprit.h"
+
+class CEGAGraphics {
+public:
+ CEGAGraphics(short episode, const char *path);
+ virtual ~CEGAGraphics();
+
+ bool loadData();
+
+ int getNumSprites();
+
+private:
+ short m_episode;
+ char m_path[256];
+
+ // Part of the EGAHEAD Data Structure
+ // Section 1:
+ long LatchPlaneSize; //Size of one plane of latch data
+ long SpritePlaneSize; //Size of one plane of sprite data
+ long BitmapTableStart; //Start locations of the EGAHEAD entries for unmasked graphics (Excluding font and tiles.)
+ long SpriteStart; //Where in the EGAHEAD the entries for masked graphics (Sprites) start
+
+ short FontTiles; //Number of 8x8 tiles. Meant for fonts
+ long FontLocation; //Font start location (relative to plane data, but normally 0)
+ long ScreenTiles; //Number of Screengraphics 32x32 tiles (always 0, because they were removed)
+ long ScreenLocation; //Offset of 32x32 tiles (relative to plane data)
+ short Num16Tiles; //Number of 16x16 tiles
+ long Tiles16Location; //Offset of 16x16 tiles (relative to plane data)
+ short NumBitmaps; //Number of bitmaps in table
+ long BitmapLocation; //Offset of bitmaps (relative to plane data)
+ short NumSprites; //Number of sprites
+ long SpriteLocation; //Offset of sprites (relative to plane data)
+ short compressed; // LZ compressed data
+
+ // Section 2 is in CEGALatch and section 3 is in EGASprit where also are the to be used graphics
+ // Here are which will be created, when object of class initialized
+ CEGALatch *m_Latch;
+ CEGASprit *m_Sprit;
+
+ SDL_Surface *m_FontSurface; // 8x8 Tiles
+ SDL_Surface *m_BigTileSurface; // May be 32x32. Never used in the original games
+ SDL_Surface *m_TileSurface; // 16x16 Tiles
+ SDL_Surface *m_BitmapsSurface; // Bitmaps of the games, like title screen
+};
+
+#endif /* CEGAGRAPHICS_H_ */
diff --git a/src/vorticon/CEGALatch.cpp b/src/vorticon/CEGALatch.cpp
new file mode 100644
index 000000000..930a15179
--- /dev/null
+++ b/src/vorticon/CEGALatch.cpp
@@ -0,0 +1,266 @@
+/*
+ * CEGALatch.cpp
+ *
+ * Created on: 11.07.2009
+ * Author: gerstrong
+ */
+
+#include "CEGALatch.h"
+#include "../sdl/CVideoDriver.h"
+#include "CPlanes.h"
+#include "../funcdefs.h"
+#include "../keen.h"
+#include "../keenext.h"
+#include
+#include
+
+char *BitmapData; // TODO: Partial solution. This BitmapData must become member of this class!
+
+CEGALatch::CEGALatch( int planesize,
+ long bitmaptablelocation,
+ short fonttiles,
+ long fontlocation,
+ long screentiles,
+ long screenlocation,
+ short num16tiles,
+ long tiles16location,
+ short bitmaps,
+ long bitmaplocation)
+{
+ m_latchplanesize = planesize;
+ m_bitmaptablelocation = bitmaptablelocation;
+ m_fonttiles = fonttiles;
+ m_fontlocation = fontlocation;
+ m_screentiles = screentiles;
+ m_screenlocation = screenlocation;
+ m_num16tiles = num16tiles;
+ m_tiles16location = tiles16location;
+ m_bitmaps = bitmaps;
+ m_bitmaplocation = bitmaplocation;
+
+ Bitmap = NULL;
+
+ RawData = NULL;
+}
+
+CEGALatch::~CEGALatch() {
+ if(Bitmap) delete [] Bitmap, Bitmap = NULL;
+ if(RawData) delete [] RawData, RawData = NULL;
+}
+
+bool CEGALatch::loadHead( char *data )
+{
+ data += m_bitmaptablelocation;
+ Bitmap = new st_Bitmap[m_bitmaps];
+
+ for(int i=0 ; iftextOut("latch_loadlatch(): Decoding 8x8 tiles...
", fname);
+
+ // set up the getbit() function of CPlanes class
+ CPlanes *Planes = new CPlanes(plane1 + m_fontlocation,
+ plane2 + m_fontlocation,
+ plane3 + m_fontlocation,
+ plane4 + m_fontlocation,
+ 0);
+
+ // TODO: Create surfaces which can be blitted directly to the blit surface or maybe screen.
+
+ // Load 8x8 Tiles
+ char c=0;
+ for(int p=0;p<4;p++)
+ {
+ for(int t=0;tgetbit(RawData, p) << p);
+ // map black pixels to color 16 because of the way the
+ // vorticon death sequence works in ep1
+ if (p==3 && c==0) c = 16;
+ font[t][y][x] = c;
+ }
+ }
+ }
+ }
+ delete Planes;
+
+ // Load 32x32 Tiles
+
+ // TODO: Add a read function for 32x32 Tiles
+
+ // Load 16x16 Tiles
+ Planes = new CPlanes(plane1 + m_tiles16location,
+ plane2 + m_tiles16location,
+ plane3 + m_tiles16location,
+ plane4 + m_tiles16location,
+ 0);
+
+ for(int p=0;p<4;p++)
+ {
+ for(int t=0;tgetbit(RawData, p) << p);
+ if (p==3 && c==0) c = 16;
+
+ tiledata[t][y][x] = c;
+ }
+ }
+ }
+ }
+ delete Planes;
+
+
+ // Load Bitmaps
+ // figure out how much RAM we'll need to read all 4 planes of
+ // latch data into memory.
+ BitmapBufferRAMSize = 0;
+ for(int i=0;igetbit(RawData, p) << p);
+ if (p==3 && c==0) c = 16;
+ *bmdataptr = c;
+ bmdataptr++;
+ }
+ }
+ }
+ }
+ delete Planes;
+
+ if(RawData){ delete[] RawData; RawData = NULL;}
+
+ return true;
+}
diff --git a/src/vorticon/CEGALatch.h b/src/vorticon/CEGALatch.h
new file mode 100644
index 000000000..6dac2b5be
--- /dev/null
+++ b/src/vorticon/CEGALatch.h
@@ -0,0 +1,57 @@
+/*
+ * CEGALatch.h
+ *
+ * Created on: 11.07.2009
+ * Author: gerstrong
+ */
+
+#ifndef CEGALATCH_H_
+#define CEGALATCH_H_
+
+#include
+
+class CEGALatch {
+public:
+ CEGALatch( int planesize,
+ long bitmaptablelocation,
+ short fonttiles,
+ long fontlocation,
+ long screentiles,
+ long screenlocation,
+ short num16tiles,
+ long tiles16location,
+ short bitmaps,
+ long bitmaplocation);
+ virtual ~CEGALatch();
+
+ bool loadHead(char *data );
+ bool loadData(const char *filename, bool compresseddata);
+
+ char *RawData;
+
+private:
+ int m_num_Latches;
+ int m_latchplanesize;
+ long m_bitmaptablelocation;
+
+ struct st_Bitmap{
+ short height;
+ short width;
+ long location;
+ char name[8];
+ }*Bitmap;
+
+ long m_latchstart;
+ short m_fonttiles;
+ long m_fontlocation;
+ long m_screentiles;
+ long m_screenlocation;
+ short m_num16tiles;
+ long m_tiles16location;
+ short m_bitmaps;
+ long m_bitmaplocation;
+
+ unsigned long BitmapBufferRAMSize;
+};
+
+#endif /* CEGALATCH_H_ */
diff --git a/src/vorticon/CEGASprit.cpp b/src/vorticon/CEGASprit.cpp
new file mode 100644
index 000000000..f5d29a8e9
--- /dev/null
+++ b/src/vorticon/CEGASprit.cpp
@@ -0,0 +1,172 @@
+/*
+ * CEGASprit.cpp
+ *
+ * Created on: 11.07.2009
+ * Author: gerstrong
+ *
+ * Yes, it should be CEGASprite, bute since the file name
+ * is called EGASPRIT.CK? it is left that way,
+ * to make the understanding clearer
+ */
+
+#include "CEGASprit.h"
+#include "CPlanes.h"
+#include "../keen.h"
+#include
+#include
+
+////////////////////////
+// section of defines //
+////////////////////////
+
+#define CSF 5
+
+extern stSprite *sprites;
+
+CEGASprit::CEGASprit(int planesize,
+ long spritestartloc,
+ int numsprites,
+ long spriteloc)
+{
+ m_planesize = planesize;
+ m_spritestartloc = spritestartloc;
+ m_numsprites = numsprites;
+ m_spriteloc = spriteloc;
+ Sprite = NULL;
+ sprites = NULL;
+}
+
+CEGASprit::~CEGASprit() {
+ if(Sprite) delete [] Sprite, Sprite = NULL;
+ if(sprites) delete [] sprites, sprites = NULL;
+}
+
+
+bool CEGASprit::loadHead(char *data)
+{
+ data += m_spritestartloc;
+
+ Sprite = new st_sprite[m_numsprites];
+
+ for(int i=0 ; i>= 8;
+ Sprite[i].hitbox_u >>= 8;
+ Sprite[i].hitbox_r >>= 8;
+ Sprite[i].hitbox_b >>= 8;
+ }
+
+ return true;
+}
+
+bool CEGASprit::loadData(const char *filename, bool compresseddata)
+{
+ FILE* latchfile;
+ char *RawData;
+
+ latchfile = fopen(filename,"rb");
+
+ if(!latchfile)
+ return false;
+
+ RawData = new char[m_planesize * 5];
+ // get the data out of the file into the memory, decompressing it if necessary.
+ if (compresseddata)
+ {
+ if (lz_decompress(latchfile, (unsigned char*) RawData))
+ return 1;
+ }
+ else
+ {
+ for(int i=0 ; i<(m_planesize*5) ; i++)
+ RawData[i] = fgetc(latchfile);
+ }
+
+ fclose(latchfile);
+
+ // TODO: Try to blit the Font map here!
+ // these are the offsets of the different video planes as
+ // relative to each other--that is if a pixel in plane1
+ // is at N, the byte for that same pixel in plane3 will be
+ // at (N + plane3).
+ unsigned long plane1, plane2, plane3, plane4, plane5;
+
+ plane1 = 0;
+ plane2 = (m_planesize * 1);
+ plane3 = (m_planesize * 2);
+ plane4 = (m_planesize * 3);
+ plane5 = (m_planesize * 4);
+
+ CPlanes *Planes = new CPlanes(plane1 + m_spriteloc,
+ plane2 + m_spriteloc,
+ plane3 + m_spriteloc,
+ plane4 + m_spriteloc,
+ plane5 + m_spriteloc);
+
+ // TODO: Create surfaces which can be blitted directly to the blit surface or maybe screen.
+ // load the image data
+ sprites = new stSprite[301];
+ char c;
+ for(int p=0 ; p<4 ; p++)
+ {
+ for(int s=0 ; sgetbit(RawData, p) << p);
+ if (p==3 && c==0) c = 16;
+ sprites[s].imgdata[y][x] = c;
+ }
+ }
+ }
+ }
+
+ // now load the 5th plane, which contains the sprite masks.
+ // note that we invert the mask because our graphics functions
+ // use white on black masks whereas keen uses black on white.
+ for(int s=0 ; sgetbit(RawData, 4));
+ }
+ }
+ }
+
+ delete Planes;
+
+ if(RawData){ delete[] RawData; RawData = NULL;}
+
+ return true;
+}
diff --git a/src/vorticon/CEGASprit.h b/src/vorticon/CEGASprit.h
new file mode 100644
index 000000000..2cabe9ad9
--- /dev/null
+++ b/src/vorticon/CEGASprit.h
@@ -0,0 +1,44 @@
+/*
+ * CEGASprit.h
+ *
+ * Created on: 11.07.2009
+ * Author: gerstrong
+ */
+
+#ifndef CEGASPRIT_H_
+#define CEGASPRIT_H_
+
+class CEGASprit {
+public:
+ CEGASprit(int planesize,
+ long spritestartloc,
+ int numsprites,
+ long spriteloc);
+ virtual ~CEGASprit();
+
+ bool loadHead(char *data);
+ bool loadData(const char *filename, bool compresseddata);
+
+private:
+ int m_numsprites;
+ int m_planesize;
+ long m_spritestartloc;
+ long m_spriteloc;
+
+ struct st_sprite{
+ short width;
+ short height;
+ short location_offset; // usually. See shikadi.net for more info
+ short location;
+ short hitbox_u;
+ short hitbox_l;
+ short hitbox_b;
+ short hitbox_r;
+ char name[12];
+ long hv_offset; // Unused in Keen games. Used in later games such as Shadow Knights
+ // There are 3 copies of the same Elements in the file. There were used for performance
+ // in DOS but are ignored here.
+ }*Sprite;
+};
+
+#endif /* CEGASPRIT_H_ */
diff --git a/src/vorticon/CHighScores.cpp b/src/vorticon/CHighScores.cpp
index 973aee3a2..d166e01fa 100644
--- a/src/vorticon/CHighScores.cpp
+++ b/src/vorticon/CHighScores.cpp
@@ -38,8 +38,8 @@ CHighScores::CHighScores(stCloneKeenPlus *poutsideCKP) {
for(i=0 ; i<7 ; i++)
sprintf(Score[i],"100");
- memset(Extra, false, 7*4*sizeof(unsigned char));
- memset(Cities, false, 7*sizeof(unsigned int));
+ memset(Extra, 0, 7*4*sizeof(unsigned char));
+ memset(Cities, 0, 7*sizeof(unsigned int));
pCKP = poutsideCKP;
diff --git a/src/vorticon/CIntro.cpp b/src/vorticon/CIntro.cpp
index e3de30d01..d6972afe0 100644
--- a/src/vorticon/CIntro.cpp
+++ b/src/vorticon/CIntro.cpp
@@ -14,12 +14,9 @@
#include "../include/gamedo.h"
CIntro::CIntro() {
- // TODO Auto-generated constructor stub
-
}
CIntro::~CIntro() {
- // TODO Auto-generated destructor stub
}
void CIntro::Render(stCloneKeenPlus *pCKP)
@@ -65,13 +62,7 @@ void CIntro::Render(stCloneKeenPlus *pCKP)
// blit the scrollbuffer to the display
gamedo_frameskipping_blitonly();
- g_pGraphics->drawBitmap2FG(mid[0], scrolly, bmnum[0]);
g_pGraphics->drawBitmap2FG(mid[1], scrolly+9, bmnum[1]);
- g_pGraphics->drawBitmap2FG(mid[2], scrolly+43, bmnum[2]);
- g_pGraphics->drawBitmap2FG(mid[3], scrolly+56, bmnum[3]);
- g_pGraphics->drawBitmap2FG(mid[4], scrolly+77, bmnum[4]);
- g_pGraphics->drawBitmap2FG(mid[5], scrolly+87, bmnum[5]);
- g_pGraphics->drawBitmap2FG(mid[6], scrolly+120, bmnum[6]);
gamedo_AnimatedTiles();
@@ -83,6 +74,16 @@ void CIntro::Render(stCloneKeenPlus *pCKP)
{
timer=0;
if(scrolly>35) scrolly--;
+ else
+ {
+ g_pGraphics->drawBitmap2FG(mid[0], scrolly, bmnum[0]);
+ g_pGraphics->drawBitmap2FG(mid[1], scrolly+9, bmnum[1]);
+ g_pGraphics->drawBitmap2FG(mid[2], scrolly+43, bmnum[2]);
+ g_pGraphics->drawBitmap2FG(mid[3], scrolly+56, bmnum[3]);
+ g_pGraphics->drawBitmap2FG(mid[4], scrolly+77, bmnum[4]);
+ g_pGraphics->drawBitmap2FG(mid[5], scrolly+87, bmnum[5]);
+ g_pGraphics->drawBitmap2FG(mid[6], scrolly+120, bmnum[6]);
+ }
}
if( g_pInput->getPressedAnyKey() || g_pInput->getPressedAnyCommand() )
diff --git a/src/vorticon/CMessages.cpp b/src/vorticon/CMessages.cpp
new file mode 100644
index 000000000..e479b9d31
--- /dev/null
+++ b/src/vorticon/CMessages.cpp
@@ -0,0 +1,84 @@
+/*
+ * CMessages.cpp
+ *
+ * Created on: 16.07.2009
+ * Author: gerstrong
+ *
+ * This special class reads all the strings
+ * out of an exe-file. It also can identify
+ * what string the program needs.
+ */
+
+#include "CMessages.h"
+#include "../CLogFile.h"
+
+CMessages::CMessages() {
+
+}
+
+CMessages::~CMessages() {
+ // TODO Auto-generated destructor stub
+}
+
+// buf - is the uncompressed buffer of the exe-file (keen1.exe for example)
+// episode - the game's episode
+// version - version of the exe-file
+bool CMessages::readData(char *buf, int episode, int version)
+{
+ long offset_start;
+ long offset_end;
+
+ // TODO: This function still has bugs when reading the text. Check this closer!
+ // This part of switches is used to get the proper addresses of the message text.
+ switch(episode)
+ {
+ case 1:
+ switch(version)
+ {
+ case 131:
+ offset_start = 0x14FAB;
+ offset_end = 0x16801;
+ break;
+ }
+ break;
+ case 2:
+ g_pLogFile->textOut(RED,"This version of the game is not supported!");
+ break;
+ case 3:
+ g_pLogFile->textOut(RED,"This version of the game is not supported!");
+ break;
+ default:
+ g_pLogFile->textOut(RED,"This version of the game is not supported!");
+ return false;
+ }
+
+ // Now read the stuff and store it to a list
+ for(int pos=offset_start ; pos :: iterator i;
+
+#include
+ for(i=StringList.begin() ; i!=StringList.end() ; i++)
+ {
+ std::cout << *i << std::endl;
+ }
+ return true;
+}
+
+char *CMessages::getString(const char *IDtext)
+{
+ return 0;
+}
diff --git a/src/vorticon/CMessages.h b/src/vorticon/CMessages.h
new file mode 100644
index 000000000..a76f35568
--- /dev/null
+++ b/src/vorticon/CMessages.h
@@ -0,0 +1,32 @@
+/*
+ * CMessages.h
+ *
+ * Created on: 16.07.2009
+ * Author: gerstrong
+ */
+
+#ifndef CMESSAGES_H_
+#define CMESSAGES_H_
+
+#include
+#include
+#include
+
+using namespace std;
+
+// TODO: Make the strings a class, but it must read from the exe-files basing on uncompressed buffer
+
+class CMessages {
+public:
+ CMessages();
+ virtual ~CMessages();
+
+ bool readData(char *buf, int episode, int version);
+ char *getString(const char *IDtext);
+
+private:
+ list StringList;
+ list StringIDList;
+};
+
+#endif /* CMESSAGES_H_ */
diff --git a/src/vorticon/CPlanes.cpp b/src/vorticon/CPlanes.cpp
new file mode 100644
index 000000000..06cb929a0
--- /dev/null
+++ b/src/vorticon/CPlanes.cpp
@@ -0,0 +1,53 @@
+/*
+ * CPlanes.cpp
+ *
+ * Created on: 12.07.2009
+ * Author: gerstrong
+ */
+
+#include "CPlanes.h"
+
+
+// Constructor initializes the positions,getbit will retrieve data from
+CPlanes::CPlanes(unsigned long p1, unsigned long p2, unsigned long p3,\
+ unsigned long p4, unsigned long p5) {
+ int i;
+ getbit_bytepos[0] = p1;
+ getbit_bytepos[1] = p2;
+ getbit_bytepos[2] = p3;
+ getbit_bytepos[3] = p4;
+ getbit_bytepos[4] = p5;
+
+ for(i=0;i<=4;i++)
+ {
+ getbit_bitmask[i] = 128;
+ }
+}
+
+// retrieves a bit from plane "plane". the positions of the planes
+// should have been previously initilized with setplanepositions()
+unsigned char CPlanes::getbit(char *buf, unsigned char plane)
+{
+ int retval;
+ int byt;
+ if (!getbit_bitmask[plane])
+ {
+ getbit_bitmask[plane] = 128;
+ getbit_bytepos[plane]++;
+ }
+
+ byt = buf[getbit_bytepos[plane]];
+
+ if (byt & getbit_bitmask[plane])
+ {
+ retval = 1;
+ }
+ else
+ {
+ retval = 0;
+ }
+
+ getbit_bitmask[plane] >>= 1;
+
+ return retval;
+}
diff --git a/src/vorticon/CPlanes.h b/src/vorticon/CPlanes.h
new file mode 100644
index 000000000..5505ecc2c
--- /dev/null
+++ b/src/vorticon/CPlanes.h
@@ -0,0 +1,24 @@
+/*
+ * CPlanes.h
+ *
+ * Created on: 12.07.2009
+ * Author: gerstrong
+ */
+
+#ifndef CPLANES_H_
+#define CPLANES_H_
+
+class CPlanes {
+public:
+ CPlanes(unsigned long p1, unsigned long p2, unsigned long p3,\
+ unsigned long p4, unsigned long p5);
+
+ unsigned char getbit(char *buf, unsigned char plane);
+
+private:
+ unsigned long getbit_bytepos[5];
+ unsigned char getbit_bitmask[5];
+
+};
+
+#endif /* CPLANES_H_ */