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

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