applied changes from 0.3pre6 (patch from rev40 to rev49)

git-svn-id: https://clonekeenplus.svn.sourceforge.net/svnroot/clonekeenplus/cgenius/trunk@79 4df4b0f3-56ce-47cb-b001-ed939b7d65a6
This commit is contained in:
albertzeyer
2009-07-21 23:33:30 +00:00
parent 59b5a31f70
commit 68a5a6a245
62 changed files with 4916 additions and 2743 deletions

View File

@@ -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

View File

@@ -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...<br>");
@@ -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.<br>", Episode, version/100,version%100);
if(version == 134) g_pLogFile->ftextOut("This version of the game is not supported!<br>");
// 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; }

View File

@@ -9,7 +9,8 @@
#define CGAME_H_
#include <string.h>
#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_ */

View File

@@ -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;i<MAX_BITMAPS;i++)
{
bitmaps[i].name[8] = 0; // ensure null-terminated
@@ -563,6 +564,11 @@ int i;
return i;
}
}
// If the Bitmap was not found,
// try to take one basing on the position
// where it should be
return -1;
}
@@ -706,7 +712,17 @@ Uint8 *CGraphics::getScrollbuffer(void)
void CGraphics::renderHQBitmap()
{
if(HQBitmap)
HQBitmap->updateHQBitmap(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)

View File

@@ -9,11 +9,13 @@
#include <string.h>
#include <stdio.h>
#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<int>(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...<br>");
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...<br>", 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...<br>", 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...<br>", BitmapBufferRAMSize);
BitmapData = new char[BitmapBufferRAMSize];
@@ -344,7 +357,7 @@ char buffer[256];
g_pLogFile->ftextOut("latch_loadlatch(): Decoding bitmaps...<br>", 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...<br>");
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...<br>", 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;x<sprites[s].xsize;x++)
{
sprites[s].maskdata[y][x] = (1 - getbit(RawData, 4));
sprites[s].maskdata[y][x] = (1 - Planes->getbit(RawData, 4));
}
}
}
delete Planes;
return 0;
}

View File

@@ -58,9 +58,6 @@ private:
unsigned long BitmapBufferRAMSize;
unsigned long getbit_bytepos[5];
unsigned char getbit_bitmask[5];
EgaHead LatchHeader;
SpriteHead *SpriteTable;
BitmapHead *BitmapTable;

View File

@@ -8,9 +8,7 @@
#ifndef CLOGFILE_H_
#define CLOGFILE_H_
#define REVISION "CloneKeenPlus Beta v0.2.9.7 (Commander Genius)"
#include <stdio.h>
#define REVISION "Commander Genius Prerelease v0.3"
#include "CSingleton.h"
#define g_pLogFile CLogFile::Get()

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 <unistd.h>
#include <sys/types.h>
#include <dirent.h>
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<br>");
}
// 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<<CSF, ((curmapy<<4)+8)<<CSF, OBJ_YORP);
}
else
@@ -204,7 +299,6 @@ int o,x;
// in ep2 level 16 there a vorticon embedded in the floor for
// some reason! that's what the if() is for--to fix it.
if (TileProperty[map.mapdata[curmapx][curmapy+1]][BLEFT])
//if (tiles[map.mapdata[curmapx][curmapy+1]].solidl)
{
spawn_object(curmapx<<4<<CSF, ((curmapy<<4)-16)<<CSF, OBJ_VORT);
}
@@ -277,7 +371,6 @@ int o,x;
else if (pCKP->Control.levelcontrol.episode==3)
{
if(TileProperty[map.mapdata[curmapx][curmapy+1]][BLEFT])
//if (tiles[map.mapdata[curmapx][curmapy+1]].solidl)
{
spawn_object(curmapx<<4<<CSF, (curmapy-1)<<4<<CSF, OBJ_NINJA);
}
@@ -501,7 +594,6 @@ int resetcnt, resetpt;
c=18;
//while(!mapdone)
while(c < ((filebuf[9] / 2)+18)) // Check against Tilesize
{
t = filebuf[c];
@@ -609,245 +701,6 @@ int resetcnt, resetpt;
return 0;
}
char loadtileattributes(int episode, char *extrapath)
{
FILE *fp;
int t,a,b;
char fname[MAX_STRING_LENGTH];
char buf[MAX_STRING_LENGTH];
int bufsize;
unsigned char *filebuf;
int i,j; // standard counters
FILE *fin;
filebuf = (unsigned char*) malloc(500000*sizeof(unsigned char));
// We need a function that autodetects tli files in a directory...
sprintf(buf,"tiles.tli");
formatPathString(fname,extrapath);
strcat(fname,buf);
g_pLogFile->ftextOut("loadtileattributes() : Trying to read the tiles from \"%s\"<br>", 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\"<br>", 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.<br>",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-1;t++)
{
a = fgetc(fp); b = fgetc(fp);
tiles[t].chgtile = (a*256)+b;
if(tiles[t].chgtile > numtiles)
tiles[t].chgtile = 0;
}
fclose(fp);
return 0;
}
char loadstrings_AddAttr(char *attr, int stringIndex)
{
char stAttrName[80];

222
src/fileio/CExeFile.cpp Normal file
View File

@@ -0,0 +1,222 @@
/*
* CExeFile.cpp
*
* Created on: 17.07.2009
* Author: gerstrong
*/
#include "CExeFile.h"
#include <string.h>
#include <iostream>
#include <fstream>
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<unsigned char> *decdata;
decdata = new vector<unsigned char>;
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<unsigned char> *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; }

36
src/fileio/CExeFile.h Normal file
View File

@@ -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 <vector>
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<unsigned char> *outbuffer);
};
#endif /* CEXEFILE_H_ */

