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_ */