View File

@@ -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;

182
src/fileio/CPatcher.cpp Normal file
View File

@@ -0,0 +1,182 @@
/*
* CPatcher.cpp
*
* Created on: 19.07.2009
* Author: gerstrong
*/
#include "CPatcher.h"
#include <dirent.h>
#include <string.h>
#include <fstream>
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();
}

35
src/fileio/CPatcher.h Normal file
View File

@@ -0,0 +1,35 @@
/*
* CPatcher.h
*
* Created on: 19.07.2009
* Author: gerstrong
*/
#ifndef CPATCHER_H_
#define CPATCHER_H_
#include <list>
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<char*> m_TextList;
};
#endif /* CPATCHER_H_ */

203
src/fileio/CTileLoader.cpp Normal file
View File

@@ -0,0 +1,203 @@
/*
* CTileLoader.cpp
*
* Created on: 19.07.2009
* Author: gerstrong
*/
#include "CTileLoader.h"
#include "../CLogFile.h"
#include <stdlib.h>
#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).<br>");
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!<br>");
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!<br>");
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!<br>");
return false;
}
// load additional information the tiles
for(t=0;t<numtiles-1;t++)
{
a = fgetc(fp); b = fgetc(fp);
tiles[t].chgtile = (a<<8)+b;
if(tiles[t].chgtile > 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;
}
}
}

41
src/fileio/CTileLoader.h Normal file
View File

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

View File

@@ -1,150 +0,0 @@
/*
* lzexe.c
*
* Created on: 24.01.2009
* Author: gerstrong
*/
#include <stdlib.h>
#include <stdio.h>
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;
}

View File

@@ -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);
}

View File

@@ -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);

File diff suppressed because it is too large Load Diff

View File

@@ -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)<<CSF,(my>>4<<4)<<CSF,OBJ_SECTOREFFECTOR);
objects[o].ai.se.type = SE_EXTEND_PLATFORM;
objects[o].ai.se.platx = platx;
objects[o].ai.se.platy = platy;
}
else
{ // switch toggled from down to up--remove platform
map_chgtile(mx>>4,my>>4,TILE_SWITCH_UP);
o = spawn_object((mx>>4<<4)<<CSF,(my>>4<<4)<<CSF,OBJ_SECTOREFFECTOR);
objects[o].ai.se.type = SE_RETRACT_PLATFORM;
objects[o].ai.se.platx = platx;
objects[o].ai.se.platy = platy;
}
}
else if (player[cp].ppogostick==0 && t==TILE_LIGHTSWITCH)
{ // lightswitch
p_levelcontrol->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)<<CSF,(my>>4<<4)<<CSF,OBJ_SECTOREFFECTOR);
objects[o].ai.se.type = SE_EXTEND_PLATFORM;
objects[o].ai.se.platx = platx;
objects[o].ai.se.platy = platy;
}
else
{ // switch toggled from down to up--remove platform
map_chgtile(mx>>4,my>>4,TILE_SWITCH_UP);
o = spawn_object((mx>>4<<4)<<CSF,(my>>4<<4)<<CSF,OBJ_SECTOREFFECTOR);
objects[o].ai.se.type = SE_RETRACT_PLATFORM;
objects[o].ai.se.platx = platx;
objects[o].ai.se.platy = platy;
}
}
else if (!player[cp].ppogostick && t==TILE_LIGHTSWITCH)
{ // lightswitch
p_levelcontrol->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;
}
}

View File

@@ -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<<CSF);
player[cp].x += (8<<CSF);
}*/
}
}
}

View File

@@ -24,39 +24,50 @@ CHQBitmap::~CHQBitmap() {
bool CHQBitmap::loadImage(const char *pFilename, int wsize, int hsize)
{
m_scrimg = SDL_LoadBMP(pFilename);
SDL_Surface *BitmapSurface = SDL_LoadBMP(pFilename);
m_active = false;
if(m_scrimg)
if(BitmapSurface)
{
if( ((m_scrimg->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.<br>");
g_pLogFile->ftextOut("Please use a proper bitmap with %dx%d dimensions.<br>", m_scrimg->w, m_scrimg->h);
g_pLogFile->ftextOut("Your bitmap is of %dx%d.<br>", wsize, hsize);
g_pLogFile->textOut(BLUE,"HQBitmapLoader : Loading the level without HQBitmap.<br>");
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.<br>");
g_pLogFile->ftextOut("Please use a proper bitmap with %dx%d dimensions.<br>", m_scrimg->w, m_scrimg->h);
g_pLogFile->ftextOut("Your bitmap is of %dx%d.<br>", wsize, hsize);
g_pLogFile->textOut(BLUE,"HQBitmapLoader : Loading the level without HQBitmap.<br>");
}
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;

View File

@@ -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);

View File

@@ -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!<br>", musicfile);
return 1;
@@ -50,7 +50,8 @@ int CMusic::load(SDL_AudioSpec AudioSpec, char *musicfile)
g_pLogFile->ftextOut("Music Driver(): File \"%s\" opened successfully!<br>", 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));

View File

@@ -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<br>", soundfile);
return 1;

View File

@@ -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);

View File

@@ -1,14 +0,0 @@
/*
* lzexe.h
*
* Created on: 24.01.2009
* Author: gerstrong
*/
#include <stdio.h>
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);

View File

@@ -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);

View File

@@ -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

View File

@@ -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];

View File

@@ -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;

View File

@@ -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<<LZ_MAXBITS)+1)
#define LZ_MAXSTRINGSIZE 72
unsigned char *lz_outbuffer;
@@ -22,7 +20,7 @@ typedef struct stLZDictionaryEntry
unsigned char string[LZ_MAXSTRINGSIZE];
} stLZDictionaryEntry;
stLZDictionaryEntry *lzdict[LZ_MAXDICTSIZE];
stLZDictionaryEntry **lzdict;
// reads a word of length numbits from file lzfile.
unsigned int lz_readbits(FILE *lzfile, unsigned char numbits, unsigned char reset)
@@ -66,6 +64,12 @@ void lz_outputdict(int entry)
{
int i;
/*for(i=0;i<lzdict[entry].stringlen;i++)
{
*lz_outbuffer = lzdict[entry].string[i];
lz_outbuffer++;
}*/
for(i=0;i<lzdict[entry]->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;i<LZ_MAXDICTSIZE;i++)
{
lzdict[i] = (stLZDictionaryEntry*) malloc(sizeof(stLZDictionaryEntry));
if (!lzdict[i])
{
g_pLogFile->textOut("lz_decompress(): unable to allocate memory for dictionary!<br>");
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;i<LZ_MAXDICTSIZE;i++)
{
lzdict[i]->stringlen = 0;
}
maxdictcodewords = fgetc(lzfile);
maxdictcodewords += fgetc(lzfile) << 8;
// reset readbits
lz_readbits(NULL, 0, 1);
maxdictsize = ((1<<maxdictcodewords)+1);
// set starting # of bits-per-code
numbits = LZ_STARTBITS;
maxdictindex = (1 << numbits) - 1;
lzdict = new stLZDictionaryEntry*[maxdictsize];
// allocate memory for the LZ dictionary
for(i=0;i<maxdictsize;i++)
{
//lzdict[i] = (stLZDictionaryEntry*) malloc(sizeof(stLZDictionaryEntry));
lzdict[i] = new stLZDictionaryEntry;
if (!lzdict[i])
{
g_pLogFile->textOut("lz_decompress(): unable to allocate memory for dictionary!<br>");
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;i<maxdictsize;i++)
{
lzdict[i]->stringlen = 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;i<lzdict[lastcode]->stringlen;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<br>", 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;i<LZ_MAXDICTSIZE;i++)
{
free(lzdict[i]);
}
lzdict[dictindex]->string[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<br>", 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;i<maxdictsize;i++)
delete lzdict[i];
delete [] lzdict;
return 0;
}

View File

@@ -1,2 +1,3 @@
long lz_decompress( FILE *fin, char *pout );
long lz_compress( FILE *inf, FILE *outf );
//long lz_decompress( FILE *fin, char *pout );
char lz_decompress(FILE *lzfile, unsigned char *outbuffer);
//long lz_compress( FILE *inf, FILE *outf );

View File

@@ -7,10 +7,6 @@
the original author, Caitlin Shaw and to the new author
Gerstrong.
Please go ahead and port this game to other platforms.
I would love to see it on Linux, Mac, or CE but I do
not have the platforms/knowledge to port to these platforms.
If you make any changes or improvements to the code that
you feel merit inclusion in the source tree email them
to me at gerstrong@gmail.com or get my latest email
@@ -19,15 +15,16 @@
Thanks to ID Software for the "Commander Keen: Invasion of
the Vorticons" games. "Commander Keen" and it's associated
graphics, level, and sound files are the property of ID
Software. CloneKeen requires the original version of a
Software. Commander Genius requires the original version of a
Commander Keen game in order to be able to emulate that
episode.
Enjoy the Code
-Caitlin and Gerstrong
- The Commander Genius Team
CloneKeen 2003-2005 Caitlin Shaw
CloneKeenPlus 2008-2009 Gerstrong
CloneKeen 2003-2005 Caitlin Shaw
CloneKeenPlus 2008-2009 Gerstrong
Commander Genius 2009 Tulip, Pickle and DaVince
*/
#include "keen.h"
@@ -96,8 +93,10 @@ stFade fade;
stMap map;
unsigned int AnimTileInUse[ATILEINUSE_SIZEX][ATILEINUSE_SIZEY];
stTile tiles[MAX_TILES+1];
int numtiles;
int **TileProperty; // This version will replace the old stTile Structure and save memory
unsigned char tiledata[MAX_TILES+1][16][16];
stSprite sprites[MAX_SPRITES+1];
stSprite *sprites;
stBitmap bitmaps[MAX_BITMAPS+1];
stObject objects[MAX_OBJECTS+1];
char font[MAX_FONT+1][8][8];
@@ -302,8 +301,6 @@ void playgame_levelmanager(stCloneKeenPlus *pCKP)
p_levelcontrol->success = 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);

View File

@@ -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 && x<mapx+64 && y<mapy+64)
{
g_pGraphics->drawTile(((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<MAX_ANIMTILES-1;i++)
{
@@ -294,21 +293,22 @@ int c, i;
px = ((mapxstripepos+((x-mapx)<<4))&511);
py = ((mapystripepos+((y-mapy)<<4))&511);
c = map.mapdata[x][y];
//if (tiles[c].isAnimated)
if ( TileProperty[c][ANIMATION] > 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;i<MAX_ANIMTILES-1;i++)

View File

@@ -128,7 +128,8 @@ short loadResourcesforStartMenu(stCloneKeenPlus *pCKP, CGame *Game)
pCKP->Control.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)<br>");
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;

View File

@@ -39,7 +39,7 @@ char buf[80];
printf("%s", buf);
printf(" (%d bit)", static_cast<int> (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));
}

29
src/patch2 Normal file
View File

@@ -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; }

29
src/patch20092006 Normal file
View File

@@ -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; }

View File

@@ -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)

View File

@@ -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
{

View File

@@ -14,6 +14,9 @@
#include "../scale2x/scalebit.h"
#include "../CLogFile.h"
#include "../CGraphics.h"
#include <iostream>
#include <fstream>
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!<br>");
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<br>"); 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!<br>");
@@ -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!<br>");
@@ -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<br>");
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<br>");
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!<br>");
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)<<bbp)+(((i<<1)*Width)<<bbp),src+(j<<bbp)+((i*GAME_STD_WIDTH)<<bbp),bbp<<1);
memcpy(dest+(((j<<1)+1)<<bbp)+(((i<<1)*Width)<<bbp),src+(j<<bbp)+((i*GAME_STD_WIDTH)<<bbp),bbp<<1);
memcpy(dest+((j<<1)<<bbp)+(((i<<1)*m_Resolution.width)<<bbp),src+(j<<bbp)+((i*GAME_STD_WIDTH)<<bbp),bbp<<1);
memcpy(dest+(((j<<1)+1)<<bbp)+(((i<<1)*m_Resolution.width)<<bbp),src+(j<<bbp)+((i*GAME_STD_WIDTH)<<bbp),bbp<<1);
}
memcpy(dest+(((i<<1)+1)*(Width<<bbp)),(dest+(i<<1)*(Width<<bbp)),(bbp<<2)*GAME_STD_WIDTH);
memcpy(dest+(((i<<1)+1)*(m_Resolution.width<<bbp)),(dest+(i<<1)*(m_Resolution.width<<bbp)),(bbp<<2)*GAME_STD_WIDTH);
}
}
@@ -597,12 +669,12 @@ void CVideoDriver::scale3xnofilter(char *dest, char *src, short bbp)
for(j = 0; j < 320 ; j++)
{
// j*3 = (j<<1) + j
memcpy(dest+(((j<<1)+j)<<bbp)+((((i<<1) + i)*Width)<<bbp),src+(j<<bbp)+((i*GAME_STD_WIDTH)<<bbp),bbp<<1);
memcpy(dest+(((j<<1)+j+1)<<bbp)+((((i<<1) + i)*Width)<<bbp),src+(j<<bbp)+((i*GAME_STD_WIDTH)<<bbp),bbp<<1);
memcpy(dest+(((j<<1)+j+2)<<bbp)+((((i<<1) + i)*Width)<<bbp),src+(j<<bbp)+((i*GAME_STD_WIDTH)<<bbp),bbp<<1);
memcpy(dest+(((j<<1)+j)<<bbp)+((((i<<1) + i)*m_Resolution.width)<<bbp),src+(j<<bbp)+((i*GAME_STD_WIDTH)<<bbp),bbp<<1);
memcpy(dest+(((j<<1)+j+1)<<bbp)+((((i<<1) + i)*m_Resolution.width)<<bbp),src+(j<<bbp)+((i*GAME_STD_WIDTH)<<bbp),bbp<<1);
memcpy(dest+(((j<<1)+j+2)<<bbp)+((((i<<1) + i)*m_Resolution.width)<<bbp),src+(j<<bbp)+((i*GAME_STD_WIDTH)<<bbp),bbp<<1);
}
memcpy(dest+((i<<1)+i+1)*(Width<<bbp),dest+((i<<1)+i)*(Width<<bbp),(3<<bbp)*GAME_STD_WIDTH);
memcpy(dest+((i<<1)+i+2)*(Width<<bbp),dest+((i<<1)+i)*(Width<<bbp),(3<<bbp)*GAME_STD_WIDTH);
memcpy(dest+((i<<1)+i+1)*(m_Resolution.width<<bbp),dest+((i<<1)+i)*(m_Resolution.width<<bbp),(3<<bbp)*GAME_STD_WIDTH);
memcpy(dest+((i<<1)+i+2)*(m_Resolution.width<<bbp),dest+((i<<1)+i)*(m_Resolution.width<<bbp),(3<<bbp)*GAME_STD_WIDTH);
}
}
@@ -624,19 +696,19 @@ void CVideoDriver::scale4xnofilter(char *dest, char *src, short bbp)
{
// j*4 = (j<<2)
srctemp = src+((j+(i*GAME_STD_WIDTH))<<bbp);
desttemp = dest+((4*(j+(i*Width)))<<bbp);
desttemp = dest+((4*(j+(i*m_Resolution.width)))<<bbp);
memcpy(desttemp,srctemp,bbp<<1);
memcpy(desttemp+(1<<bbp),srctemp,bbp<<1);
memcpy(desttemp+(2<<bbp),srctemp,bbp<<1);
memcpy(desttemp+(3<<bbp),srctemp,bbp<<1);
}
srctemp = dest+(((i<<2)*Width)<<bbp);
desttemp = dest+((((i<<2)+1)*Width)<<bbp);
srctemp = dest+(((i<<2)*m_Resolution.width)<<bbp);
desttemp = dest+((((i<<2)+1)*m_Resolution.width)<<bbp);
size = GAME_STD_WIDTH*(bbp<<1<<2);
memcpy(desttemp,srctemp,size);
memcpy(desttemp+(Width<<bbp),srctemp,size);
memcpy(desttemp+((Width<<bbp)<<1),srctemp,size);
memcpy(desttemp+(m_Resolution.width<<bbp),srctemp,size);
memcpy(desttemp+((m_Resolution.width<<bbp)<<1),srctemp,size);
}
}
@@ -746,11 +818,11 @@ short CVideoDriver::getFiltermode(void)
bool CVideoDriver::getFullscreen(void)
{ return Fullscreen; }
unsigned int CVideoDriver::getWidth(void)
{ return Width; }
{ return m_Resolution.width; }
unsigned int CVideoDriver::getHeight(void)
{ return Height; }
{ return m_Resolution.height; }
unsigned short CVideoDriver::getDepth(void)
{ return Depth; }
{ return m_Resolution.depth; }
SDL_Surface *CVideoDriver::getScrollSurface(void)
{ return ScrollSurface; }
SDL_Surface *CVideoDriver::getBGLayerSurface(void)

View File

@@ -0,0 +1,756 @@
/*
* CVideoDriver.cpp
*
* Created on: 17.03.2009
* Author: gerstrong
*/
#include "CVideoDriver.h"
#include "CInput.h"
#include "../keen.h"
#include "video/colourconvert.h"
#include "video/colourtable.h"
#include "../scale2x/scalebit.h"
#include "../CLogFile.h"
#include "../CGraphics.h"
#define CKLOGFILENAME "genius.log"
#define MAX_CONSOLE_MESSAGES 3
#define CONSOLE_MESSAGE_X 3
#define CONSOLE_MESSAGE_Y 3
#define CONSOLE_MESSAGE_SPACING 9
#define CONSOLE_EXPIRE_RATE 250
#define GAME_STD_WIDTH 320
#define GAME_STD_HEIGHT 200
// pointer to the line in VRAM to start blitting to when stretchblitting.
// this may not be the first line on the display as it is adjusted to
// center the image on the screen when in fullscreen.
unsigned char *VRAMPtr;
char blitsurface_alloc = 0;
SDL_Rect dstrect;
typedef struct stConsoleMessage
{
char msg[80];
} stConsoleMessage;
stConsoleMessage cmsg[MAX_CONSOLE_MESSAGES];
int NumConsoleMessages = 0;
int ConsoleExpireTimer = 0;
CVideoDriver::CVideoDriver() {
// Default values
showfps=true;
#ifdef WIZ
Width=320;
Height=240;
Depth=16;
Mode=0;
Fullscreen=true;
Filtermode=0;
Zoom=1;
FrameSkip=0;
m_targetfps = 30; // Enable automatic frameskipping by default at 30
#else
Width=640;
Height=480;
Depth=0;
Mode=0;
Fullscreen=false;
Filtermode=1;
Zoom=2;
FrameSkip=2;
m_targetfps = 0; // Disable automatic frameskipping by default
#endif
m_opengl = false;
#ifdef USE_OPENGL
m_opengl_filter = GL_NEAREST;
mp_OpenGL = NULL;
#endif
m_aspect_correction = true;
screenrect.x=0;
screenrect.y=0;
screenrect.h=0;
screenrect.w=0;
ScrollSurface=NULL; // 512x512 scroll buffer
FGLayerSurface=NULL; // Scroll buffer for Messages
BGLayerSurface=NULL;
BlitSurface=NULL;
}
CVideoDriver::~CVideoDriver() {
stop();
}
void CVideoDriver::stop(void)
{
if(screen) { SDL_FreeSurface(screen); g_pLogFile->textOut("freed screen<br>"); screen = NULL; }
if(ScrollSurface && (ScrollSurface->map != NULL)) { SDL_FreeSurface(ScrollSurface); g_pLogFile->textOut("freed scrollsurface<br>"); ScrollSurface = NULL; }
if(blitsurface_alloc) { blitsurface_alloc = 0; SDL_FreeSurface(BlitSurface); g_pLogFile->textOut("freed blitsurface<br>"); BlitSurface=NULL; }
#ifdef USE_OPENGL
if(mp_OpenGL) { delete mp_OpenGL; mp_OpenGL = NULL; }
#endif
g_pLogFile->textOut(GREEN,"CVideoDriver Close%s<br>", 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<br>", SDL_GetError());
return false;
}
else
g_pLogFile->textOut(GREEN,"SDL was successfully initialized!<br>");
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<br>");
g_pLogFile->textOut(RED,"Check, if you have the most recent drivers installed!<br>");
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<br>", 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!<br>");
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!<br>");
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!<br>");
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<br>");
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<br>");
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!<br>");
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<br>");
g_pLogFile->textOut(PURPLE,"Try to use a higher zoom factor. Switching to no-filter<br>");
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<br>");
g_pLogFile->textOut(PURPLE,"Try to use a higher zoom factor. Switching to no-filter<br>");
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<br>");
g_pLogFile->textOut(PURPLE,"Try to use a higher zoom factor. Switching to no-filter<br>");
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<br>");
g_pLogFile->textOut(PURPLE,"Try to use a higher zoom factor. Switching to no-filter<br>");
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)<<bbp)+(((i<<1)*Width)<<bbp),src+(j<<bbp)+((i*GAME_STD_WIDTH)<<bbp),bbp<<1);
memcpy(dest+(((j<<1)+1)<<bbp)+(((i<<1)*Width)<<bbp),src+(j<<bbp)+((i*GAME_STD_WIDTH)<<bbp),bbp<<1);
}
memcpy(dest+(((i<<1)+1)*(Width<<bbp)),(dest+(i<<1)*(Width<<bbp)),(bbp<<2)*GAME_STD_WIDTH);
}
}
void CVideoDriver::scale3xnofilter(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.
// Optimization of using bit shifting
bbp >>= 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)<<bbp)+((((i<<1) + i)*Width)<<bbp),src+(j<<bbp)+((i*GAME_STD_WIDTH)<<bbp),bbp<<1);
memcpy(dest+(((j<<1)+j+1)<<bbp)+((((i<<1) + i)*Width)<<bbp),src+(j<<bbp)+((i*GAME_STD_WIDTH)<<bbp),bbp<<1);
memcpy(dest+(((j<<1)+j+2)<<bbp)+((((i<<1) + i)*Width)<<bbp),src+(j<<bbp)+((i*GAME_STD_WIDTH)<<bbp),bbp<<1);
}
memcpy(dest+((i<<1)+i+1)*(Width<<bbp),dest+((i<<1)+i)*(Width<<bbp),(3<<bbp)*GAME_STD_WIDTH);
memcpy(dest+((i<<1)+i+2)*(Width<<bbp),dest+((i<<1)+i)*(Width<<bbp),(3<<bbp)*GAME_STD_WIDTH);
}
}
void CVideoDriver::scale4xnofilter(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;
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))<<bbp);
desttemp = dest+((4*(j+(i*Width)))<<bbp);
memcpy(desttemp,srctemp,bbp<<1);
memcpy(desttemp+(1<<bbp),srctemp,bbp<<1);
memcpy(desttemp+(2<<bbp),srctemp,bbp<<1);
memcpy(desttemp+(3<<bbp),srctemp,bbp<<1);
}
srctemp = dest+(((i<<2)*Width)<<bbp);
desttemp = dest+((((i<<2)+1)*Width)<<bbp);
size = GAME_STD_WIDTH*(bbp<<1<<2);
memcpy(desttemp,srctemp,size);
memcpy(desttemp+(Width<<bbp),srctemp,size);
memcpy(desttemp+((Width<<bbp)<<1),srctemp,size);
}
}
// functions to directly set and retrieve pixels from the VGA display
void CVideoDriver::setpixel(unsigned int x, unsigned int y, unsigned char c)
{
if( x > 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;i<NumConsoleMessages;i++)
{
g_pGraphics->drawFont( (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; }

View File

@@ -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 <SDL.h>
#include <iostream>
#include <list>
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<st_resolution> m_Resolutionlist;
list<st_resolution> :: 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_ */

View File

@@ -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 <gerstrong@gmail.com> (2008)
Implemented by Gerhard Stein <gerstrong@gmail.com> (2008,2009)
Copyright (C) 2007 Hans de Goede <j.w.r.degoede@hhs.nl>
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<br>", inputfname);
if (strcmp((char *)(&buf[sounds_start]), "SND"))
{
g_pLogFile->ftextOut( "Error: Beginning of sound data not found at expected offset<br>");
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<br>", outputfname);
fclose(fin);
fclose(fout);
}
delete ExeFile;
return ret;
}
void CSound::setSoundmode(int freq, bool stereo)

View File

@@ -9,89 +9,68 @@
#include <vorbis/codec.h>
#include <vorbis/vorbisfile.h>
#include <cstdio>
#include <iostream>
#include <vector>
#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<char> 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; i<psound->sound_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<br>");
return 1;
}
int eof=0;
while(!eof){
ret=ov_read(&oggStream,stream + pos,sizeof(stream),0,2,1,&section);
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!<br>");
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

View File

@@ -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],"");

View File

@@ -0,0 +1,137 @@
/*
* CEGAGraphics.cpp
*
* Created on: 11.07.2009
* Author: gerstrong
*/
#include "CEGAGraphics.h"
#ifdef TARGET_WIN32
#include <dir.h>
#endif
#include <fstream>
#include <vector>
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<char> 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; }

View File

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

266
src/vorticon/CEGALatch.cpp Normal file
View File

@@ -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 <stdio.h>
#include <string.h>
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 ; i<m_bitmaps ; i++)
{
memcpy(&(Bitmap[i].width),data+16*i,2);
memcpy(&(Bitmap[i].height),data+16*i+2,2);
memcpy(&(Bitmap[i].location),data+16*i+4,4);
memcpy(Bitmap[i].name,data+16*i+8,8);
Bitmap[i].width *= 8; // The width is always divided by eight
}
return true;
}
bool CEGALatch::loadData(const char *filename, bool compresseddata)
{
FILE* latchfile;
char *RawData;
latchfile = fopen(filename,"rb");
if(!latchfile)
return false;
RawData = new char[m_latchplanesize * 4];
// 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_latchplanesize*4) ; 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;
plane1 = 0;
plane2 = (m_latchplanesize * 1);
plane3 = (m_latchplanesize * 2);
plane4 = (m_latchplanesize * 3);
// ** read the 8x8 tiles **
//g_pLogFile->ftextOut("latch_loadlatch(): Decoding 8x8 tiles...<br>", 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;t<m_fonttiles;t++)
{
for(int y=0;y<8;y++)
{
for(int x=0;x<8;x++)
{
// if we're on the first plane start with black,
// else merge with the previously accumulated data
if (p==0)
{
c = 0;
}
else
{
c = font[t][y][x];
}
// read a bit out of the current plane, shift it into the
// correct position and merge it
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;
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;t<m_num16tiles;t++)
{
for(int y=0;y<16;y++)
{
for(int x=0;x<16;x++)
{
if (p==0)
{
c = 0;
}
else
{
c = tiledata[t][y][x];
}
c |= (Planes->getbit(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;i<m_bitmaps;i++)
{
// keep a tally of the bitmap sizes so we'll know how much RAM we have
// to allocate for all of the bitmaps once they're decoded
BitmapBufferRAMSize += (Bitmap[i].width *
Bitmap[i].height);
}
BitmapBufferRAMSize++;
BitmapData = new char[BitmapBufferRAMSize];
// set up the getbit() function
Planes = new CPlanes(plane1 + m_bitmaplocation,
plane2 + m_bitmaplocation,
plane3 + m_bitmaplocation,
plane4 + m_bitmaplocation,
0);
// decode bitmaps into the BitmapData structure. The bitmaps are
// loaded into one continous stream of image data, with the bitmaps[]
// array giving pointers to where each bitmap starts within the stream.
const char defbitmapname[][9] = { "TITLE", "IDLOGO", "F1HELP", "HIGHSCOR",
"NAME", "SCORE", "PARTS", "GAMEOVER", "AN", "PRESENT", "APOGEE", "KEENSHIP", "WINDON",
"WINDOFF", "ONEMOMEN", "OFAN", "PRODUCT", "IDSOFT"};
// In case there is a strange mod or defect episode, put some names to it!
char *bmdataptr;
for(int p=0 ; p<4 ; p++)
{
// this points to the location that we're currently
// decoding bitmap data to
bmdataptr = &BitmapData[0];
for(int b=0 ; b<m_bitmaps ; b++)
{
bitmaps[b].xsize = Bitmap[b].width;
bitmaps[b].ysize = Bitmap[b].height;
if( Bitmap[b].name[0] == 0 && b<18 )
strcpy(bitmaps[b].name,defbitmapname[b]);
else
memcpy(bitmaps[b].name, Bitmap[b].name, 8);
bitmaps[b].name[8] = 0; //ensure null-terminated
bitmaps[b].bmptr = (unsigned char*) bmdataptr;
for(int y=0 ; y<bitmaps[b].ysize ; y++)
{
for(int x=0 ; x<bitmaps[b].xsize ; x++)
{
if (p==0)
{
c = 0;
}
else
{
c = *bmdataptr;
}
c |= (Planes->getbit(RawData, p) << p);
if (p==3 && c==0) c = 16;
*bmdataptr = c;
bmdataptr++;
}
}
}
}
delete Planes;
if(RawData){ delete[] RawData; RawData = NULL;}
return true;
}

57
src/vorticon/CEGALatch.h Normal file
View File

@@ -0,0 +1,57 @@
/*
* CEGALatch.h
*
* Created on: 11.07.2009
* Author: gerstrong
*/
#ifndef CEGALATCH_H_
#define CEGALATCH_H_
#include <SDL/SDL.h>
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_ */

172
src/vorticon/CEGASprit.cpp Normal file
View File

@@ -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 <stdio.h>
#include <string.h>
////////////////////////
// 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<m_numsprites ; i++ )
{
memcpy(&(Sprite[i].width),data+128*i,2);
memcpy(&(Sprite[i].height),data+128*i+2,2);
memcpy(&(Sprite[i].location_offset),data+128*i+4,2);
memcpy(&(Sprite[i].location),data+128*i+6,2);
memcpy(&(Sprite[i].hitbox_l),data+128*i+8,2);
memcpy(&(Sprite[i].hitbox_u),data+128*i+10,2);
memcpy(&(Sprite[i].hitbox_r),data+128*i+12,2);
memcpy(&(Sprite[i].hitbox_b),data+128*i+14,2);
memcpy(Sprite[i].name,data+128*i+16,12);
memcpy(&(Sprite[i].hv_offset),data+128*i+28,4);
Sprite[i].width *= 8; // Another case where the width is divided by 8
Sprite[i].hitbox_l >>= 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 ; s<m_numsprites ; s++)
{
sprites[s].xsize = Sprite[s].width;
sprites[s].ysize = Sprite[s].height;
sprites[s].bboxX1 = (Sprite[s].hitbox_l << CSF);
sprites[s].bboxY1 = (Sprite[s].hitbox_u << CSF);
sprites[s].bboxX2 = (Sprite[s].hitbox_r << CSF);
sprites[s].bboxY2 = (Sprite[s].hitbox_b << CSF);
for(int y=0 ; y<sprites[s].ysize ; y++)
{
for(int x=0 ; x<sprites[s].xsize ; x++)
{
if (p==0)
{
c = 0;
}
else
{
c = sprites[s].imgdata[y][x];
}
c |= (Planes->getbit(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 ; s<m_numsprites ; s++)
{
for(int y=0 ; y<sprites[s].ysize ; y++)
{
for(int x=0 ; x<sprites[s].xsize ; x++)
{
sprites[s].maskdata[y][x] = (1 - Planes->getbit(RawData, 4));
}
}
}
delete Planes;
if(RawData){ delete[] RawData; RawData = NULL;}
return true;
}

44
src/vorticon/CEGASprit.h Normal file
View File

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

View File

@@ -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;

View File

@@ -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() )

View File

@@ -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<offset_end ; pos++)
{
string Text;
while(buf[pos] != 0)
{
Text += buf[pos];
pos++;
}
pos++;
if(!Text.empty()) // not empty
StringList.push_back(Text);
}
list<string> :: iterator i;
#include <iostream>
for(i=StringList.begin() ; i!=StringList.end() ; i++)
{
std::cout << *i << std::endl;
}
return true;
}
char *CMessages::getString(const char *IDtext)
{
return 0;
}

32
src/vorticon/CMessages.h Normal file
View File

@@ -0,0 +1,32 @@
/*
* CMessages.h
*
* Created on: 16.07.2009
* Author: gerstrong
*/
#ifndef CMESSAGES_H_
#define CMESSAGES_H_
#include <list>
#include <string>
#include <iostream>
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<string> StringList;
list<string> StringIDList;
};
#endif /* CMESSAGES_H_ */

53
src/vorticon/CPlanes.cpp Normal file
View File

@@ -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;
}

24
src/vorticon/CPlanes.h Normal file
View File

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