diff --git a/src/CGame.cpp b/src/CGame.cpp index 6aa24af59..78160b697 100644 --- a/src/CGame.cpp +++ b/src/CGame.cpp @@ -27,7 +27,6 @@ CGame::CGame() { m_Episode = 0; - memset(m_DataDirectory,0,256); TileLoader = NULL; EGAGraphics = NULL; @@ -218,13 +217,13 @@ short CGame::runCycle(stCloneKeenPlus *pCKP) return 0; } -int CGame::loadResources(unsigned short Episode, char *DataDirectory) +int CGame::loadResources(unsigned short Episode, const std::string& DataDirectory) { m_Episode = Episode; - memcpy(m_DataDirectory, DataDirectory, 256); + m_DataDirectory = DataDirectory; - if( ( *(DataDirectory+strlen(DataDirectory)-1) != '/' ) && strlen(DataDirectory) > 0) - strcat(DataDirectory,"/"); + if( m_DataDirectory.size() > 0 && m_DataDirectory[m_DataDirectory.size()-1] != '/' ) + m_DataDirectory += "/"; // Decode the entire graphics for the game (EGALATCH, EGASPRIT) EGAGraphics = new CEGAGraphics(Episode, DataDirectory); // Path is relative to the data dir @@ -277,8 +276,6 @@ void CGame::preallocateCKP(stCloneKeenPlus *pCKP) pCKP->GameData = NULL; pCKP->GameData = new stGameData[1]; - memset(pCKP->GameData, 0, sizeof(stGameData)); - framebyframe = 0; demomode = DEMO_NODEMO; diff --git a/src/CGame.h b/src/CGame.h index 6dd5ce2e0..ab8afeeb2 100644 --- a/src/CGame.h +++ b/src/CGame.h @@ -8,7 +8,7 @@ #ifndef CGAME_H_ #define CGAME_H_ -#include +#include #include "vorticon/CEGAGraphics.h" #include "vorticon/CMessages.h" @@ -17,15 +17,14 @@ public: CGame(); virtual ~CGame(); - int loadResources(unsigned short Episode, char *DataDirectory); + int loadResources(unsigned short Episode, const std::string& DataDirectory); void freeResources(void); short runCycle(stCloneKeenPlus *pCKP); void preallocateCKP(stCloneKeenPlus *pCKP); private: - static const unsigned short MAX_TEXT_LENGTH = 256; unsigned short m_Episode; - char m_DataDirectory[MAX_TEXT_LENGTH]; + std::string m_DataDirectory; int current_demo; CEGAGraphics *EGAGraphics; diff --git a/src/CGraphics.cpp b/src/CGraphics.cpp index 6af7864fa..53c179a3d 100644 --- a/src/CGraphics.cpp +++ b/src/CGraphics.cpp @@ -10,12 +10,14 @@ * not platform-specific). */ -#include "CGraphics.h" #include "keen.h" +#include "keenext.h" +#include "CGraphics.h" #include "sdl/CVideoDriver.h" #include "sdl/video/colourtable.h" #include "sdl/CVideoDriver.h" #include "CLogFile.h" +#include "StringUtils.h" CGraphics::CGraphics() { HQBitmap = NULL; @@ -591,13 +593,13 @@ int c; } // font drawing functions -void CGraphics::drawFont(unsigned char *text, int xoff, int yoff, int highlight) +void CGraphics::drawFont(const std::string& text, int xoff, int yoff, int highlight) { unsigned int i,x=xoff,y; int c; y = yoff; - for(i=0;i #include #include "hqp/CHQBitmap.h" @@ -44,18 +45,18 @@ public: void drawBitmap2FG(int xa, int ya, int b); int getBitmapNumberFromName(const char *bmname); void sb_drawCharacterinverse(int x, int y, int f); - void drawFont(unsigned char *text, int xoff, int yoff, int highlight); - void sb_font_draw(const unsigned char *text, int xoff, int yoff); - void sb_mask_font_draw(unsigned char *text, int xoff, int yoff, char mask); - void sb_color_font_draw(unsigned char *text, int xoff, int yoff, unsigned int colour, unsigned short bgcolour); - void sb_font_draw_inverse(unsigned char *text, int xoff, int yoff); + void drawFont(const std::string& text, int xoff, int yoff, int highlight); + void sb_font_draw(const std::string& text, int xoff, int yoff); + void sb_mask_font_draw(const std::string& text, int xoff, int yoff, char mask); + void sb_color_font_draw(const std::string& text, int xoff, int yoff, unsigned int colour, unsigned short bgcolour); + void sb_font_draw_inverse(const std::string& text, int xoff, int yoff); void drawTile_direct(int x, int y, unsigned int t); void setFadeBlack(bool value); Uint8 *getScrollbuffer(void); void renderHQBitmap(); - void loadHQGraphics(unsigned char episode, unsigned char level, char *datadir); + void loadHQGraphics(unsigned char episode, unsigned char level, const std::string& datadir); void unloadHQGraphics(); private: diff --git a/src/CLatch.cpp b/src/CLatch.cpp index 6f762702f..bb6165230 100644 --- a/src/CLatch.cpp +++ b/src/CLatch.cpp @@ -13,6 +13,7 @@ #include "fileio.h" #include "keen.h" #include "keenext.h" +#include "StringUtils.h" #include "CLogFile.h" //#include "vorticon/CEGAGraphics.h" @@ -58,19 +59,15 @@ char CLatch::loadHeader(int episode, const char *path) FILE *headfile; unsigned long SpriteTableRAMSize; unsigned long BitmapTableRAMSize; - char buf[12]; + std::string buf; int i,j,k; - char fname[80]; - char buffer[256]; + std::string fname; + std::string buffer; - memset(buffer,0,256); - memset(fname,0,80); + buffer = formatPathString(path); + buffer += "egahead.ck"; - formatPathString(buffer,path); - - strcat(buffer,"egahead.ck"); - - sprintf(fname, "%s%d", buffer,episode); + fname = buffer + itoa(episode); /*CEGAGraphics *EGAGraphics; @@ -80,14 +77,14 @@ char CLatch::loadHeader(int episode, const char *path) delete EGAGraphics;*/ - headfile = fopen(fname, "rb"); + headfile = fopen(fname.c_str(), "rb"); if (!headfile) { - g_pLogFile->ftextOut("latch_loadheader(): unable to open '%s'.
", fname); + g_pLogFile->ftextOut("latch_loadheader(): unable to open '%s'.
", fname.c_str()); return 1; } - g_pLogFile->ftextOut("latch_loadheader(): reading main header from '%s'...
", fname); + g_pLogFile->ftextOut("latch_loadheader(): reading main header from '%s'...
", fname.c_str()); // read the main header data from EGAHEAD LatchHeader.LatchPlaneSize = fgetl(headfile); @@ -135,7 +132,7 @@ char CLatch::loadHeader(int episode, const char *path) return 1; } - g_pLogFile->ftextOut("latch_loadheader(): Reading sprite table from '%s'...
", fname); + g_pLogFile->ftextOut("latch_loadheader(): Reading sprite table from '%s'...
", fname.c_str()); fseek(headfile, LatchHeader.OffSpriteTable, SEEK_SET); for(i=0;iftextOut("latch_loadheader(): reading bitmap table from '%s'...
", fname); + g_pLogFile->ftextOut("latch_loadheader(): reading bitmap table from '%s'...
", fname.c_str()); fseek(headfile, LatchHeader.OffBitmapTable, SEEK_SET); @@ -191,7 +188,7 @@ char CLatch::loadHeader(int episode, const char *path) // print the bitmap info to the console for debug for(j=0;j<8;j++) buf[j] = BitmapTable[i].Name[j]; buf[j] = 0; - g_pLogFile->ftextOut(" Bitmap '%s': %dx%d at offset %04x. RAMAllocSize=0x%04x
", buf,BitmapTable[i].Width,BitmapTable[i].Height,BitmapTable[i].Offset,BitmapBufferRAMSize); + g_pLogFile->ftextOut(" Bitmap '%s': %dx%d at offset %04x. RAMAllocSize=0x%04x
", buf.c_str(),BitmapTable[i].Width,BitmapTable[i].Height,BitmapTable[i].Offset,BitmapBufferRAMSize); } BitmapBufferRAMSize++; @@ -206,26 +203,24 @@ char CLatch::load(int episode, const char *path) { FILE *latchfile; unsigned long plane1, plane2, plane3, plane4; -char fname[80]; + std::string fname; int x,y,t,b,c,p; char *bmdataptr; unsigned long RawDataSize; //unsigned char ch; -char buffer[256]; + std::string buffer; - formatPathString(buffer,path); + buffer = formatPathString(path); + buffer += "egalatch.ck"; + fname = buffer + itoa(episode); - strcat(buffer,"egalatch.ck"); + g_pLogFile->ftextOut("latch_loadlatch(): Opening file '%s'.
", fname.c_str()); - sprintf(fname, "%s%c", buffer,episode + '0'); - - g_pLogFile->ftextOut("latch_loadlatch(): Opening file '%s'.
", fname); - - latchfile = fopen(fname, "rb"); + latchfile = fopen(fname.c_str(), "rb"); if (!latchfile) { - g_pLogFile->ftextOut("latch_loadlatch(): Unable to open '%s'!
", fname); + g_pLogFile->ftextOut("latch_loadlatch(): Unable to open '%s'!
", fname.c_str()); return 1; } @@ -266,7 +261,7 @@ char buffer[256]; plane4 = (LatchHeader.LatchPlaneSize * 3); // ** read the 8x8 tiles ** - g_pLogFile->ftextOut("latch_loadlatch(): Decoding 8x8 tiles...
", fname); + g_pLogFile->ftextOut("latch_loadlatch(): Decoding 8x8 tiles...
", fname.c_str()); // set up the getbit() function @@ -309,7 +304,7 @@ char buffer[256]; delete Planes; // ** read the 16x16 tiles ** - g_pLogFile->ftextOut("latch_loadlatch(): Decoding 16x16 tiles...
", fname); + g_pLogFile->ftextOut("latch_loadlatch(): Decoding 16x16 tiles...
", fname.c_str()); // set up the getbit() function Planes = new CPlanes(plane1 + LatchHeader.Off16Tiles, \ @@ -354,7 +349,7 @@ char buffer[256]; return 1; } - g_pLogFile->ftextOut("latch_loadlatch(): Decoding bitmaps...
", fname); + g_pLogFile->ftextOut("latch_loadlatch(): Decoding bitmaps...
", fname.c_str()); // set up the getbit() function Planes = new CPlanes(plane1 + LatchHeader.OffBitmaps, \ @@ -419,24 +414,22 @@ char CLatch::loadSprites(int episode, const char *path) { FILE *spritfile; unsigned long plane1, plane2, plane3, plane4, plane5; -char fname[80]; + std::string fname; int x,y,s,c,p; unsigned long RawDataSize; -char buffer[256]; + std::string buffer; CPlanes *Planes; - formatPathString(buffer,path); + buffer = formatPathString(path); + buffer += "egasprit.ck"; + fname = buffer + itoa(episode); - strcat(buffer,"egasprit.ck"); + g_pLogFile->ftextOut("latch_loadsprites(): Opening file '%s'.
", fname.c_str()); - sprintf(fname, "%s%c", buffer,episode + '0'); - - g_pLogFile->ftextOut("latch_loadsprites(): Opening file '%s'.
", fname); - - spritfile = fopen(fname, "rb"); + spritfile = fopen(fname.c_str(), "rb"); if (!spritfile) { - g_pLogFile->ftextOut("latch_loadsprites(): Unable to open '%s'!
", fname); + g_pLogFile->ftextOut("latch_loadsprites(): Unable to open '%s'!
", fname.c_str()); return 1; } @@ -475,7 +468,7 @@ CPlanes *Planes; plane5 = (LatchHeader.SpritePlaneSize * 4); // ** read the sprites ** - g_pLogFile->ftextOut("latch_loadsprites(): Decoding sprites...
", fname); + g_pLogFile->ftextOut("latch_loadsprites(): Decoding sprites...
", fname.c_str()); // set up the getbit() function Planes = new CPlanes(plane1 + LatchHeader.OffSprites, \ diff --git a/src/CVec.h b/src/CVec.h new file mode 100644 index 000000000..607474f5e --- /dev/null +++ b/src/CVec.h @@ -0,0 +1,168 @@ +///////////////////////////////////////// +// +// OpenLieroX +// +// Auxiliary Software class library +// +// based on the work of JasonB +// enhanced by Dark Charlie and Albert Zeyer +// +// code under LGPL +// +///////////////////////////////////////// + + +// 2D Vector / Matrix class +// Created 20/11/01 +// By Jason Boettcher +// enhanced by Albert Zeyer + +#ifndef __CVEC_H__ +#define __CVEC_H__ + +#include + +template +struct VectorD2 { + // Constructor + VectorD2() : x(0), y(0) {} + VectorD2(_T _x, _T _y) : x(_x), y(_y) {} + + + // Attributes + _T x, y; + + + // Methods + + template + VectorD2(const _T2& cp) { + x = (_T)cp.x; y = (_T)cp.y; + } + + float GetLength() const { return sqrtf((float)x*x + (float)y*y); } + _T GetLength2() const { return x*x + y*y; }; + + float GetAngle() const { return (float)atan2((float)y,(float)x); } + + VectorD2 Normalize() { return *this/GetLength(); } + + _T Scalar(const VectorD2& vec) const { return x*vec.x + y*vec.y; } + + VectorD2 orthogonal() const { return VectorD2(y, -x); } + + _T Cross(const VectorD2& oth) const { return x * oth.y - y * oth.x; } + + // Overloads + VectorD2 operator*(const float scalar) const { + return VectorD2(x*scalar,y*scalar); + } + VectorD2 operator*(const int scalar) const { + return VectorD2(x*scalar,y*scalar); + } + /* + VectorD2 operator*(const VectorD2& vec) const { + // WARNING: this doesn't make any sense (in most 'mathematical' cases) + // TODO: why is it here? I would expect dot product or cross product... + return VectorD2(x*vec.x,y*vec.y); + } + */ + VectorD2 operator/(const float scalar) const { + return VectorD2(x/scalar,y/scalar); + } + VectorD2 operator/(const int scalar) const { + return VectorD2(x/scalar,y/scalar); + } + VectorD2 operator+(const VectorD2& vec) const { + return VectorD2(x+vec.x,y+vec.y); + } + VectorD2 operator-(const VectorD2& vec) const { + return VectorD2(x-vec.x,y-vec.y); + } + VectorD2 operator-() const { + return VectorD2(-x,-y); + } + VectorD2& operator+=(const VectorD2& vec) { + x+=vec.x; y+=vec.y; + return *this; + } + VectorD2& operator-=(const VectorD2& vec) { + x-=vec.x; y-=vec.y; + return *this; + } + VectorD2& operator*=(const float scalar) { + x*=scalar; y*=scalar; + return *this; + } + VectorD2& operator*=(const int scalar) { + x*=scalar; y*=scalar; + return *this; + } + + template + bool operator<(const VectorD2<_T2> & op) const { + return ((y == op.y && (x < op.x)) + || y < op.y); + } + + template + bool operator==(const VectorD2<_T2> & op) const { + return (x==op.x && y==op.y); + } + + template + bool operator!=(const VectorD2<_T2> & op) const { + return (x!=op.x || y!=op.y); + } + + template + bool operator<=(const VectorD2<_T2> & op) const { + return ((*this < op) || (*this == op)); + } + +}; + +template +struct VectorD2__absolute_less { + VectorD2<_T> zero; + VectorD2__absolute_less(VectorD2<_T> z = VectorD2<_T>(0,0)) : zero(z) {} + + bool operator()(const VectorD2<_T> v1, const VectorD2<_T> v2) const { + return (v1-zero).GetLength2() < (v2-zero).GetLength2(); + } +}; + + + +typedef VectorD2 CVec; + +template +struct MatrixD2 { + VectorD2<_T> v1; + VectorD2<_T> v2; + + MatrixD2() {} + MatrixD2(_T f) { v1.x = f; v2.y = f; } + MatrixD2(_T x1, _T y1, _T x2, _T y2) : v1(x1,y1), v2(x2,y2) {} + MatrixD2(const VectorD2<_T>& _v1, const VectorD2<_T>& _v2) : v1(_v1), v2(_v2) {} + static MatrixD2 Rotation(_T x, _T y) { return MatrixD2(x,y,-y,x); } + + template bool operator==(const MatrixD2<_T2>& m) const { return v1 == m.v1 && v2 == m.v2; } + template bool operator!=(const MatrixD2<_T2>& m) const { return !(*this == m); } + + VectorD2<_T> operator*(const VectorD2<_T>& v) const { + return VectorD2<_T>( v1.x * v.x + v2.x * v.y, v1.y * v.x + v2.y * v.y ); + } + + MatrixD2<_T> operator*(const MatrixD2<_T>& m) const { + return MatrixD2<_T>( *this * m.v1, *this * m.v2 ); + } + + MatrixD2<_T>& operator*=(const MatrixD2<_T>& m) { + return *this = *this * m; + } +}; + + + +#endif // __CVEC_H__ diff --git a/src/Color.h b/src/Color.h new file mode 100644 index 000000000..80ae1c7ac --- /dev/null +++ b/src/Color.h @@ -0,0 +1,133 @@ +/* + OpenLieroX + + color type and related functions + + code under LGPL + created 10-01-2007 +*/ + +#ifndef __COLOR_H__ +#define __COLOR_H__ + +#include +#include + +#include "MathLib.h" + + +/////////////////// +// If you want to use the adress of some Uint32 directly with memcpy or similar, use this +inline Uint32 SDLColourToNativeColour(Uint32 pixel, short bpp) { +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + return (pixel << (32 - 8 * bpp)); +#else + return pixel; +#endif +} + +///////////////// +// If you copied some data directly with memcpy into an Uint32, use this +inline Uint32 NativeColourToSDLColour(Uint32 pixel, short bpp) { +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + return (pixel >> (32 - 8 * bpp)); +#else + return pixel; +#endif +} + + + +/////////////// +// Get the specified component from the pixel (grabbed from SDL) +inline Uint8 GetR(Uint32 pixel, SDL_PixelFormat *fmt) { + return (Uint8)((((pixel & fmt->Rmask) >> fmt->Rshift) << fmt->Rloss) + + (((pixel & fmt->Rmask) >> fmt->Rshift) >> (8 - (fmt->Rloss << 1)))); +} + +inline Uint8 GetG(Uint32 pixel, SDL_PixelFormat *fmt) { + return (Uint8)((((pixel & fmt->Gmask) >> fmt->Gshift) << fmt->Gloss) + + (((pixel & fmt->Gmask) >> fmt->Gshift) >> (8 - (fmt->Gloss << 1)))); +} + +inline Uint8 GetB(Uint32 pixel, SDL_PixelFormat *fmt) { + return (Uint8)((((pixel & fmt->Bmask) >> fmt->Bshift) << fmt->Bloss) + + (((pixel & fmt->Bmask) >> fmt->Bshift) >> (8 - (fmt->Bloss << 1)))); +} + +inline Uint8 GetA(Uint32 pixel, SDL_PixelFormat *fmt) { + return (Uint8)((((pixel & fmt->Amask) >> fmt->Ashift) << fmt->Aloss) + + (((pixel & fmt->Amask) >> fmt->Ashift) >> (8 - (fmt->Aloss << 1)))); +} + +extern SDL_PixelFormat* mainPixelFormat; + +inline SDL_PixelFormat* getMainPixelFormat() { + return mainPixelFormat; +} + +/////////////// +// Returns true if the two colors are the same, ignoring the alpha +// HINT: both colors have to be in the same pixelformat +inline bool EqualRGB(Uint32 p1, Uint32 p2, SDL_PixelFormat* fmt) { + return ((p1|fmt->Amask) == (p2|fmt->Amask)); +} + +/////////////// +// Creates a int colour based on the 3 components +// HINT: format is that one from videosurface! +inline Uint32 MakeColour(Uint8 r, Uint8 g, Uint8 b) { + return SDL_MapRGB(getMainPixelFormat(), r, g, b); +} + +/////////////// +// Creates a int colour based on the 4 components +// HINT: format is that one from videosurface! +inline Uint32 MakeColour(Uint8 r, Uint8 g, Uint8 b, Uint8 a) { + return SDL_MapRGBA(getMainPixelFormat(), r, g, b, a); +} + + + +// Device-independent color +struct Color { + Color() : r(0), g(0), b(0), a(SDL_ALPHA_OPAQUE) {} + Color(Uint8 _r, Uint8 _g, Uint8 _b) : r(_r), g(_g), b(_b), a(SDL_ALPHA_OPAQUE) {} + Color(Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a) : r(_r), g(_g), b(_b), a(_a) {} + Color(SDL_PixelFormat *f, Uint32 cl) { SDL_GetRGBA(cl, f, &r, &g, &b, &a); } + explicit Color(Uint32 cl) { set(getMainPixelFormat(), cl); } + Color(const SDL_Color& cl) : r(cl.r), g(cl.g), b(cl.b), a(SDL_ALPHA_OPAQUE) {} + + Uint8 r; + Uint8 g; + Uint8 b; + Uint8 a; + + Uint32 get() const { return get(getMainPixelFormat()); } + Uint32 get(SDL_PixelFormat *f) const { return SDL_MapRGBA(f, r, g, b, a); } + Uint32 getDefault() const { return (Uint32(r) << 24) | (Uint32(g) << 16) | (Uint32(b) << 8) | Uint32(a); } + Color derived(Sint16 _r, Sint16 _g, Sint16 _b, Sint16 _a) const { + return Color( + Uint8(CLAMP(_r + r, 0, 255)), + Uint8(CLAMP(_g + g, 0, 255)), + Uint8(CLAMP(_b + b, 0, 255)), + Uint8(CLAMP(_a + a, 0, 255))); + } + void set(SDL_PixelFormat *f, Uint32 cl) { SDL_GetRGBA(cl, f, &r, &g, &b, &a); } + + bool operator == ( const Color & c ) const { return r == c.r && g == c.g && b == c.b && a == c.a; }; + bool operator != ( const Color & c ) const { return ! ( *this == c ); }; + + Color operator * ( float f ) const { return Color( Uint8(CLAMP(r*f,0.0f,255.0f)), Uint8(CLAMP(g*f,0.0f,255.0f)), Uint8(CLAMP(b*f,0.0f,255.0f)), a ); }; + Color operator + ( const Color & c ) const { return Color( (Uint8)CLAMP(Uint16(r)+c.r,0,255), (Uint8)CLAMP(Uint16(g)+c.g,0,255), (Uint8)CLAMP(Uint16(b)+c.b,0,255), (Uint8)(Uint16(a)+c.a)/2 ); }; + bool operator<(const Color& c) const { + if(r != c.r) return r < c.r; + if(g != c.g) return g < c.g; + if(b != c.b) return b < c.b; + return a < c.a; + } + Uint8& operator[](int i) { switch(i) { case 0: return r; case 1: return g; case 2: return b; case 3: return a; default: assert(false); } return *((Uint8*)NULL); } + Uint8 operator[](int i) const { switch(i) { case 0: return r; case 1: return g; case 2: return b; case 3: return a; default: assert(false); } return 0; } +}; + +#endif diff --git a/src/CrashHandler.cpp b/src/CrashHandler.cpp new file mode 100644 index 000000000..29cea244d --- /dev/null +++ b/src/CrashHandler.cpp @@ -0,0 +1,540 @@ +/* + OpenLieroX CrashHandler + + registers a crash handler in the OS and handles the crashes + + code under LGPL + created 09-07-2008 by Albert Zeyer +*/ + +#include "CrashHandler.h" +#include "StringUtils.h" +#include "Debug.h" + + +#ifndef WIN32 +#include +sigjmp_buf longJumpBuffer; +#endif + + +// note: important to have const char* here because std::string is too dynamic, could be screwed up when returning +void SetCrashHandlerReturnPoint(const char* name) { +#ifndef WIN32 + if(sigsetjmp(longJumpBuffer, true) != 0) { + hints << "returned from sigsetjmp in " << name << endl; + if(/*tLXOptions->bFullscreen*/ false) { + notes << "we are in fullscreen, going to window mode now" << endl; + // tLXOptions->bFullscreen = false; + // doSetVideoModeInMainThread(); + notes << "back in window mode" << endl; + } + } +#endif +} + + + +// +// WIN 32 +// + +#if defined(_MSC_VER) + +#define itoa _itoa + +#include +#include +#include "FindFile.h" // for IsFileAvailable and mkdir + +LONG WINAPI CustomUnhandledExceptionFilter(PEXCEPTION_POINTERS pExInfo); + +// Crash handling +class CrashHandlerImpl : public CrashHandler { +public: + CrashHandlerImpl() { +#ifdef _DEBUG +#ifdef USE_DEFAULT_MSC_DELEAKER + _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); +#endif +#endif // _DEBUG + + SetUnhandledExceptionFilter(CustomUnhandledExceptionFilter); + + notes << "Win32 Exception Filter installed" << endl; + } + +}; + +extern void OlxWriteCoreDump_Win32(const char* fileName, PEXCEPTION_POINTERS pExInfo); + +/////////////////// +// This callback function is called whenever an unhandled exception occurs +LONG WINAPI CustomUnhandledExceptionFilter(PEXCEPTION_POINTERS pExInfo) +{ + // Get the path + char buf[1024]; + if (!SHGetSpecialFolderPath(NULL, buf, CSIDL_PERSONAL, false)) { + buf[0] = '\0'; + strcpy(buf, "bug_reports"); + } else { + size_t len = strnlen(buf, sizeof(buf)); + if (buf[len - 1] != '\\' && buf[len - 1] != '/') + strncat(buf, "\\OpenLieroX", sizeof(buf)); + else + strncat(buf, "OpenLieroX", sizeof(buf)); + CreateDirectory(buf, NULL); // If the crash occurs at first startup, the OpenLieroX dir doesn't have to exist + strncat(buf, "\\bug_reports", sizeof(buf)); + fix_markend(buf); + } + CreateDirectory(buf, NULL); + strncat(buf, "\\", sizeof(buf)); + + // Get the file name + char checkname[1024]; + + char tmp[32]; + FILE *f = NULL; + for (int i=1;1;i++) { + itoa(i, tmp, 10); + fix_markend(tmp); + strncpy(checkname, buf, sizeof(checkname)); + strncat(checkname, "report", sizeof(checkname)); + strncat(checkname, tmp, sizeof(checkname)); + strncat(checkname, ".dmp", sizeof(checkname)); + f = fopen(checkname, "rb"); + if (!f) + break; + fclose(f); + } + + OlxWriteCoreDump_Win32(checkname, pExInfo); + + // Try to free the cache, it eats a lot of memory + __try { + cCache.Clear(); + } + __except(EXCEPTION_EXECUTE_HANDLER) {} + + // Quit SDL + __try { + SDL_Quit(); + } + __except(EXCEPTION_EXECUTE_HANDLER) {} + + // End conversation logging (to make the XML valid) + __try { + if (convoLogger) + delete convoLogger; + } + __except(EXCEPTION_EXECUTE_HANDLER) {} + + // Close all opened files + fcloseall(); + + + strncpy(&buf[1], checkname, sizeof(buf) - 1); + buf[0] = '\"'; + strncat(buf, "\"", sizeof(buf)); + fix_markend(buf); + + // If ded server is running as service user won't see any dialog anyway + if (!bDedicated) + ShellExecute(NULL,"open","BugReport.exe",buf,NULL,SW_SHOWNORMAL); + + // If running as a dedicated server, restart the application (there usually isn't any person sitting + // at the computer to fix this problem) + // If ded server is running as service it's restarted automatically +#ifdef DEDICATED_ONLY + //ShellExecute(NULL, "open", GetAppPath(), "-dedicated", NULL, SW_SHOWNORMAL); +#else + if (bDedicated) { + //ShellExecute(NULL, "open", GetAppPath(), "-dedicated", NULL, SW_SHOWNORMAL); + } +#endif + + return EXCEPTION_EXECUTE_HANDLER; +} + + + +#elif !defined(WIN32) // MacOSX, Linux, Unix + +#include +#include +#include +#include + +#include +#include +#include + +#if defined(__linux__) || defined(__APPLE__) +// TODO: why is execinfo needed here? at least on MacOSX, it's not needed here +//#include +/* get REG_EIP / REG_RIP from ucontext.h */ +#include +#endif + +#ifndef EIP +#define EIP 14 +#endif + +#if (defined (__x86_64__)) +#ifndef REG_RIP +#define REG_RIP REG_INDEX(rip) /* seems to be 16 */ +#endif +#endif + + +struct signal_def { char name[10]; int id; char description[40]; } ; + +static signal_def signal_data[] = +{ +{ "SIGHUP", SIGHUP, "Hangup (POSIX)" }, +{ "SIGINT", SIGINT, "Interrupt (ANSI)" }, +{ "SIGQUIT", SIGQUIT, "Quit (POSIX)" }, +{ "SIGILL", SIGILL, "Illegal instruction (ANSI)" }, +{ "SIGTRAP", SIGTRAP, "Trace trap (POSIX)" }, +{ "SIGABRT", SIGABRT, "Abort (ANSI)" }, +{ "SIGIOT", SIGIOT, "IOT trap (4.2 BSD)" }, +{ "SIGBUS", SIGBUS, "BUS error (4.2 BSD)" }, +{ "SIGFPE", SIGFPE, "Floating-point exception (ANSI)" }, +{ "SIGKILL", SIGKILL, "Kill, unblockable (POSIX)" }, +{ "SIGUSR1", SIGUSR1, "User-defined signal 1 (POSIX)" }, +{ "SIGSEGV", SIGSEGV, "Segmentation violation (ANSI)" }, +{ "SIGUSR2", SIGUSR2, "User-defined signal 2 (POSIX)" }, +{ "SIGPIPE", SIGPIPE, "Broken pipe (POSIX)" }, +{ "SIGALRM", SIGALRM, "Alarm clock (POSIX)" }, +{ "SIGTERM", SIGTERM, "Termination (ANSI)" }, +//{ "SIGSTKFLT", SIGSTKFLT, "Stack fault" }, +{ "SIGCHLD", SIGCHLD, "Child status has changed (POSIX)" }, +//{ "SIGCLD", SIGCLD, "Same as SIGCHLD (System V)" }, +{ "SIGCONT", SIGCONT, "Continue (POSIX)" }, +{ "SIGSTOP", SIGSTOP, "Stop, unblockable (POSIX)" }, +{ "SIGTSTP", SIGTSTP, "Keyboard stop (POSIX)" }, +{ "SIGTTIN", SIGTTIN, "Background read from tty (POSIX)" }, +{ "SIGTTOU", SIGTTOU, "Background write to tty (POSIX)" }, +{ "SIGURG", SIGURG, "Urgent condition on socket (4.2 BSD)" }, +{ "SIGXCPU", SIGXCPU, "CPU limit exceeded (4.2 BSD)" }, +{ "SIGXFSZ", SIGXFSZ, "File size limit exceeded (4.2 BSD)" }, +{ "SIGVTALRM", SIGVTALRM, "Virtual alarm clock (4.2 BSD)" }, +{ "SIGPROF", SIGPROF, "Profiling alarm clock (4.2 BSD)" }, +{ "SIGWINCH", SIGWINCH, "Window size change (4.3 BSD, Sun)" }, +{ "SIGIO", SIGIO, "I/O now possible (4.2 BSD)" }, +//{ "SIGPOLL", SIGPOLL, "Pollable event occurred (System V)" }, +//{ "SIGPWR", SIGPWR, "Power failure restart (System V)" }, +{ "SIGSYS", SIGSYS, "Bad system call" }, +}; + +static int handlerSignalList[] = { +SIGSEGV, SIGTRAP, SIGABRT, SIGHUP, SIGBUS, SIGILL, SIGFPE, SIGSYS, SIGUSR1, SIGUSR2 +}; + +typedef const char * cchar; + +bool CrashHandler_RecoverAfterCrash = false; + +class CrashHandlerImpl : public CrashHandler { +public: + CrashHandlerImpl() { + if(CrashHandler_RecoverAfterCrash) { + setSignalHandlers(); + DumpCallstack(NullOut); // dummy call to force loading dynamic lib at this point (with sane heap) for backtrace and friends + + notes << "registered simple resuming signal handler" << endl; + } + else + notes << "no signal handler with these settings" << endl; + } + + + static void setSignalHandlers() { + struct sigaction sa; + + sa.sa_sigaction = SimpleSignalHandler; + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_RESTART | SA_SIGINFO; + + for (unsigned int i = 0; i < sizeof(handlerSignalList) / sizeof(int); i++) + sigaction(handlerSignalList[i], &sa, NULL); + } + + static void unsetSignalHandlers() { + for (unsigned int i = 0; i < sizeof(handlerSignalList) / sizeof(int); i++) + signal(handlerSignalList[i], SIG_DFL); + } + + void enable() { if(CrashHandler_RecoverAfterCrash) setSignalHandlers(); } + void disable() { unsetSignalHandlers(); } + + static void SimpleSignalHandler(int signr, siginfo_t *info, void *secret) { + signal(signr, SIG_IGN); // discard all remaining signals + + signal_def *d = NULL; + for (unsigned int i = 0; i < sizeof(signal_data) / sizeof(signal_def); i++) + if (signr == signal_data[i].id) + { d = &signal_data[i]; break; } + if (d) + printf("Got signal 0x%02X (%s): %s\n", signr, d->name, d->description); + else + printf("Got signal 0x%02X\n", signr); + + /* + see this article for further details: (thanks also for some code snippets) + http://www.linuxjournal.com/article/6391 */ + + void *pnt = NULL; +#if defined(__APPLE__) +# if defined(__x86_64__) + ucontext_t* uc = (ucontext_t*) secret; + pnt = (void*) uc->uc_mcontext->__ss.__rip ; +# elif defined(__hppa__) + ucontext_t* uc = (ucontext_t*) secret; + pnt = (void*) uc->uc_mcontext.sc_iaoq[0] & ~0x3UL ; +# elif (defined (__ppc__)) || (defined (__powerpc__)) + ucontext_t* uc = (ucontext_t*) secret; +# if __DARWIN_UNIX03 + pnt = (void*) uc->uc_mcontext->__ss.__srr0 ; +# else + pnt = (void*) uc->uc_mcontext->ss.srr0 ; +# endif +# elif defined(__sparc__) + struct sigcontext* sc = (struct sigcontext*) secret; +# if __WORDSIZE == 64 + pnt = (void*) scp->sigc_regs.tpc ; +# else + pnt = (void*) scp->si_regs.pc ; +# endif +# elif defined(__i386__) + ucontext_t* uc = (ucontext_t*) secret; +# if __DARWIN_UNIX03 + pnt = (void*) uc->uc_mcontext->__ss.__eip ; +# else + pnt = (void*) uc->uc_mcontext->ss.eip ; +# endif +# else +# warning mcontext is not defined for this arch, thus a dumped backtrace could be crippled +# endif +#elif defined(__linux__) +# if defined(__x86_64__) + ucontext_t* uc = (ucontext_t*) secret; + pnt = (void*) uc->uc_mcontext.gregs[REG_RIP] ; +# elif defined(__hppa__) + ucontext_t* uc = (ucontext_t*) secret; + pnt = (void*) uc->uc_mcontext.sc_iaoq[0] & ~0x3UL ; +# elif (defined (__ppc__)) || (defined (__powerpc__)) + ucontext_t* uc = (ucontext_t*) secret; + pnt = (void*) uc->uc_mcontext.regs->nip ; +# elif defined(__sparc__) + struct sigcontext* sc = (struct sigcontext*) secret; +# if __WORDSIZE == 64 + pnt = (void*) scp->sigc_regs.tpc ; +# else + pnt = (void*) scp->si_regs.pc ; +# endif +# elif defined(__i386__) + ucontext_t* uc = (ucontext_t*) secret; + pnt = (void*) uc->uc_mcontext.gregs[REG_EIP] ; +# else +# warning mcontext is not defined for this arch, thus a dumped backtrace could be crippled +# endif +#else +# warning mcontest is not defined for this system, thus a dumped backtraced could be crippled +#endif + + /* potentially correct for other archs: + * alpha: ucp->m_context.sc_pc + * arm: ucp->m_context.ctx.arm_pc + * ia64: ucp->m_context.sc_ip & ~0x3UL + * mips: ucp->m_context.sc_pc + * s390: ucp->m_context.sregs->regs.psw.addr + */ + + if (signr == SIGSEGV || signr == SIGBUS) + printf("Faulty address is %p, called from %p\n", info->si_addr, pnt); + + /* The first two entries in the stack frame chain when you + * get into the signal handler contain, respectively, a + * return address inside your signal handler and one inside + * sigaction() in libc. The stack frame of the last function + * called before the signal (which, in case of fault signals, + * also is the one that supposedly caused the problem) is lost. + */ + + /* the third parameter to the signal handler points to an + * ucontext_t structure that contains the values of the CPU + * registers when the signal was raised. + */ + + // WARNING: dont use cout here in this function, it sometimes screws the cout up + // look at signal(2) for a list of safe functions + + DumpCallstackPrintf(pnt); + +#ifdef DEBUG + // commented out for now because it still doesn't work that good + //OlxWriteCoreDump(d ? d->name : NULL); +#endif + + if(!CrashHandler_RecoverAfterCrash) + { + fflush(stdout); + abort(); +#ifdef DEBUG +// raise(SIGQUIT); +#else +// exit(-1); +#endif + return; + } + setSignalHandlers(); // reset handler + printf("resuming ...\n"); + fflush(stdout); + + setSignalHandlers(); + siglongjmp(longJumpBuffer, 1); // jump back to main loop, maybe we'll be able to continue somehow + } + + ///////////////////////////////////////////////////////////////////////////// + // + // Attempts to cleanup and call drkonqi to process the crash + // (code taken from Lgi (LGPL) and modified) + // + static void DrKonqiSignalHandler(int Sig) { + // Don't get into an infinite loop + signal(SIGSEGV, SIG_DFL); + + // Our pid + int MyPid = getpid(); + printf("CrashHandler trigger MyPid=%i\n", MyPid); + + // Fork to run the crash handler + pid_t Pid = fork(); + if (Pid <= 0) + { + // Pass our state down to the crash handler... + int Args = 0; + cchar Arg[32]; + memset(Arg, 0, sizeof(Arg)); + char SigName[16], PidName[16], Version[32]; + + // TODO: sprintf allocates memory on the heap internally, is it safe to do it here? + sprintf(SigName, "%i", Sig); + sprintf(PidName, "%i", MyPid); +// strcpy( Version, GetFullGameName() ); + + Arg[Args++] = "drkonqi"; + //Arg[Args++] = "--display"; + //Arg[Args++] = XDisplayString(o.XDisplay()); + Arg[Args++] = "--appname"; +// Arg[Args++] = GetFullGameName(); + Arg[Args++] = "--programname"; +// Arg[Args++] = GetFullGameName(); + Arg[Args++] = "--appversion"; + Arg[Args++] = Version; + Arg[Args++] = "--apppath"; +// Arg[Args++] = GetAppPath(); // should be save to call + Arg[Args++] = "--signal"; + Arg[Args++] = SigName; + Arg[Args++] = "--pid"; + Arg[Args++] = PidName; + Arg[Args++] = "--bugaddress"; + Arg[Args++] = "openlierox@az2000.de"; + + setgid(getgid()); + setuid(getuid()); + + execvp("drkonqi", (char* const*)Arg); + } + else + { + // Wait for child to exit + waitpid(Pid, NULL, 0); + _exit(253); + } + } + + // Attempts to cleanup and call bug-buddy to process the crash + static void BugBuddySignalHandler(int Sig) { + // Don't get into an infinite loop + signal(SIGSEGV, SIG_DFL); + + // Our pid + int MyPid = getpid(); + printf("CrashHandler trigger MyPid=%i\n", MyPid); + + // Fork to run the crash handler + pid_t Pid = fork(); + if (Pid <= 0) + { + // Pass our state down to the crash handler... + int Args = 0; + cchar Arg[32]; + memset(Arg, 0, sizeof(Arg)); + char SigName[16], PidName[16], Version[40]; + + sprintf(SigName, "%i", Sig); + sprintf(PidName, "%i", MyPid); +// strcpy( Version, GetFullGameName() ); + + Arg[Args++] = "bug-buddy"; + //Arg[Args++] = "--display"; + //Arg[Args++] = XDisplayString(o.XDisplay()); + Arg[Args++] = "--appname"; + Arg[Args++] = Version; + Arg[Args++] = "--pid"; + Arg[Args++] = PidName; + Arg[Args++] = "--name"; + Arg[Args++] = "Albert Zeyer"; + Arg[Args++] = "--email"; + Arg[Args++] = "openlierox@az2000.de"; + + setgid(getgid()); + setuid(getuid()); + + execvp("bug-buddy", (char* const*)Arg); + } + else + { + // Wait for child to exit + waitpid(Pid, NULL, 0); + _exit(253); + } + } + + +}; + + +#else +class CrashHandlerImpl : public CrashHandler { +public: + CrashHandlerImpl() { + notes << "Dummy CrashHandler implementation" << endl; + } +}; + +#endif + +CrashHandlerImpl* crashHandlerInstance = NULL; + +void CrashHandler::init() { + if(crashHandlerInstance) { + warnings << "CrashHandler tried to init twice" << endl; + return; + } + notes << "Installing CrashHandler .. "; + crashHandlerInstance = new CrashHandlerImpl(); +} + +void CrashHandler::uninit() { + if(crashHandlerInstance) { + delete crashHandlerInstance; + crashHandlerInstance = NULL; + } +} + +CrashHandler* CrashHandler::get() { + return crashHandlerInstance; +} diff --git a/src/CrashHandler.h b/src/CrashHandler.h new file mode 100644 index 000000000..88920ce03 --- /dev/null +++ b/src/CrashHandler.h @@ -0,0 +1,25 @@ +/* + OpenLieroX CrashHandler + + registers a crash handler in the OS and handles the crashes + + code under LGPL + created 09-07-2008 by Albert Zeyer +*/ + +#ifndef __CRASHHANDLER_H__ +#define __CRASHHANDLER_H__ + +class CrashHandler { +public: + virtual ~CrashHandler() {} + static void init(); + static void uninit(); + static CrashHandler* get(); + + // you can temporarly disable it (and then enable it again) + virtual void disable() {} + virtual void enable() {} +}; + +#endif diff --git a/src/Debug.cpp b/src/Debug.cpp new file mode 100644 index 000000000..2c3a7b4f6 --- /dev/null +++ b/src/Debug.cpp @@ -0,0 +1,584 @@ +/* + * Debug.cpp + * OpenLieroX + * + * Created by Albert Zeyer on 01.01.09. + * code under LGPL + * + */ + +#include "Debug.h" +#include "StringUtils.h" +#include "CrashHandler.h" + + +#include + +#ifdef WIN32 + +void RaiseDebugger() { +#ifdef DEBUG + // HINT: ignored when not in debugger + // If it just does nothing then, remove the surrounding #ifdef DEBUG + // I read about a Win32's IsDebuggerPresent() function, perhaps you should use that one here. + __asm { int 3 }; +#endif +} + +#else + +#if defined(__APPLE__) + +#include +#include +#include +#include +#include + +// Based on Apple's recommended method as described in +// http://developer.apple.com/qa/qa2004/qa1361.html +static bool AmIBeingDebugged() + // Returns true if the current process is being debugged (either + // running under the debugger or has a debugger attached post facto). +{ + // Initialize mib, which tells sysctl what info we want. In this case, + // we're looking for information about a specific process ID. + int mib[] = + { + CTL_KERN, + KERN_PROC, + KERN_PROC_PID, + getpid() + }; + + // Caution: struct kinfo_proc is marked __APPLE_API_UNSTABLE. The source and + // binary interfaces may change. + struct kinfo_proc info; + size_t info_size = sizeof ( info ); + + int sysctl_result = sysctl ( mib, sizeof(mib) / sizeof(*mib), &info, &info_size, NULL, 0 ); + if ( sysctl_result != 0 ) + return false; + + // This process is being debugged if the P_TRACED flag is set. + return ( info.kp_proc.p_flag & P_TRACED ) != 0; +} + +#else + +#include +#include +#include +#include +#include + + +static bool AmIBeingDebugged() { + // We can look in /proc/self/status for TracerPid. We are likely used in crash + // handling, so we are careful not to use the heap or have side effects. + int status_fd = open("/proc/self/status", O_RDONLY); + if (status_fd == -1) + return false; + + // We assume our line will be in the first 1024 characters and that we can + // read this much all at once. In practice this will generally be true. + // This simplifies and speeds up things considerably. + char buf[1024]; + + ssize_t num_read = read(status_fd, buf, sizeof(buf)); + fix_markend(buf); + close(status_fd); + if (num_read <= 0) return false; + + const char* searchStr = "TracerPid:\t"; + const char* f = strstr(buf, searchStr); + if(f == NULL) return false; + + // Our pid is 0 without a debugger, assume this for any pid starting with 0. + f += strlen(searchStr); + return f < &buf[num_read] && *f != '0'; +} + +#endif // OSX/LINUX + +#include + +void RaiseDebugger() { + if(AmIBeingDebugged()) { + printf("I am being debugged, raising debugger ...\n"); + CrashHandler::get()->disable(); + // TODO: We need a way to set another ucontext here. (And that should be specified via a parameter + // to RaiseDebugger().) E.g. when we use this function in the debugger thread, we want to set the + // ucontext of the main loop thread. + raise(SIGABRT); + CrashHandler::get()->enable(); + } else + printf("I am not being debugged, ignoring debugger raise.\n"); +} + +#endif + + +#ifdef WIN32 + +#include "AuxLib.h" // for Windows.h + +#include +#include + +#include "LieroX.h" +#include "CClient.h" +#include "CServer.h" +#include "DedicatedControl.h" +#include "StringUtils.h" +#include "ConversationLogger.h" +#include "CGameMode.h" + +#define itoa _itoa + +void *ReadGameStateForReport(char *buffer, size_t bufsize) +{ + memset(buffer, 0, bufsize); + __try { + if (cClient) { + strncat(buffer, "Game state:\n", bufsize); + if (cClient->getStatus() == NET_CONNECTED) { + if (cClient->getGameReady()) + strncat(buffer, "In game, selecting weapons.", bufsize); + else + strncat(buffer, "In lobby.", bufsize); + } else if (cClient->getStatus() == NET_PLAYING) { + strncat(buffer, "In game, playing.", bufsize); + } else if (cClient->getStatus() == NET_CONNECTING) { + strncat(buffer, "Connecting to a server.", bufsize); + } else if (cClient->getStatus() == NET_DISCONNECTED) { + strncat(buffer, "Disconnected.\n", bufsize); + } else { + strncat(buffer, "Unknown state.\n", bufsize); + } + } + buffer[bufsize - 1] = '\0'; + } __except (EXCEPTION_EXECUTE_HANDLER) + { return buffer; } + + return buffer; +} + +void *ReadGameInfoForReport(char *buffer, size_t bufsize) +{ + memset(buffer, 0, bufsize); + if (!tLXOptions || !tLX) + return buffer; + char tmp[32]; + __try { + + // Game type + strncat(buffer, "iGameType = ", bufsize); + switch (tLX->iGameType) { + case GME_LOCAL: + strncat(buffer, "GME_LOCAL", bufsize); + break; + case GME_HOST: + strncat(buffer, "GME_HOST", bufsize); + break; + case GME_JOIN: + strncat(buffer, "GME_JOIN", bufsize); + break; + default: + itoa(tLX->iGameType, tmp, 10); + fix_markend(tmp); + strncat(buffer, "UNKNOWN ", bufsize); strncat(buffer, tmp, bufsize); + } + strncat(buffer, "\n", bufsize); + + // Game mode + strncat(buffer, "GameMode = ", bufsize); + char tmp[16]; + itoa(tLXOptions->tGameInfo.gameMode->GeneralGameType(), tmp, 10); + fix_markend(tmp); + strncat(buffer, tmp, bufsize); + strncat(buffer, "\n", bufsize); + + // Mod name + strncat(buffer, "sModName = ", bufsize); + if (tLXOptions->tGameInfo.sModName.size()) + strncat(buffer, tLXOptions->tGameInfo.sModName.c_str(), bufsize); + strncat(buffer, "\n", bufsize); + + // Map file + strncat(buffer, "sMapFile = ", bufsize); + if (tLXOptions->tGameInfo.sMapFile.size()) + strncat(buffer, tLXOptions->tGameInfo.sMapFile.c_str(), bufsize); + strncat(buffer, "\n", bufsize); + + // Map name + strncat(buffer, "sMapName = ", bufsize); + if (tLXOptions->tGameInfo.sMapName.size()) + strncat(buffer, tLXOptions->tGameInfo.sMapName.c_str(), bufsize); + strncat(buffer, "\n", bufsize); + + // Mod dir + strncat(buffer, "sModDir = ", bufsize); + if (tLXOptions->tGameInfo.sModDir.size()) + strncat(buffer, tLXOptions->tGameInfo.sModDir.c_str(), bufsize); + strncat(buffer, "\n", bufsize); + + // Loading time + itoa(tLXOptions->tGameInfo.iLoadingTime, tmp, 10); + fix_markend(tmp); + strncat(buffer, "iLoadingTimes = ", bufsize); + strncat(buffer, tmp, bufsize); + strncat(buffer, "\n", bufsize); + + // Server name + strncat(buffer, "sServerName = ", bufsize); + if (tLXOptions->sServerName.size()) + strncat(buffer, tLXOptions->sServerName.c_str(), bufsize); + strncat(buffer, "\n", bufsize); + + // Welcome message + strncat(buffer, "sWelcomeMessage = ", bufsize); + if (tLXOptions->sWelcomeMessage.size()) + strncat(buffer, tLXOptions->sWelcomeMessage.c_str(), bufsize); + strncat(buffer, "\n", bufsize); + + // Lives + itoa(tLXOptions->tGameInfo.iLives, tmp, 10); + fix_markend(tmp); + strncat(buffer, "iLives = ", bufsize); + strncat(buffer, tmp, bufsize); + strncat(buffer, "\n", bufsize); + + // Max kills + itoa(tLXOptions->tGameInfo.iKillLimit, tmp, 10); + fix_markend(tmp); + strncat(buffer, "iKillLimit = ", bufsize); + strncat(buffer, tmp, bufsize); + strncat(buffer, "\n", bufsize); + + // Time limit + itoa((int)(tLXOptions->tGameInfo.fTimeLimit * 10), tmp, 10); + fix_markend(tmp); + strncat(buffer, "fTimeLimit = ", bufsize); + strncat(buffer, tmp, bufsize); + strncat(buffer, "\n", bufsize); + + // Bonuses on + strncat(buffer, "bBonusesOn = ", bufsize); + strncat(buffer, tLXOptions->tGameInfo.bBonusesOn ? "true" : "false", bufsize); + strncat(buffer, "\n", bufsize); + + // Bonus names + strncat(buffer, "bShowBonusName = ", bufsize); + strncat(buffer, tLXOptions->tGameInfo.bShowBonusName ? "true" : "false", bufsize); + strncat(buffer, "\n", bufsize); + + // Number of players + if (cServer) { + itoa(cServer->getNumPlayers(), tmp, 10); + fix_markend(tmp); + strncat(buffer, "iNumPlayers = ", bufsize); + strncat(buffer, tmp, bufsize); + strncat(buffer, "\n", bufsize); + } + + buffer[bufsize - 1] = '\0'; + } __except (EXCEPTION_EXECUTE_HANDLER) { + return buffer; + } + return buffer; +} + +// This function also used in CrashHandler.cpp +void OlxWriteCoreDump_Win32(const char* fileName, PEXCEPTION_POINTERS pExInfo ) +{ + // MSVC-compatible core dump, GDB cannot read it :( + // Set the exception info for the minidump + MINIDUMP_EXCEPTION_INFORMATION eInfo; + eInfo.ThreadId = GetCurrentThreadId(); + eInfo.ExceptionPointers = pExInfo; + eInfo.ClientPointers = FALSE; + + // Set the minidump info + MINIDUMP_CALLBACK_INFORMATION cbMiniDump; + cbMiniDump.CallbackRoutine = NULL; + cbMiniDump.CallbackParam = 0; + + // Additional data + MINIDUMP_USER_STREAM pExtraInfo[3]; + + // Version info + char version[64]; + strcpy(version, GetFullGameName()); + pExtraInfo[0].Type = LastReservedStream + 1; + pExtraInfo[0].BufferSize = sizeof(version); + pExtraInfo[0].Buffer = (void *)&version[0]; + + // Current game info + char game_info[1024]; + pExtraInfo[1].Type = LastReservedStream + 2; + pExtraInfo[1].BufferSize = sizeof(game_info); + pExtraInfo[1].Buffer = ReadGameInfoForReport(game_info, sizeof(game_info)); + + // Current game state + char game_state[1024]; + pExtraInfo[2].Type = LastReservedStream + 3; + pExtraInfo[2].BufferSize = sizeof(game_state); + pExtraInfo[2].Buffer = ReadGameStateForReport(game_state, sizeof(game_state)); + + MINIDUMP_USER_STREAM_INFORMATION iStreams; + iStreams.UserStreamCount = sizeof(pExtraInfo)/sizeof(MINIDUMP_USER_STREAM); + iStreams.UserStreamArray = pExtraInfo; + + // Open the file + HANDLE hFile = CreateFile((LPCSTR)fileName,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); + + // Write the minidump + if (hFile) { + MINIDUMP_TYPE type = (MINIDUMP_TYPE)(MiniDumpScanMemory | MiniDumpWithIndirectlyReferencedMemory); + MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, type, &eInfo,&iStreams,&cbMiniDump); + } + + // Close the file + CloseHandle(hFile); +} + +void OlxWriteCoreDump(const char* fileName) +{ + OlxWriteCoreDump_Win32(fileName, NULL); +} + +#else + +#ifdef GCOREDUMPER +#include +#endif +#include +#include +#include +#include +#include + +#ifndef GCOREDUMPER +static void GdbWriteCoreDump(const char* fname) { + // WARNING: this is terribly slow like this + char gdbparam[1000]; + sprintf(gdbparam, + "attach %i \n" + "gcore %s \n" + "detach \n" + "quit \n", + getpid(), fname); + FILE* p = popen("gdb -q", "w"); + if(p) { + fprintf(p, "%s", gdbparam); + fflush(p); + int status = 0; wait(&status); + pclose(p); + } +} +#endif + +void OlxWriteCoreDump(const char* file_postfix) { + char corefile[PATH_MAX + 100]; + if(getcwd(corefile, PATH_MAX) == NULL) strcpy(corefile, ""); + strcat(corefile, "/core.OpenLieroX"); + if(file_postfix) { strcat(corefile, "."); strcat(corefile, file_postfix); } + printf("writing coredump to %s\n", corefile); + + printf("dumping core ... "); fflush(0); +#ifdef GCOREDUMPER + WriteCoreDump(corefile); +#else + GdbWriteCoreDump(corefile); +#endif + printf("ready\n"); +} + +#endif + +// ----------------- core dump code end ------------- + + +// --------------- backtrace stuff start -------------- + +#ifndef HAVE_EXECINFO +# if defined(__linux__) +# define HAVE_EXECINFO 1 +# elif defined(__DARWIN_VERS_1050) +# define HAVE_EXECINFO 1 +# else +# define HAVE_EXECINFO 0 +# endif +#endif + +#if HAVE_EXECINFO + +#include +#include +#include + +void DumpCallstackPrintf(void* callpnt) { + void *callstack[128]; + int framesC = backtrace(callstack, sizeof(callstack)); + printf("backtrace() returned %d addresses\n", framesC); + if(callpnt != NULL && framesC > 3) callstack[3] = callpnt; // expected to be called from signal handler + char** strs = backtrace_symbols(callstack, framesC); + for(int i = 0; i < framesC; ++i) { + if(strs[i]) + printf("%s\n", strs[i]); + else + break; + } + free(strs); +} + +void DumpCallstack(void (*PrintOutFct) (const std::string&)) { + void *callstack[128]; + int framesC = backtrace(callstack, sizeof(callstack)); + (*PrintOutFct) ("DumpCallstack: " + itoa(framesC) + " addresses:"); + char** strs = backtrace_symbols(callstack, framesC); + for(int i = 0; i < framesC; ++i) { + if(strs[i]) + (*PrintOutFct) (std::string(" ") + strs[i] + "\n"); + else + break; + } + free(strs); +} + +#elif defined(WIN32) + +#include "StackWalker.h" // Call Luke Stackwalker for help + +typedef void (*PrintOutFct) (const std::string&); + +// Override the default stackwalker with our own print functions +class PrintStackWalker : public StackWalker { +private: + PrintOutFct m_print; + +public: + PrintStackWalker(PrintOutFct fct = NULL) : StackWalker(RetrieveVerbose) { m_print = fct; } + void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion) + { + + } + + void OnOutput(LPCSTR szText) + { + if (m_print == NULL) + printf(szText); + else + m_print(std::string(szText)); + StackWalker::OnOutput(szText); + } +}; + +void DumpCallstackPrintf(void* callpnt) +{ + PrintStackWalker sw; + sw.ShowCallstack(); + +} +void DumpCallstack(void (*LineOutFct) (const std::string&)) +{ + PrintStackWalker sw(LineOutFct); + sw.ShowCallstack(); +} + +#else + +#warning No DumpCallstack implementation for this arch/sys + +void DumpCallstackPrintf(void* callpnt) { + printf("DumpCallstackPrintf not implemented\n"); +} + +void DumpCallstack(void (*PrintOutFct) (const std::string&)) { + printf("DumpCallstack not implemented\n"); +} + +#endif + +std::string GetLogTimeStamp() +{ + // TODO: please recode this, don't use C-strings! + char buf[64]; + const time_t unif_time = time(NULL); + struct tm *t = localtime(&unif_time); + if (t == NULL) + return ""; + + strftime(buf, sizeof(buf), "[%H:%M:%S] ", t); + fix_markend(buf); + return std::string(buf); +} + +Logger notes(0,2,1000, "n: "); +Logger hints(0,1,100, "H: "); +Logger warnings(0,0,10, "W: "); +Logger errors(-1,-1,1, "E: "); + +#include +#include +#include "ThreadPool.h" +#include "StringUtils.h" + +static SDL_mutex* globalCoutMutex = NULL; + +Logger::Logger(int o, int ingame, int callst, const std::string& p) +: minCoutVerb(o), minIngameConVerb(ingame), minCallstackVerb(callst), prefix(p), lastWasNewline(true), mutex(NULL) { + mutex = SDL_CreateMutex(); + if(!globalCoutMutex) + globalCoutMutex = SDL_CreateMutex(); +} + +Logger::~Logger() { + SDL_DestroyMutex(mutex); mutex = NULL; + if(globalCoutMutex) { + SDL_DestroyMutex(globalCoutMutex); + globalCoutMutex = NULL; + } +} + +void Logger::lock() { + SDL_mutexP(mutex); +} + +void Logger::unlock() { + SDL_mutexV(mutex); +} + +static void CoutPrint(const std::string& str) { + // TODO: We have used std::cout here before but it doesn't seem to work after a while for some reason. + printf("%s", str.c_str()); +} + +int Logger_Verbosity = 0; + +// true if last was newline +static bool logger_output(Logger& log, const std::string& buf) { + bool ret = true; + + std::string prefix = log.prefix; + + if(Logger_Verbosity >= log.minCoutVerb) { + SDL_mutexP(globalCoutMutex); + ret = PrettyPrint(prefix, buf, CoutPrint, log.lastWasNewline); + //std::cout.flush(); + SDL_mutexV(globalCoutMutex); + } + if(Logger_Verbosity >= log.minCallstackVerb) { + DumpCallstackPrintf(); + } + return ret; +} + +Logger& Logger::flush() { + lock(); + lastWasNewline = logger_output(*this, buffer); + buffer = ""; + unlock(); + return *this; +} diff --git a/src/Debug.h b/src/Debug.h new file mode 100644 index 000000000..d48c4f5b1 --- /dev/null +++ b/src/Debug.h @@ -0,0 +1,76 @@ +/* + * Debug.h + * OpenLieroX + * + * Created by Albert Zeyer on 01.01.09. + * code under LGPL + * + */ + +#ifndef __OLXDEBUG_H__ +#define __OLXDEBUG_H__ + +#include +#include +#include "StringUtils.h" + +// { these function should be safe to be called from everywhere, also from signalhandlers +void RaiseDebugger(); // if run in a debugger, it should raise it; if not, it should do nothing +void OlxWriteCoreDump(const char* file_postfix = NULL); +void DumpCallstackPrintf(void* callpnt = NULL); +// } + + +void DumpCallstack(void (*PrintOutFct) (const std::string&)); + +struct SDL_mutex; + +struct Logger { + int minCoutVerb; + int minIngameConVerb; + int minCallstackVerb; + std::string prefix; + std::string buffer; + bool lastWasNewline; + SDL_mutex* mutex; + + Logger(int o, int ingame, int callst, const std::string& p); + ~Logger(); + void lock(); void unlock(); + + struct LockedStreamWrapper { + Logger* logger; + LockedStreamWrapper(Logger* l) : logger(l) {} + LockedStreamWrapper(const LockedStreamWrapper& l) : logger(l.logger) { ((LockedStreamWrapper&)l).logger = NULL; } + ~LockedStreamWrapper() { if(logger) logger->unlock(); } + Logger* push_back() { Logger* tmp = logger; logger = NULL; return tmp; } + Logger* push_back_and_unlock() { Logger* tmp = push_back(); tmp->unlock(); return tmp; } + + LockedStreamWrapper& operator<<(const std::string& msg) { logger->buffer += msg; return *this; } + template LockedStreamWrapper& operator<<(_T v) { return operator<<(to_string(v)); } + Logger& operator<<(Logger& (*__pf)(Logger&)) { return (*__pf)(*push_back_and_unlock()); } + Logger& flush() { return push_back_and_unlock()->flush(); } + }; + + LockedStreamWrapper operator<<(const std::string& msg) { lock(); buffer += msg; return LockedStreamWrapper(this); } + Logger& operator<<(Logger& (*__pf)(Logger&)) { return (*__pf)(*this); } + template LockedStreamWrapper operator<<(_T v) { return operator<<(to_string(v)); } + Logger& flush(); + + // deprecated, only for easier find/replace with printf + void operator()(const std::string& str) { (*this) << str; flush(); } +}; + +inline Logger& endl(Logger& __os) { return (__os << "\n").flush(); } +inline Logger& flush(Logger& __os) { return __os.flush(); } + +template< Logger& l > +void printOnLogger(const std::string& str) { l << str; } + + +extern Logger notes; +extern Logger hints; +extern Logger warnings; +extern Logger errors; + +#endif diff --git a/src/Event.h b/src/Event.h new file mode 100644 index 000000000..41deed29e --- /dev/null +++ b/src/Event.h @@ -0,0 +1,143 @@ +/* + OpenLieroX + + event class + + created on 27-05-2008 by Albert Zeyer + code under LGPL +*/ + +#ifndef __EVENT_H__ +#define __EVENT_H__ + +#include +#include +#include "Ref.h" +#include "SmartPointer.h" +#include "EventQueue.h" +#include "Utils.h" // for isSameType + +struct EventData { + EventData(void* own = NULL) : owner(own) {} + + void* owner; +}; + + +class _Event {}; + +/* + This is an Event class, which represents a possible event. + It handles all the event handlers. + + _Data should provide at least an owner field like EventData +*/ +template< typename _Data = EventData > +class Event : public _Event { +public: + class Handler { + public: + typedef _Data Data; + virtual ~Handler() {} + virtual void operator()(_Data data) = 0; + virtual bool operator==(const Handler& hndl) = 0; + virtual Handler* copy() const = 0; + }; + + typedef std::list< Ref > HandlerList; + +protected: + class HandlerAccessor { + private: + Event* base; + public: + HandlerAccessor(Event* b) : base(b) {} + HandlerAccessor& operator=(const Ref& h) { base->m_handlers.clear(); if(h.isSet()) base->m_handlers.push_back(h); return *this; } + HandlerAccessor& operator+=(const Ref& h) { if(h.isSet()) base->m_handlers.push_back(h); return *this; } + HandlerAccessor& operator-=(const Ref& h) { + for(typename Event::HandlerList::iterator i = base->m_handlers.begin(); i != base->m_handlers.end(); ++i) + if(i->get() == h.get()) { + base->m_handlers.erase(i); + break; + } + return *this; + } + + const typename Event::HandlerList& get() { return base->m_handlers; } + }; + +private: + friend class HandlerAccessor; + HandlerList m_handlers; + +public: + Event() {} + ~Event() { if (mainQueue) mainQueue->removeCustomEvents(this); } + Event(const Event& e) { (*this) = e; } + Event& operator=(const Event& e) { m_handlers = e.m_handlers; return *this; } + HandlerAccessor handler() { return HandlerAccessor(this); } + + void pushToMainQueue(_Data data) { if(mainQueue) mainQueue->push(new EventThrower<_Data>(this, data)); } + + void occurred(_Data data) { + callHandlers(m_handlers, data); + } + static void callHandlers(HandlerList& handlers, _Data data) { + for(typename HandlerList::iterator i = handlers.begin(); i != handlers.end(); ++i) + i->get()(data); + } +}; + + +template< typename _Base, typename _Data = EventData > +class MemberFunction : public Event<_Data>::Handler { +public: + typedef void (_Base::*Function) (_Data data); +private: + _Base* m_obj; + Function m_fct; +public: + MemberFunction(_Base* obj, Function fct) : m_obj(obj), m_fct(fct) {} + MemberFunction(const MemberFunction& other) : m_obj(other.m_obj), m_fct(other.m_fct) {} + + virtual void operator()(_Data data) { (*m_obj.*m_fct)(data); } + virtual bool operator==(const typename Event<_Data>::Handler& hndl) { + const MemberFunction* hPtr = dynamic_cast(&hndl); + if(hPtr == NULL) return false; + return hPtr->m_obj == m_obj && hPtr->m_fct == m_fct; + } + virtual typename Event<_Data>::Handler* copy() const { return new MemberFunction(m_obj, m_fct); } +}; + + +template< typename _Data = EventData > +class StaticFunction : public Event<_Data>::Handler { +public: + typedef void (*Function) (_Data data); +private: + Function m_fct; +public: + StaticFunction(Function fct) : m_fct(fct) {} + StaticFunction(const StaticFunction& other) : m_fct(other.m_fct) {} + + virtual void operator()(_Data data) { (m_fct)(data); } + virtual bool operator==(const typename Event<_Data>::Handler& hndl) { + const StaticFunction* hPtr = dynamic_cast(&hndl); + if(hPtr == NULL) return false; + return hPtr->m_fct == m_fct; + } + virtual typename Event<_Data>::Handler* copy() const { return new StaticFunction(m_fct); } +}; + + +template< typename _Base, typename _Data > +Ref::Handler> getEventHandler( _Base* obj, void (_Base::*fct) (_Data data) ) { + return new MemberFunction<_Base,_Data>( obj, fct ); +} + +template< typename _Data > +Ref::Handler> getEventHandler( void (*fct) (_Data data) ) { + return new StaticFunction<_Data>( fct ); +} + +#endif diff --git a/src/EventQueue.h b/src/EventQueue.h new file mode 100644 index 000000000..c94e89aaa --- /dev/null +++ b/src/EventQueue.h @@ -0,0 +1,101 @@ +///////////////////////////////////////// +// +// OpenLieroX +// +// event queue +// +// based on the work of JasonB +// enhanced by Dark Charlie and Albert Zeyer +// +// code under LGPL +// +///////////////////////////////////////// + +#ifndef __EVENTQUEUE_H__ +#define __EVENTQUEUE_H__ + +#include +#include "ThreadPool.h" // for Action + +enum SDLUserEvent { + UE_CustomEventHandler = 0, + UE_QuitEventThread = 1, + UE_DoVideoFrame = 2, + UE_DoSetVideoMode = 3, + UE_DoActionInMainThread = 4 +}; + + +// bDedicated must be set before we can call this +void InitEventQueue(); +void ShutdownEventQueue(); + + + +union SDL_Event; +typedef SDL_Event EventItem; // for now, we can change that later + +class _Event; +template< typename _Data > class Event; + +class CustomEventHandler : public Action { +public: + virtual int handle() = 0; + virtual const _Event* owner() const = 0; + virtual CustomEventHandler* copy(_Event* newOwner = NULL) const = 0; + virtual ~CustomEventHandler() {} +}; + +template< typename _Data > +class EventThrower : public CustomEventHandler { +public: + Event<_Data>* m_event; + _Data m_data; + EventThrower(Event<_Data>* e, _Data d) : m_event(e), m_data(d) {} + virtual int handle() { + m_event->occurred( m_data ); + return 0; + } + virtual const _Event* owner() const { return m_event; } + virtual CustomEventHandler* copy(_Event* newOwner) const { + EventThrower* th = new EventThrower(*this); + if(newOwner) th->m_event = (Event<_Data>*) newOwner; + return th; + } +}; + + +struct EventQueueIntern; + +class EventQueue { +private: + EventQueueIntern* data; +public: + EventQueue(); + ~EventQueue(); + + // Polls for currently pending events. + bool poll(EventItem& e); + + // Waits indefinitely for the next available event. + bool wait(EventItem& e); + + /* Add an event to the event queue. + * This function returns true on success + * or false if there was some error. + */ + bool push(const EventItem& e); + bool push(Action* eh); + + // goes through all CustomEventHandler and copies them if oldOwner is matching + void copyCustomEvents(const _Event* oldOwner, _Event* newOwner); + + // removes all CustomEventHandler with owner + void removeCustomEvents(const _Event* owner); +}; + +extern EventQueue* mainQueue; + + + +#endif // __EVENTQUEUE_H__ diff --git a/src/FindFile.h b/src/FindFile.h new file mode 100644 index 000000000..23d3e6532 --- /dev/null +++ b/src/FindFile.h @@ -0,0 +1,496 @@ +///////////////////////////////////////// +// +// OpenLieroX +// +// Auxiliary Software class library +// +// work by JasonB +// code under LGPL +// enhanced by Dark Charlie and Albert Zeyer +// +///////////////////////////////////////// + + +// File finding routines +// Created 30/9/01 +// By Jason Boettcher + +// TODO: rename this file + +#ifndef __FINDFILE_H__ +#define __FINDFILE_H__ + +#include +#include +#include +#include +#include +#include "Unicode.h" +#include "Debug.h" +#include "Mutex.h" +#include "Iterator.h" +#include "RefCounter.h" +#include "Event.h" +#include "StringUtils.h" + +#ifndef WIN32 +# include +# include +#endif + +// file input/output +#include +#include + +#ifdef WIN32 +# include +# include +# include + // wrappers to provide the standards + inline int mkdir(const char *path, int mode) { return _mkdir(Utf8ToSystemNative(path).c_str()); } +# define stat _stat +#ifndef S_ISREG +# define S_IFLNK 0120000 +inline bool S_ISREG(unsigned short s) { return (s & S_IFREG) != 0; } +inline bool S_ISDIR(unsigned short d) { return (d & S_IFDIR) != 0; } +inline bool S_ISLNK(unsigned short d) { return (d & S_IFLNK) != 0; } +#endif +#endif + + +#ifndef SYSTEM_DATA_DIR +# define SYSTEM_DATA_DIR "/usr/share" +#endif + +extern std::string binary_dir; + +// +// Drive types +// + +// Windows +#ifdef WIN32 +# define DRV_UNKNOWN DRIVE_UNKNOWN // The drive is unknown +# define DRV_NO_ROOT_DIR DRIVE_NO_ROOT_DIR // The root path is invalid; for example, there is no volume is mounted at the path. +# define DRV_REMOVABLE DRIVE_REMOVABLE // The drive has removable media; for example, a floppy drive or flash card reader. +# define DRV_FIXED DRIVE_FIXED // The drive has fixed media; for example, a hard drive, flash drive, or thumb drive. +# define DRV_REMOTE DRIVE_REMOTE // The drive is a remote (network) drive. +# define DRV_CDROM DRIVE_CDROM // The drive is a CD-ROM drive. +# define DRV_RAMDISK DRIVE_RAMDISK // The drive is a RAM disk. +#endif + + +class drive_t { public: + std::string name; + unsigned int type; +}; + +typedef std::vector drive_list; + +// Define intptr_t if not defined +#ifdef _MSC_VER +#ifndef _INTPTR_T_DEFINED +typedef long intptr_t; +#endif +#endif + +typedef std::vector searchpathlist; +extern searchpathlist tSearchPaths; + +void AddToFileList(searchpathlist* l, const std::string& f); +bool FileListIncludesExact(const searchpathlist* l, const std::string& f); + +void initSpecialSearchPathForTheme(); +const std::string* getSpecialSearchPathForTheme(); + +// this replaces ${var} in filename with concrete values +// currently, the following variables are handled: +// ${HOME} - the home-dir, that means under unix ~ and under windows the 'my-documents' +// ${BIN} - the dir of the executable-binary +// ${SYSTEM_DATA} - data-dir of the system, that means usually /usr/share +void ReplaceFileVariables(std::string& filename); + +drive_list GetDrives(); + +// This function converts relative paths to absolute paths +std::string GetAbsolutePath(const std::string& path); + +#ifndef WIN32 + +// mostly all system but Windows use case sensitive file systems +// this game uses also filenames ignoring the case sensitivity +// this function gives the case sensitive right name of a file +// also, it replaces ${var} in the searchname +// returns false if no success, true else +bool GetExactFileName(const std::string& abs_searchname, std::string& filename); + +#else // WIN32 + +// we don't have case sensitive file systems under windows +// but we still need to replace ${var} in the searchname +// returns true, if file/dir is existing and accessable, false else + +inline bool GetExactFileName(const std::string& abs_searchname, std::string& filename) { + filename = abs_searchname; + + if(abs_searchname.size() == 0) { + return true; + } + + ReplaceFileVariables(filename); + + // Remove the ending slash, else stat will fail + if (filename[filename.length()-1]== '/' || filename[filename.length()-1]== '\\') + // Don't remove, if this is a root directory, else stat will fail (really crazy) +#ifdef WIN32 + if (filename[filename.length()-2] != ':') +#endif + filename.erase(filename.length()-1); + + struct stat finfo; + + if(stat(Utf8ToSystemNative(filename).c_str(), &finfo) != 0) { + // problems stating file + return false; + } + + // we got some info, so there is something ... + return true; +} +#endif + + + +extern searchpathlist basesearchpaths; +void InitBaseSearchPaths(); + +// this does a search on all searchpaths for the file and returns the first one found +// if none was found, NULL will be returned +// if searchpath!=NULL, it will place there the searchpath +std::string GetFullFileName(const std::string& path, std::string* searchpath = NULL); + +// this give always a dir like searchpath[0]/path, but it ensures: +// - the filename is correct, if the file exists +// - it replaces ${var} with ReplaceFileVariables +// if create_nes_dirs is set, the nessecary dirs will be created +std::string GetWriteFullFileName(const std::string& path, bool create_nes_dirs = false); + +// replacement for the simple fopen +// this does a search on all searchpaths for the file and opens the first one; if none was found, NULL will be returned +// related to tSearchPaths +FILE* OpenGameFile(const std::string& path, const char *mode); + +FILE* OpenAbsFile(const std::string& path, const char *mode); + +std::ifstream* OpenGameFileR(const std::string& path); + +std::string GetFileContents(const std::string& path, bool absolute = false); +std::string ExtractDirectory(const std::string& path); +std::string JoinPaths(const std::string& path1, const std::string& path2); + +std::string GetScriptInterpreterCommandForFile(const std::string& filename); + + +bool IsFileAvailable(const std::string& f, bool absolute = false); + +// the dir will be created recursivly +// IMPORTANT: filename is absolute; no game-path! +void CreateRecDir(const std::string& abs_filename, bool last_is_dir = true); + +bool EqualPaths(const std::string& path1, const std::string& path2); + +// Returns true if the path is absolute +bool IsAbsolutePath(const std::string& path); + +// copy the src-file to the dest +// it will simply fopen(src, "r"), fopen(dest, "w") and write all the stuff +// IMPORTANT: filenames are absolute; no game-path! +bool FileCopy(const std::string& src, const std::string& dest); + +// returns true, if we can write to the dir +bool CanWriteToDir(const std::string& dir); + +size_t FileSize(const std::string& path); + +// returns the home-directory (used by ReplaceFileVariables) +std::string GetHomeDir(); +// returns the system-data-dir (under Linux, usually /usr/share) +std::string GetSystemDataDir(); +// returns the dir of the executable-binary +std::string GetBinaryDir(); +// returns the temp-dir of the system +std::string GetTempDir(); + + +typedef char filemodes_t; +enum { + FM_DIR = 1, + FM_REG = 2, + FM_LNK = 4, +}; + +bool PathListIncludes(const std::list& list, const std::string& path); + +// _handler has to be a functor with +// bool op() ( const std::string& path ) +// ending pathsep is ensured if needed +// if return is false, it will break +// HINT: it does no GetExactFileName with the paths +template +void ForEachSearchpath(_handler& handler) { + std::list handled_dirs; + std::string path; + searchpathlist::const_iterator i; + + { + const std::string* themeDir = getSpecialSearchPathForTheme(); + if(themeDir) { + if(!handler(*themeDir + "/")) return; + handled_dirs.push_back(*themeDir); + } + } + + for( + i = tSearchPaths.begin(); + i != tSearchPaths.end(); i++) { + path = *i; + if(!PathListIncludes(handled_dirs, path)) { + if(!handler(path + "/")) return; + handled_dirs.push_back(path); + } + } + + for( + i = basesearchpaths.begin(); + i != basesearchpaths.end(); i++) { + if(!FileListIncludesExact(&tSearchPaths, *i)) { + path = *i; + if(!PathListIncludes(handled_dirs, path)) { + if(!handler(path + "/")) return; + handled_dirs.push_back(path); + } + } + } +} + + +// functor for ForEachSearchpath, used by FindFiles +// it will search a subdir of a given searchpath for files +template +class FindFilesHandler { +public: + const std::string& dir; + const std::string& namefilter; + const filemodes_t modefilter; + _filehandler& filehandler; + + FindFilesHandler( + const std::string& dir_, + const std::string& namefilter_, + const filemodes_t modefilter_, + _filehandler& filehandler_) : + dir(dir_), + namefilter(namefilter_), + modefilter(modefilter_), + filehandler(filehandler_) {} + + bool operator() (const std::string& path) { + std::string abs_path = path; + if(!GetExactFileName(path + dir, abs_path)) return true; + bool ret = true; + +#ifdef WIN32 // uses UTF16 + struct _finddata_t fileinfo; + abs_path.append("/"); + intptr_t handle = _findfirst(Utf8ToSystemNative(abs_path + "*").c_str(), &fileinfo); + while(handle > 0) { + //If file is not self-directory or parent-directory + if(fileinfo.name[0] != '.' || (fileinfo.name[1] != '\0' && (fileinfo.name[1] != '.' || fileinfo.name[2] != '\0'))) { + if((!(fileinfo.attrib&_A_SUBDIR) && modefilter&FM_REG) + || fileinfo.attrib&_A_SUBDIR && modefilter&FM_DIR) + if(!filehandler(abs_path + SystemNativeToUtf8(fileinfo.name))) { + ret = false; + break; + } + } + + if(_findnext(handle,&fileinfo)) + break; + } + + _findclose(handle); +#else /* not WIN32 */ + + std::string filename; + dirent* entry; + struct stat s; + DIR* handle = opendir(abs_path.c_str()); + if(!handle) return ret; + while((entry = readdir(handle)) != 0) { + //If file is not self-directory or parent-directory + if(entry->d_name[0] != '.' || (entry->d_name[1] != '\0' && (entry->d_name[1] != '.' || entry->d_name[2] != '\0'))) { + filename = abs_path + "/" + entry->d_name; + if(stat(filename.c_str(), &s) == 0) + if((S_ISREG(s.st_mode) && modefilter&FM_REG) + || (S_ISDIR(s.st_mode) && modefilter&FM_DIR) + || (S_ISLNK(s.st_mode) && modefilter&FM_LNK)) + if(!filehandler(filename)) { + ret = false; + break; + } + } + } + closedir(handle); +#endif /* WIN32 */ + return ret; + } +}; + +// FindFiles searches for files +// _handler has to be a functor with +// bool op()( const std::string& abs_filename ) +// if it returns false, it will break +template +void FindFiles( + _handler& handler, + const std::string& dir, + bool absolutePath = false, + const filemodes_t modefilter = -1, + const std::string& namefilter = "" +) { + if(namefilter != "*" && namefilter != "") + warnings << "FindFiles: filter " << namefilter <<" isn't handled yet" << endl; + if(absolutePath) + FindFilesHandler<_handler>(dir, namefilter, modefilter, handler) (""); + else { + FindFilesHandler<_handler> searchpathHandler(dir, namefilter, modefilter, handler); + ForEachSearchpath(searchpathHandler); + } +} + +template +struct GetFileList_FileListAdder { + _CheckFct& checkFct; + _List& filelist; + GetFileList_FileListAdder(_CheckFct& f, _List& l) : checkFct(f), filelist(l) {} + bool operator() (const std::string& path) { + checkFct(filelist, path); + return true; + } +}; + +template +void GetFileList( + _List& filelist, + _CheckFct& checkFct, + const std::string& dir, + bool absolutePath = false, + const filemodes_t modefilter = -1, + const std::string& namefilter = "") +{ + GetFileList_FileListAdder<_List,_CheckFct> adder(checkFct, filelist); + FindFiles(adder, dir, absolutePath, modefilter, namefilter); +} + + +class Command; +struct AutocompleteRequest; + +class FileListCacheIntf { +public: + typedef std::string Filename; + typedef std::string ObjectName; + typedef std::map FileList; +protected: + Mutex mutex; + FileList filelist; + bool isReady; // will be set true after an update and stays always true then +public: + const std::string name; + Event<> OnUpdateFinished; + + FileListCacheIntf(const std::string& n) : isReady(false), name(n) {} + virtual ~FileListCacheIntf() {} + + // this iterator locks the filelist as long as it exists + class Iterator : public ::Iterator, public RefCounter { + private: + FileList::iterator it; + FileListCacheIntf& filelist; + public: + Iterator(FileList::iterator _it, FileListCacheIntf& f) : it(_it), filelist(f) { + filelist.mutex.lock(); + } + ~Iterator() { RefCounter::uninit(); } + virtual void onLastRefRemoved() { + filelist.mutex.unlock(); + } + Iterator(const Iterator& it) : RefCounter(it), it(it.it), filelist(it.filelist) {} + virtual ::Iterator* copy() const { return new Iterator(*this); } + virtual bool isValid() { return it != filelist.filelist.end(); } + virtual void next() { ++it; } + virtual bool operator==(const ::Iterator& other) const { + const Iterator* o = dynamic_cast (&other); + return o && it == o->it; + } + virtual FileList::value_type get() { return *it; } + + typedef ::Iterator::Ref Ref; + }; + + Iterator::Ref begin() { return new Iterator(filelist.begin(), *this); } + void add(const FileList::value_type& o) { Mutex::ScopedLock lock(mutex); filelist.insert(o); } + bool includes(const Filename& fn) { Mutex::ScopedLock lock(mutex); return filelist.find(fn) != filelist.end(); } + bool autoComplete(AutocompleteRequest& request); + bool ready() { Mutex::ScopedLock lock(mutex); return isReady; } + virtual void update() = 0; // will be run in an own thread and should lock as short as possible (in best case only for the swap of the old/new list) +}; + +template // asume that _CheckFct will be static anyway - makes it a bit simpler - just change if needed +class FileListCache : public FileListCacheIntf { +protected: + const std::string dir; + const bool absolutePath; + const filemodes_t modefilter; + const std::string namefilter; +public: + // Note: slightly different default values from FindFiles (modefilter is FM_REG here) + FileListCache(const std::string& _name, + const std::string& _dir, + bool _absPath = false, + const filemodes_t _modefilter = FM_REG, + const std::string& _namefilter = "") + : FileListCacheIntf(_name), dir(_dir), absolutePath(_absPath), modefilter(_modefilter), namefilter(_namefilter) {} + + virtual void update() { + static _CheckFct fct; + FileList newList; + GetFileList(newList, fct, dir, absolutePath, modefilter, namefilter); + { + Mutex::ScopedLock lock(mutex); + filelist.swap(newList); + isReady = true; + } + OnUpdateFinished.pushToMainQueue(EventData(this)); + } +}; + + + +// File pointer to SDL RWops conversion +SDL_RWops *RWopsFromFP(FILE *fp, bool autoclose); + +// Platform-independent stat() - use S_ISREG( st.st_mode ) and S_ISDIR( st.st_mode ) on stat struct +inline bool StatFile( const std::string & file, struct stat * st ) +{ + std::string fname = GetFullFileName( file ); + std::string exactfname; + if( ! GetExactFileName( fname, exactfname ) ) + return false; + if( stat( Utf8ToSystemNative(fname).c_str(), st ) != 0 ) + return false; + + return true; +} + +#endif // __FINDFILE_H__ diff --git a/src/Functors.h b/src/Functors.h new file mode 100644 index 000000000..b4a940b1d --- /dev/null +++ b/src/Functors.h @@ -0,0 +1,43 @@ +/* + OpenLieroX + + various functors + + code under LGPL + created 01-05-2007 + by Albert Zeyer and Dark Charlie +*/ + +#ifndef __FUNCTORS_H__ +#define __FUNCTORS_H__ + + +// joins 2 functors +template +class JoinedFunctors : _F1, _F2 { +private: + _F1& f1; _F2& f2; +public: + JoinedFunctors(_F1& f1_, _F2& f2_) : f1(f1_), f2(f2_) {} + + template + bool operator()(Targ1 arg1) { + return f1(arg1) && f2(arg1); + } + + template + bool operator()(Targ1 arg1, Targ2 arg2) { + return f1(arg1, arg2) && f2(arg1, arg2); + } + +}; + +template +class NopFunctor { +public: + void operator()(_ParamType param) {} +}; + + +#endif + diff --git a/src/Iterator.h b/src/Iterator.h new file mode 100644 index 000000000..8f92c6943 --- /dev/null +++ b/src/Iterator.h @@ -0,0 +1,128 @@ +/* + OpenLieroX + + general iterator interface + + created by Albert Zeyer on 27-05-2008 + code under LGPL +*/ + +#ifndef __OLX_ITERATOR_H__ +#define __OLX_ITERATOR_H__ + +#include +#include +#include +#include +#include +#include "Ref.h" + + +template < typename _Obj > +class Iterator { +public: + virtual ~Iterator() {} + virtual Iterator* copy() const = 0; + virtual bool isValid() = 0; + virtual void next() = 0; + virtual bool operator==(const Iterator& other) const = 0; + bool operator!=(const Iterator& other) const { return ! ((*this) == other); } + virtual _Obj get() = 0; // this has to return a valid obj if valid == true + //_Obj* operator->() { return &get(); } + + typedef ::Ref< Iterator > Ref; +}; + +template +class STLIteratorBase : public Iterator<_T> { +protected: + typename _STLT::iterator i; + _STLT& obj; +public: + STLIteratorBase(_STLT& o) : i(o.begin()), obj(o) {} + STLIteratorBase(const STLIteratorBase& it) : i(it.i), obj(it.obj) {} + virtual bool isValid() { return i != obj.end(); } + virtual void next() { ++i; } + virtual bool operator==(const Iterator<_T>& other) const { const STLIteratorBase* ot = dynamic_cast< const STLIteratorBase* > (&other); return ot && &ot->obj == &obj && ot->i == i; } +}; + + +template +class STLIterator : public STLIteratorBase<_STLT, _T> { +public: + STLIterator(_STLT& o) : STLIteratorBase<_STLT, _T>(o) {} + STLIterator(const STLIterator& it) : STLIteratorBase<_STLT, _T>(it) {} + virtual Iterator<_T>* copy() const { return new STLIterator(*this); } + virtual bool operator==(const Iterator<_T>& other) const { const STLIterator* ot = dynamic_cast< const STLIterator* > (&other); return ot != NULL && STLIteratorBase<_STLT, _T> :: operator == ( other ); } + virtual _T get() { return * STLIteratorBase<_STLT, _T> :: i; } +}; + +template +class STL_MapIterator : public STLIteratorBase<_STLT, _T> { +public: + STL_MapIterator(_STLT& o) : STLIteratorBase<_STLT, _T> (o) {} + STL_MapIterator(const STL_MapIterator& it) : STLIteratorBase<_STLT, _T> (it) {} + virtual Iterator<_T>* copy() const { return new STL_MapIterator(*this); } + virtual bool operator==(const Iterator<_T>& other) const { const STL_MapIterator* ot = dynamic_cast< const STL_MapIterator* > (&other); return ot != NULL && STLIteratorBase<_STLT, _T> :: operator == ( other ); } + virtual _T get() { return STLIteratorBase<_STLT, _T> :: i -> second; } +}; + +template +struct CArray { + _T* array; + unsigned long len; + CArray(_T* a, unsigned long l) : array(a), len(l) {} +}; + +template +CArray<_T> Array(_T* a, unsigned long l) { return CArray<_T>(a,l); } + +template +class CArrayIterator : public Iterator<_T*> { +private: + unsigned long i, len; + _T* array; +public: + CArrayIterator(const CArray<_T>& a) : i(0), len(a.len), array(a.array) {} + CArrayIterator(const CArrayIterator& it) : i(it.i), array(it.array) {} + virtual Iterator<_T*>* copy() const { return new CArrayIterator(*this); } + virtual bool isValid() { return i < len; } + virtual void next() { ++i; } + virtual bool operator==(const Iterator<_T*>& other) const { const CArrayIterator* ot = dynamic_cast< const CArrayIterator* > (&other); return ot && ot->array == array && ot->i == i; } + virtual _T* get() { return &array[i]; } +}; + +template< typename __T, typename __C > +typename Iterator<__T>::Ref GetIterator(__C& s) { return s.iterator(); } + +template< typename _T > +typename Iterator<_T>::Ref GetIterator(std::set<_T>& s) { return new STLIterator,_T>(s); } + +template< typename _T > +typename Iterator<_T&>::Ref GetIterator(std::list<_T>& s) { return new STLIterator,_T&>(s); } + +template< typename _T > +typename Iterator<_T&>::Ref GetIterator(std::vector<_T>& s) { return new STLIterator,_T&>(s); } + +template< typename _T, typename _KT > +typename Iterator<_T&>::Ref GetIterator(std::map<_KT, _T>& s) { return new STL_MapIterator, _T& >(s); } + +inline +Iterator::Ref GetIterator(std::string& s) { return new STLIterator(s); } + +inline +Iterator::Ref GetConstIterator(std::string& s) { return new STLIterator(s); } + +template< typename _T > +typename Iterator<_T const&>::Ref GetConstIterator(std::vector<_T>& s) { return new STLIterator,_T const&>(s); } + +//template< typename _I, typename _T > +//typename Iterator< std::pair<_I,_T> >::Ref GetIterator(std::map<_I,_T>& s) { return s.begin(); } + +template< typename _T > +typename Iterator<_T*>::Ref GetIterator(const CArray<_T>& s) { return new CArrayIterator<_T>(s); } + + +#define foreach( t, el, s ) for( Iterator::Ref el = GetIterator(s); el->isValid(); el->next() ) + +#endif diff --git a/src/MathLib.h b/src/MathLib.h new file mode 100644 index 000000000..335ddd1bf --- /dev/null +++ b/src/MathLib.h @@ -0,0 +1,266 @@ +///////////////////////////////////////// +// +// OpenLieroX +// +// Auxiliary Software class library +// +// based on the work of JasonB +// enhanced by Dark Charlie and Albert Zeyer +// +// code under LGPL +// +///////////////////////////////////////// + + +// Mathematics Library +// Created 20/12/01 +// Jason Boettcher +// Albert Zeyer + + +#ifndef __MATHLIB_H__ +#define __MATHLIB_H__ + +#include + +#include "CVec.h" + + +// Constants +#define PI 3.14159265358979323846 + + + + +// Routines +float GetRandomNum(); // get a random float from [-1,1] +float GetRandomPosNum(); // get a random float from [0,1] +int GetRandomInt(int max); // get a random int from [0,max] +int Round(float x); + +/*#ifdef _MSC_VER +float cos(float _v) {return cosf(_v); } +float sin(float _v) {return sinf(_v); } +float tan(float _v) {return tanf(_v); } +float atan(float _v) {return atanf(_v); } +float sqrt(float _v) {return sqrtf(_v); } +#endif*/ + + +float CalculateDistance(CVec p1, CVec p2); +float NormalizeVector(CVec *vec); +CVec GetRandomVec(); +void GetVecsFromAngle(int yaw,CVec *forward, CVec *right); +float VectorAngle(CVec vec1, CVec vec2); +float VectorLength(CVec vec); +float fastSQRT(float x); + +#define SIGN(x) (((x) > 0)?1:(((x) < 0)?-1:0)) +#define SQR(x) ((x)*(x)) + +#undef MIN +#undef MAX + +template T MIN(T a, T b) { return a < b ? a : b; } +template T MAX(T a, T b) { return a > b ? a : b; } +inline unsigned long MIN(unsigned long a, unsigned int b) { return a < b ? a : b; } +template T CLAMP(const T& num, const T& lower_bound, const T& upper_bound) { + return num < lower_bound ? lower_bound : (num > upper_bound ? upper_bound : num); } +template int CLAMP_DIRECT(T& num, const T& lower_bound, const T& upper_bound) { + if(num < lower_bound) { + num = lower_bound; + return -1; + } else if(num > upper_bound) { + num = upper_bound; + return 1; + } else return 0; +} +template void REDUCE_CONST(T& v, const T& red_const) { + if(v > 0) v = MAX((T)0, v - red_const); else if(v < 0) v = MIN((T)0, v + red_const); } +template void RESET_SMALL(T& v, const T& limit) { + if((v > 0 && v < limit) || (v < 0 && v > -limit)) v = 0; } + +template void MOD(T& a, const T& b) { a %= b; if(a < 0) a += b; } +template void FMOD(T& a, const T& b) { a -= b * floor(a / b); if(a < 0) a += b; } + + +template +class SquareMatrix { +public: + VectorD2<_T> v1, v2; + SquareMatrix(VectorD2<_T> _v1 = VectorD2<_T>(0,0), VectorD2<_T> _v2 = VectorD2<_T>(0,0)) { + v1 = _v1; v2 = _v2; + } + + static SquareMatrix Identity() { + return SquareMatrix(VectorD2<_T>(1,0), VectorD2<_T>(0,1)); + } + + static SquareMatrix RotateMatrix(float angle) { + SquareMatrix m; + m.v1.x = cos(angle); + m.v1.y = sin(angle); + m.v2.x = -m.v1.y; + m.v2.y = m.v1.x; + return m; + } + + CVec operator()(const VectorD2<_T>& v) const { + return CVec(v.x*v1.x + v.y*v2.x, v.x*v1.y + v.y*v2.y); + } + SquareMatrix operator*(const SquareMatrix& m) const { + return SquareMatrix((*this)(m.v1), (*this)(m.v2)); + } + SquareMatrix operator*(const float m) const { + return SquareMatrix(v1*m, v2*m); + } + SquareMatrix operator*(const int m) const { + return SquareMatrix(v1*m, v2*m); + } + SquareMatrix operator/(const float m) const { + return SquareMatrix(v1/m, v2/m); + } + SquareMatrix operator/(const int m) const { + return SquareMatrix(v1/m, v2/m); + } + _T det() const { + return v1.x*v2.y - v1.y*v2.x; + } + SquareMatrix inverse() const { + _T tdet = det(); + if(tdet == 0) + return SquareMatrix(); + else + return SquareMatrix(VectorD2<_T>(v2.y,-v1.y),VectorD2<_T>(-v2.x,v1.x))/tdet; + } + + // v1 is the upper-left, v2 the right-bottom + bool isInDefinedArea(const VectorD2<_T>& p) const { + return v1.x <= p.x && p.x <= v2.x && v1.y <= p.y && p.y <= v2.y; + } + + VectorD2<_T> getCenter() const { + return (v1 + v2) / 2; + } + + SquareMatrix getInsersectionWithArea(const SquareMatrix& a) const { + return SquareMatrix( + VectorD2<_T>( MAX(a.v1.x, v1.x), MAX(a.v1.y, v1.y) ), + VectorD2<_T>( MIN(a.v2.x, v2.x), MIN(a.v2.y, v2.y) ) + ); + } + +}; + + +class Parabola { +public: + float a, b, c; // a*x^2 + b*x + c +public: + Parabola() : a(0), b(0), c(0) {} + Parabola(float pa, float pb, float pc) : a(pa), b(pb), c(pc) {} + Parabola(const Parabola& p) { a = p.a; b = p.b; c = p.c; } + Parabola(CVec p1, CVec p2, CVec p3); + Parabola(CVec p1, float angleP1, CVec p2); + + inline bool operator==(const Parabola& p) const { + return (a == p.a && b == p.b && c == p.c); + } + + float getLength(CVec p1, CVec p2); + float getLength(float pa, float pb); + bool isPointAtParabola(CVec p1) { + return (p1.y == (a * p1.x * p1.x ) + (b * p1.x) + c); + } +}; + + +// Random number generator with save()/restore() methods that will save and restore generator's state +// This generator should produce the same numbers on any CPU architecture, if initialized with the same seed. +// Ripped from Gnu Math library +// I don't want to use Mersenne Twister 'cuz it has a state of 624 ints which should be copied with Save()/Restore() + +class SyncedRandom +{ +public: + + SyncedRandom( unsigned long s = getRandomSeed() ) + { + if (!s) + s = 1UL; /* default seed is 1 */ + + z1 = LCG (s); + if (z1 < 2UL) + z1 += 2UL; + z2 = LCG (z1); + if (z2 < 8UL) + z2 += 8UL; + z3 = LCG (z2); + if (z3 < 16UL) + z3 += 16UL; + z4 = LCG (z3); + if (z4 < 128UL) + z4 += 128UL; + + /* Calling RNG ten times to satify recurrence condition */ + getInt(); getInt(); getInt(); getInt(); getInt(); + getInt(); getInt(); getInt(); getInt(); getInt(); + }; + + // Returns unsigned int in a range 0 : UINT_MAX + unsigned long getInt() + { + unsigned long b1, b2, b3, b4; + + b1 = ((((z1 << 6UL) & MASK) ^ z1) >> 13UL); + z1 = ((((z1 & 4294967294UL) << 18UL) & MASK) ^ b1); + + b2 = ((((z2 << 2UL) & MASK) ^ z2) >> 27UL); + z2 = ((((z2 & 4294967288UL) << 2UL) & MASK) ^ b2); + + b3 = ((((z3 << 13UL) & MASK) ^ z3) >> 21UL); + z3 = ((((z3 & 4294967280UL) << 7UL) & MASK) ^ b3); + + b4 = ((((z4 << 3UL) & MASK) ^ z4) >> 12UL); + z4 = ((((z4 & 4294967168UL) << 13UL) & MASK) ^ b4); + + return (z1 ^ z2 ^ z3 ^ z4); + }; + + // Returns float in range 0 : 1 (1 non-inclusive) + float getFloat() + { + return getInt() / 4294967296.0f; + }; + + void save() + { + save_z1 = z1; + save_z2 = z2; + save_z3 = z3; + save_z4 = z4; + }; + + void restore() + { + z1 = save_z1; + z2 = save_z2; + z3 = save_z3; + z4 = save_z4; + }; + + // Returns random seed based on time() and SDL_GetTicks() functions + static unsigned long getRandomSeed(); + +private: + + static const unsigned long MASK = 0xffffffffUL; + unsigned long LCG(unsigned long n) { return ((69069UL * n) & MASK); }; + + unsigned long z1, z2, z3, z4; + + unsigned long save_z1, save_z2, save_z3, save_z4; +}; + + +#endif // __MATHLIB_H__ diff --git a/src/Mutex.h b/src/Mutex.h new file mode 100644 index 000000000..27fb5f19a --- /dev/null +++ b/src/Mutex.h @@ -0,0 +1,51 @@ +/* + OpenLieroX + + Mutex wrapper + + created 10-02-2009 by Karel Petranek + code under LGPL +*/ + +#ifndef __MUTEX_H__ +#define __MUTEX_H__ + +#include + +#define INVALID_THREAD_ID (Uint32)-1 + +class Condition; + +// Mutex wrapper class with some extra debugging checks +class Mutex { + friend class Condition; +private: + SDL_mutex *m_mutex; + +#ifdef DEBUG + volatile Uint32 m_lockedThread; // Thread that keeps the lock +#endif + +public: +/*#ifdef DEBUG + Mutex(); + ~Mutex(); + void lock(); + void unlock(); + + static void test(); +#else */ + Mutex() { m_mutex = SDL_CreateMutex(); } + ~Mutex() { SDL_DestroyMutex(m_mutex); } + void lock() { SDL_LockMutex(m_mutex); } + void unlock() { SDL_UnlockMutex(m_mutex); } +//#endif + + struct ScopedLock { + Mutex& mutex; + ScopedLock(Mutex& m) : mutex(m) { mutex.lock(); } + ~ScopedLock() { mutex.unlock(); } + }; +}; + +#endif // __MUTEX_H__ diff --git a/src/Ref.h b/src/Ref.h new file mode 100644 index 000000000..530fd60d6 --- /dev/null +++ b/src/Ref.h @@ -0,0 +1,43 @@ +/* + OpenLieroX + + various utilities + + code under LGPL + created 01-05-2007 + by Albert Zeyer and Dark Charlie +*/ + +#ifndef __OLX__REF_H__ +#define __OLX__REF_H__ + +/* + intended to hold an object of an abstract class (interface) + + Ref< Iterator > is a typical example, because you normally + don't want to know about the specific implementation of Iterator +*/ +template < typename _Obj > +class Ref { +private: + _Obj* m_obj; + void clear() { if(m_obj) delete m_obj; m_obj = NULL; } + +public: + Ref(_Obj* obj = NULL) : m_obj(obj) {} + Ref(const Ref& ref) { m_obj = ref->copy(); } + ~Ref() { clear(); } + + Ref& operator=(_Obj* obj) { if(obj != m_obj) { clear(); m_obj = obj; } return *this; } + Ref& operator=(const Ref& ref) { if(ref.m_obj != m_obj) { clear(); m_obj = ref->copy(); } return *this; } + + _Obj* operator->() { return m_obj; } + const _Obj* operator->() const { return m_obj; } + _Obj& get() { return *m_obj; } + const _Obj& get() const { return *m_obj; } + bool isSet() const { return m_obj != NULL; } + _Obj* overtake() { _Obj* r = m_obj; m_obj = NULL; return r; } // this resets the Ref and returns the old pointer without deleting it +}; + +#endif + diff --git a/src/RefCounter.h b/src/RefCounter.h new file mode 100644 index 000000000..0164cbee7 --- /dev/null +++ b/src/RefCounter.h @@ -0,0 +1,54 @@ +/* + * RefCounter.h + * OpenLieroX + * + * Created by Albert Zeyer on 01.06.09. + * code under LGPL + * + */ + +#ifndef __OLX__REFCOUNTER_H__ +#define __OLX__REFCOUNTER_H__ + +#include // for size_t + +/* + * This class is to be added as an additional baseclass and overload the onLastRefRemoved method. + */ + +class RefCounter { +private: + size_t* m_refCount; + + // asumes that already cleared + void copy(const RefCounter& r) { + m_refCount = r.m_refCount; + (*m_refCount)++; + } + +protected: + // call this manually if you aren't sure if your virtual function is already unset + void uninit() { + if(m_refCount) { + (*m_refCount)--; + size_t* ref = m_refCount; + m_refCount = NULL; + if(*ref == 0) { + delete ref; + onLastRefRemoved(); + } + } + } + +public: + RefCounter() : m_refCount(NULL) { m_refCount = new size_t(1); } + RefCounter(const RefCounter& r) : m_refCount(NULL) { copy(r); } + RefCounter& operator=(const RefCounter& r) { uninit(); copy(r); return *this; } + virtual ~RefCounter() { uninit(); } + size_t refCount() const { return *m_refCount; } + + virtual void onLastRefRemoved() = 0; +}; + +#endif + diff --git a/src/SmartPointer.h b/src/SmartPointer.h new file mode 100644 index 000000000..a79e8c109 --- /dev/null +++ b/src/SmartPointer.h @@ -0,0 +1,263 @@ +/* + OpenLieroX + code under LGPL + 27-12-2007 Albert Zeyer +*/ + +#ifndef __SMARTPOINTER_H__ +#define __SMARTPOINTER_H__ + +#include +#include +#include + +#ifdef DEBUG +#include +#include "Debug.h" +#endif + +#include "Functors.h" +#include "ThreadPool.h" + +template < typename _Type, typename _SpecificInitFunctor > +class SmartPointer; + +// Default de-initialization action is to call operator delete, for each object type. +template < typename _Type > +void SmartPointer_ObjectDeinit( _Type * obj ) +{ + delete obj; +} + +// these forward-declaration are needed here +struct SDL_Surface; +struct SoundSample; +class CMap; +class CGameScript; + +// Specialized de-init functions, for each simple struct-like type that has no destructor +template <> void SmartPointer_ObjectDeinit ( SDL_Surface * obj ); // Calls gfxFreeSurface(obj); +template <> void SmartPointer_ObjectDeinit ( SoundSample * obj ); // Calls FreeSoundSample(obj); +template <> void SmartPointer_ObjectDeinit ( CMap * obj ); // Requires to be defined elsewhere +template <> void SmartPointer_ObjectDeinit ( CGameScript * obj ); // Requires to be defined elsewhere + +#ifdef DEBUG +extern SDL_mutex *SmartPointer_CollMutex; +extern std::map< void *, SDL_mutex * > * SmartPointer_CollisionDetector; +#endif + +/* + standard smartpointer based on simple refcounting + + The refcounting is multithreading safe in this class, + you can have copies of this object in different threads. + Though it's not designed to operate with the same + object in different threads. Also there is absolutly no + thread safty on the pointer itself, you have to care + about this yourself. +*/ + +/*template < typename _Obj > +class SmartObject;*/ + +template < typename _Type, typename _SpecificInitFunctor = NopFunctor > +class SmartPointer { //friend class SmartObject<_Type>; +private: + _Type* obj; + int* refCount; + SDL_mutex* mutex; + + + void init(_Type* newObj) { +#ifdef DEBUG + if (SmartPointer_CollMutex == NULL) + SmartPointer_CollMutex = SDL_CreateMutex(); +#endif + + if( newObj == NULL ) + return; + if(!mutex) { + mutex = SDL_CreateMutex(); + obj = newObj; + refCount = new int; + *refCount = 1; + #ifdef DEBUG + SDL_LockMutex(SmartPointer_CollMutex); + if( SmartPointer_CollisionDetector == NULL ) + { + hints << "SmartPointer collision detector initialized" << endl; + SmartPointer_CollisionDetector = new std::map< void *, SDL_mutex * > (); + } + if( SmartPointer_CollisionDetector->count(obj) != 0 ) // Should be faster than find() I think + { + errors << "ERROR! SmartPointer collision detected, old mutex " << (*SmartPointer_CollisionDetector)[obj] + << ", new ptr (" << this << " " << obj << " " << refCount << " " << mutex << " " << (refCount?*refCount:-99) << ") new " << newObj << endl; + SDL_UnlockMutex(SmartPointer_CollMutex); + assert(false); // TODO: maybe do smth like *(int *)NULL = 1; to generate coredump? Simple assert(false) won't help us a lot + } + else + SmartPointer_CollisionDetector->insert( std::make_pair( obj, mutex ) ); + SDL_UnlockMutex(SmartPointer_CollMutex); + #endif + } + } + + void reset() { + if(mutex) { + lock(); + (*refCount)--; + if(*refCount == 0) { + #ifdef DEBUG + SDL_LockMutex(SmartPointer_CollMutex); + if( !SmartPointer_CollisionDetector || SmartPointer_CollisionDetector->count(obj) == 0 ) + { + errors << "ERROR! SmartPointer already deleted reference (" + << this << " " << obj << " " << refCount << " " << mutex << " " << (refCount?*refCount:-99) << ")" << endl; + if(!SmartPointer_CollisionDetector) + errors << "SmartPointer_CollisionDetector is already uninitialised" << endl; + SDL_UnlockMutex(SmartPointer_CollMutex); + assert(false); + } + else + { + SmartPointer_CollisionDetector->erase(obj); + if( SmartPointer_CollisionDetector->empty() ) + { + delete SmartPointer_CollisionDetector; + SmartPointer_CollisionDetector = NULL; + if (SmartPointer_CollMutex) + { + SDL_DestroyMutex(SmartPointer_CollMutex); + SmartPointer_CollMutex = NULL; + } + + // WARNING: this is called at a very end for global objects and most other objects are already uninitialised. + // For me, even the internal string structure doesn't work anymore (I get a std::length_error) and thus we cannot use the logging system. + // TODO: Remove any global objects! We should not have any globals, at least not such complex globals. + #ifdef DEBUG + printf("SmartPointer collision detector de-initialized, everything is freed now\n"); + #endif + } + } + if( SmartPointer_CollMutex ) + SDL_UnlockMutex(SmartPointer_CollMutex); + #endif + SmartPointer_ObjectDeinit( obj ); + delete refCount; // safe, because there is no other ref anymore + obj = NULL; + refCount = NULL; + unlock(); + SDL_DestroyMutex(mutex); // safe because there is no other ref anymore + mutex = NULL; + } else + unlock(); + } + obj = NULL; + refCount = NULL; + mutex = NULL; + } + + void incCounter() { + assert(*refCount > 0 && *refCount < INT_MAX); + (*refCount)++; + } + + void lock() { + //printf("SmartPointer::lock (%10p %10p %10p %10p %3i)\n", this, obj, refCount, mutex, refCount?*refCount:-99); + SDL_mutexP(mutex); + } + void unlock() { + //printf("SmartPointer::unlock (%10p %10p %10p %10p %3i)\n", this, obj, refCount, mutex, refCount?*refCount:-99); + SDL_mutexV(mutex); + } + +public: + SmartPointer() : obj(NULL), refCount(NULL), mutex(NULL) { + //printf("SmartPointer::construc(%10p %10p %10p %10p %3i)\n", this, obj, refCount, mutex, refCount?*refCount:-99); + _SpecificInitFunctor()(this); + } + ~SmartPointer() { + //printf("SmartPointer::destruct(%10p %10p %10p %10p %3i)\n", this, obj, refCount, mutex, refCount?*refCount:-99); + reset(); + } + + // Default copy constructor and operator= + // If you specify any template<> params here these funcs will be silently ignored by compiler + SmartPointer(const SmartPointer& pt) : obj(NULL), refCount(NULL), mutex(NULL) { operator=(pt); } + SmartPointer& operator=(const SmartPointer& pt) { + if(mutex == pt.mutex) return *this; // ignore this case + reset(); + mutex = pt.mutex; + if(mutex) { + lock(); + obj = pt.obj; refCount = pt.refCount; + incCounter(); + unlock(); + } else { obj = NULL; refCount = NULL; } + return *this; + } + + // WARNING: Be carefull, don't assing a pointer to different SmartPointer objects, + // else they will get freed twice in the end. Always copy the SmartPointer itself. + // In short: SmartPointer ptr(SomeObj); SmartPointer ptr1( ptr.get() ); // It's wrong, don't do that. + SmartPointer(_Type* pt): obj(NULL), refCount(NULL), mutex(NULL) { operator=(pt); } + SmartPointer& operator=(_Type* pt) { + //printf("SmartPointer::op=Type (%10p %10p %10p %10p %3i)\n", this, obj, refCount, mutex, refCount?*refCount:-99); + if(obj == pt) return *this; // ignore this case + reset(); + init(pt); + return *this; + } + + _Type* get() const { return obj; } // The smartpointer itself won't change when returning address of obj, so it's const. + + // HINT: no convenient cast functions in this class to avoid error-prone automatic casts + // (which would lead to collisions!) + // This operator is safe though. + _Type * operator -> () const { return obj; }; + + // refcount may be changed from another thread, though if refcount==1 or 0 it won't change + int getRefCount() { + int ret = 0; + if(mutex) { + lock(); + ret = *refCount; + unlock(); // Here the other thread may change refcount, that's why it's approximate + } + return ret; + } + + // Returns true only if the data is deleted (no other smartpointer used it), sets pointer to NULL then + bool tryDeleteData() { + if(mutex) { + lock(); + if( *refCount == 1 ) + { + unlock(); // Locks mutex again inside reset(), since we're only ones using data refcount cannot change from other thread + reset(); + return true; // Data deleted + } + unlock(); + return false; // Data not deleted + } + return true; // Data was already deleted + } + +}; + +/* +template< typename _Obj> +class SmartObject : public SmartPointer< SmartObject<_Obj> > { +public: + typedef SmartPointer< SmartObject<_Obj> > SmartPtrType; + SmartObject() { SmartPtrType :: operator =( this ); } + virtual ~SmartObject() { } +private: + // overwrite to disable this op= + SmartPtrType& operator=(const SmartPtrType& pt) { assert(false); } + +}; +*/ + +#endif + diff --git a/src/StringBuf.cpp b/src/StringBuf.cpp new file mode 100644 index 000000000..b136ed564 --- /dev/null +++ b/src/StringBuf.cpp @@ -0,0 +1,199 @@ +///////////////////////////////////////// +// +// OpenLieroX +// +// code under LGPL, based on JasonBs work, +// enhanced by Dark Charlie and Albert Zeyer +// +// +///////////////////////////////////////// + + +// String Buffer +// Created 11/8/08 +// Karel Petranek + + + +#include "StringBuf.h" +#include "StringUtils.h" +#include "Debug.h" +#include "Utils.h" + + +// Helper functions +std::string strlwr(const std::string& s) +{ + std::string res = s; + stringlwr(res); + return res; +} + +///////////////////// +// Adjusts the blank characters so that there are no repeated blank characters and the blank characters are all +// turned to spaces +void StringBuf::adjustBlank() +{ + // Check + if (sStr.size() < 3) + return; + + // Initialize iterators + std::string::const_iterator it = sStr.begin(); + std::string::const_iterator prev = it; + it++; + + // Get the adjusted string + std::string res; + res += *sStr.begin(); // First character, sStr != "" here + for (; it != sStr.end(); it++, prev++) { + if (isspace((unsigned char)*it)) { // Blank + if (isspace((unsigned char)*prev)) // Previous also blank, ignroe + continue; + else { // Previous not blank, convert to space and add + res += ' '; + continue; + } + } + res += *it; // Normal character + } + + sStr = res; + tPos = sStr.begin(); +} + +///////////////////// +// Trims all blank characters from both sides of the string +void StringBuf::trimBlank() +{ + // Start + while (sStr.size() && isspace((unsigned char)(*(sStr.begin())))) + sStr.erase(sStr.begin()); + + // End + while (sStr.size() && isspace((unsigned char)(*(sStr.rbegin())))) + sStr.erase(sStr.size() - 1, 1); + + tPos = sStr.begin(); +} + +//////////////////// +// Tokenizes the string buffer by blank characters, multiple blank characters are taken as one +std::vector StringBuf::splitByBlank() +{ + std::vector res; + std::string token; + bool was_space = false; + for (std::string::iterator it = sStr.begin(); it != sStr.end(); it++) { + if (isspace((unsigned char)(*it))) { + if (was_space) // Multiple spaces get ignored + continue; + else { + res.push_back(token); // Add the token + token = ""; + } + + was_space = true; + continue; + } + + was_space = false; + token += *it; + } + + // Last token + res.push_back(token); + + return res; +} + +//////////////////// +// Tokenizes the string buffer by blank the specified character +std::vector StringBuf::splitBy(char c) +{ + std::vector res; + std::string token; + for (std::string::iterator it = sStr.begin(); it != sStr.end(); it++) { + if (*it == c) { + res.push_back(token); // Add the token + token = ""; + continue; + } + + token += *it; + } + + // Last token + res.push_back(token); + + return res; +} + +//////////////////////// +// Reads until the specified character and skips it +std::string StringBuf::readUntil(char c) +{ + std::string res; + while (!atEnd() && *tPos != c) { + res += *tPos; + incPos(); + } + + // Skip the breaking character + if (!atEnd()) + incPos(); + + return res; +} + +//////////////////////// +// Reads until one of the characters specified in char_array, NOT until the string in char_array +std::string StringBuf::readUntil(const std::string& char_array) +{ + std::string res; + while (!atEnd() && char_array.find(*tPos) == std::string::npos) { + res += *tPos; + incPos(); + } + + // Skip the breaking character + if (!atEnd()) + incPos(); + + return res; +} + +///////////////////////// +// Reads the specified number of bytes from the buf +std::string StringBuf::read(size_t num) +{ + std::string::iterator oth = tPos; + SafeAdvance(tPos, num, sStr.end()); + return std::string(tPos, oth); +} + +/////////////////////// +// Skips any blank characters +size_t StringBuf::skipBlank() +{ + size_t res = 0; + while (!atEnd() && isspace((unsigned char)(*tPos))) { + ++res; + incPos(); + } + return res; +} + +///////////////////// +// Converts the buffer to lower case +void StringBuf::toLower() +{ + stringlwr(sStr); +} + +///////////////////// +// Prints the contents to stdout +void StringBuf::debugPrint() +{ + notes << sStr << endl << endl; +} diff --git a/src/StringBuf.h b/src/StringBuf.h new file mode 100644 index 000000000..3676f94af --- /dev/null +++ b/src/StringBuf.h @@ -0,0 +1,74 @@ +///////////////////////////////////////// +// +// OpenLieroX +// +// code under LGPL, based on JasonBs work, +// enhanced by Dark Charlie and Albert Zeyer +// +// +///////////////////////////////////////// + +#ifndef __OLX__STRINGBUF_H__ +#define __OLX__STRINGBUF_H__ + +// String Buffer +// Created 11/8/08 +// Karel Petranek + +#include +#include + +// String buffer class +class StringBuf { +public: + StringBuf() : sStr("") { tPos = sStr.begin(); } + StringBuf(const std::string& str) : sStr(str) { tPos = sStr.begin(); } +private: + std::string::iterator tPos; + std::string sStr; + +public: + StringBuf& operator=(const StringBuf& b2) { + if (&b2 != this) { + tPos = b2.tPos; + sStr = b2.sStr; + } + return *this; + } + + StringBuf& operator=(const std::string& s) { + sStr = s; + tPos = sStr.begin(); + return *this; + } + + StringBuf& operator=(const char *s) { + sStr = s; + tPos = sStr.begin(); + return *this; + } + + char getC() { return tPos == sStr.end() ? 0 : *tPos; } + void setC(char c) { if (!atEnd()) *tPos = c; } + void incPos() { tPos++; } + void decPos() { tPos--; } + void resetPos() { tPos = sStr.begin(); } + bool atEnd() { return tPos == sStr.end(); } + void erase(size_t start, size_t count) { sStr.erase(start, count); tPos = sStr.begin(); } + void toLower(); + std::string readUntil(char c); + std::string readUntil(const std::string& char_array); + std::string read(size_t num); + std::string getRestStr() { return std::string(tPos, sStr.end()); } + void trimBlank(); + void adjustBlank(); + size_t skipBlank(); + size_t size() { return sStr.size(); } + bool empty() { return sStr.size() == 0; } + const std::string& str() { return sStr; } + std::vector splitByBlank(); + std::vector splitBy(char c); + void debugPrint(); +}; + +#endif diff --git a/src/StringUtils.cpp b/src/StringUtils.cpp new file mode 100644 index 000000000..355e2010e --- /dev/null +++ b/src/StringUtils.cpp @@ -0,0 +1,1050 @@ +/* + OpenLieroX + + string utilities + + code under LGPL + created 01-05-2007 + by Albert Zeyer and Dark Charlie +*/ + +#ifdef _MSC_VER +#pragma warning(disable: 4786) // WARNING: identifier XXX was truncated to 255 characters in the debug info... +#endif + +#include "StringUtils.h" +#include "FindFile.h" +#include "MathLib.h" +#include "StringBuf.h" + + +#include +#include + + +/////////////////// +// Trim the leading & ending spaces from a string +void TrimSpaces(std::string& szLine) { + size_t n = 0; + std::string::iterator p; + for(p = szLine.begin(); p != szLine.end(); p++, n++) + if(!isspace((unsigned char)*p) || isgraph((unsigned char)*p)) break; + if(n>0) szLine.erase(0,n); + + n = 0; + std::string::reverse_iterator p2; + for(p2 = szLine.rbegin(); p2 != szLine.rend(); p2++, n++) + if(!isspace((unsigned char)*p2) || isgraph((unsigned char)*p2)) break; + if(n>0) szLine.erase(szLine.size()-n); +} + + +/////////////////// +// Replace a string in text, returns true, if something was replaced +bool replace(const std::string& text, const std::string& what, const std::string& with, std::string& result) +{ + result = text; + return replace(result, what, with); +} + +/////////////////// +// Replace a string in text, returns result, replaces maximally max occurences +std::string replacemax(const std::string& text, const std::string& what, const std::string& with, std::string& result, int max) +{ + result = text; + + size_t pos = 0; + size_t what_len = what.length(); + size_t with_len = with.length(); + if((pos = result.find(what, pos)) != std::string::npos) { + result.replace(pos, what_len, with); + pos += with_len; + } + + return result; +} + +std::string replacemax(const std::string& text, const std::string& what, const std::string& with, int max) { + std::string result; + return replacemax(text, what, with, result, max); +} + +/////////////////// +// Replace a string in text, returns result, replaces maximally max occurences +// returns true, if at least one replace was made +bool replace(std::string& text, const std::string& what, const std::string& with) { + // Make sure there is something to replace + if (!what.size()) { + return false; + } + + bool one_repl = false; + size_t pos = 0; + while((pos = text.find(what, pos)) != std::string::npos) { + text.replace(pos, what.length(), with); + pos += with.length(); + one_repl = true; + } + return one_repl; +} + +// chrcasecmp - like strcasecomp, but for a single char +int chrcasecmp(const char c1, const char c2) +{ + return (tolower(c1) == tolower(c2)); +} + +////////////////// +// Gets the string [beginning of text,searched character) +std::string ReadUntil(const std::string& text, char until_character) { + size_t pos = 0; + for(std::string::const_iterator i = text.begin(); i != text.end(); i++, pos++) { + if(*i == until_character) + return text.substr(0, pos); + } + return text; +} + +std::string ReadUntil(const std::string& text, std::string::const_iterator& it, char until_character, const std::string& alternative) { + std::string::const_iterator start = it; + for(; it != text.end(); it++) { + if(*it == until_character) + return std::string(start, it); + } + return alternative; +} + + +std::string ReadUntil(FILE* fp, char until_character) { + char buf[256]; + std::string res; + res = ""; + size_t buf_pos = 0; + while(true) { + if(fread(&buf[buf_pos],1,1,fp) == 0 || buf[buf_pos] == until_character) { + res.append(buf,buf_pos); + break; + } + buf_pos++; + if(buf_pos >= sizeof(buf)) { + buf_pos = 0; + res.append(buf,sizeof(buf)); + } + } + + return res; +} + +bool PrettyPrint(const std::string& prefix, const std::string& buf, PrintOutFct printOutFct, bool firstLineWithPrefix) { + std::string::const_iterator it = buf.begin(); + bool firstLine = true; + while(true) { + std::string tmp = ReadUntil(buf, it, '\n', std::string(it, buf.end())); + if(it == buf.end()) { + if(tmp != "") { + (*printOutFct) ( (!firstLineWithPrefix && firstLine) ? tmp : (prefix + tmp) ); + return false; + } + return !firstLine || firstLineWithPrefix; + } + ++it; + (*printOutFct) ( (!firstLineWithPrefix && firstLine) ? (tmp + "\n") : (prefix + tmp + "\n") ); + firstLine = false; + } +} + + +Iterator::Ref HexDump(Iterator::Ref start, PrintOutFct printOutFct, size_t mark, size_t count) { + std::string tmpLeft; + std::string tmpRight; + unsigned int tmpChars = 0; + static const unsigned int charsInLine = 16; + + size_t c = 0; + while(start->isValid() && c < count) { + unsigned char ch = start->get(); + + tmpLeft += FixedWidthStr_LeftFill(hex(ch), 2, '0'); + tmpLeft += (c == mark) ? "]" : (c + 1 == mark) ? "[" : " "; + if(ch >= 32 && ch <= 126) + tmpRight += ch; + else + tmpRight += '.'; + + tmpChars++; + if(tmpChars == charsInLine / 2) { + tmpLeft += " "; + tmpRight += " "; + } + if(tmpChars == charsInLine) { + (*printOutFct) ( tmpLeft + "| " + tmpRight + "\n" ); + tmpChars = 0; + tmpLeft = tmpRight = ""; + } + + start->next(); + c++; + } + + tmpLeft += std::string((charsInLine - tmpChars) * 3, ' '); + tmpRight += std::string((charsInLine - tmpChars), ' '); + if(tmpChars < charsInLine / 2) { tmpLeft += " "; tmpRight += " "; } + (*printOutFct) ( tmpLeft + "| " + tmpRight + "\n" ); + + return start; +} + + +////////////////////////// +// Contains a definition of some common colors, used internally by StrToCol +Color GetColorByName(const std::string& str, bool& fail) +{ + fail = false; + + struct ColorEntry { + std::string sName; + Uint8 r, g, b, a; + }; +#define OP SDL_ALPHA_OPAQUE +#define TR SDL_ALPHA_TRANSPARENT + + // TODO: more? These are taken from the HTML specification + static const ColorEntry predefined[] = { + { "white", 255, 255, 255,OP }, + { "black", 0, 0, 0, OP }, + { "red", 255, 0, 0, OP }, + { "green", 0, 127, 0, OP }, + { "blue", 0, 0, 255, OP }, + { "silver", 0xC0, 0xC0, 0xC0, OP }, + { "gray", 127, 127, 127, OP }, + { "grey", 127, 127, 127, OP }, + { "purple", 127, 0, 127, OP }, + { "fuchsia", 255, 0, 255, OP }, + { "pink", 255, 0, 255, OP }, + { "lime", 0, 255, 0, OP }, + { "olive", 127, 127, 0, OP }, + { "yellow", 255, 255, 0, OP }, + { "navy", 0, 0, 127, OP }, + { "teal", 0, 127, 127, OP }, + { "aqua", 0, 255, 255, OP }, + { "gold", 255, 215, 0, OP }, + { "transparent", 0, 0, 0, TR } + }; + + for (size_t i = 0; i < sizeof(predefined) / sizeof(ColorEntry); ++i) + if (stringcaseequal(str, predefined[i].sName)) + return Color(predefined[i].r, predefined[i].g, predefined[i].b, predefined[i].a); + + fail = true; + + return Color(); +} + +///////////////////// +// Helper function for HexToCol, accepts only adjusted values +static void HexToCol_Pure(const std::string& hex, Color& col, bool& fail) +{ + col.r = MIN(from_string(hex.substr(0,2), std::hex, fail), 255); + col.g = MIN(from_string(hex.substr(2,2), std::hex, fail), 255); + col.b = MIN(from_string(hex.substr(4,2), std::hex, fail), 255); + if (hex.size() >= 8) + col.a = MIN(from_string(hex.substr(6,2), std::hex, fail), 255); + else + col.a = SDL_ALPHA_OPAQUE; +} + +//////////////////////// +// Helper function for StrToCol +static Color HexToCol(const std::string& hex, bool& fail) +{ + fail = false; + Color res; + + // For example FFF for white + if (hex.size() == 3) { + std::string tmp; + tmp += hex[0]; tmp += hex[0]; + tmp += hex[1]; tmp += hex[1]; + tmp += hex[2]; tmp += hex[2]; + + HexToCol_Pure(tmp, res, fail); + + return res; + } + + // Same as the above but with alpha + if (hex.size() == 4) { + std::string tmp; + tmp += hex[0]; tmp += hex[0]; + tmp += hex[1]; tmp += hex[1]; + tmp += hex[2]; tmp += hex[2]; + tmp += hex[3]; tmp += hex[3]; + + HexToCol_Pure(tmp, res, fail); + + return res; + } + + // For example FFFFFF for white + if (hex.size() == 6) { + HexToCol_Pure(hex, res, fail); + return res; + } + + // Same as the above but with alpha + if (hex.size() >= 8) { + HexToCol_Pure(hex, res, fail); + return res; + } + + fail = true; + return Color(); +} + +std::string ColToHex(Color col) { + std::string buf; + buf += FixedWidthStr_LeftFill(itoa(col.r, 16), 2, '0') + + buf += FixedWidthStr_LeftFill(itoa(col.g, 16), 2, '0') + + buf += FixedWidthStr_LeftFill(itoa(col.b, 16), 2, '0'); + if(col.a != SDL_ALPHA_OPAQUE) + buf += FixedWidthStr_LeftFill(itoa(col.a, 16), 2, '0'); + + return "#" + buf; +} + + +////////////////////// +// Returns true if the value ends with a percent sign +static bool is_percent(const std::string& str) +{ + if (!str.size()) + return false; + return (*(str.rbegin())) == '%'; +} + +/////////////////// +// Returns a color defined function-like: rgba(0, 0, 0, 0) +static Color ColFromFunc(const std::string& func, bool& fail) +{ + StringBuf tmp(func); + + tmp.trimBlank(); + tmp.adjustBlank(); + std::string func_name = tmp.readUntil('('); + TrimSpaces(func_name); + + // Get the params + StringBuf params = tmp.readUntil(')'); + std::vector tokens = params.splitBy(','); + if (tokens.size() < 3) { + fail = true; + return Color(); + } + + // Adjust the tokens + for (std::vector::iterator it = tokens.begin(); it != tokens.end(); it++) { + TrimSpaces(*it); + } + + // The param count is >= 3 + Color res; + res.r = MIN(255, from_string(tokens[0], fail)); if (is_percent(tokens[0])) res.r = (Uint8)MIN(255.0f, (float)res.r * 2.55f); + res.g = MIN(255, from_string(tokens[1], fail)); if (is_percent(tokens[1])) res.g = (Uint8)MIN(255.0f, (float)res.g * 2.55f); + res.b = MIN(255, from_string(tokens[2], fail)); if (is_percent(tokens[2])) res.b = (Uint8)MIN(255.0f, (float)res.b * 2.55f); + if (tokens.size() >= 4 && stringcaseequal(func_name, "rgba")) { + res.a = MIN(255, from_string(tokens[3], fail)); if (is_percent(tokens[3])) res.a = (Uint8)MIN(255.0f, (float)res.a * 2.55f); + } else + res.a = SDL_ALPHA_OPAQUE; + + return res; +} + +static Color ColFromSeperatedNums(const std::string& txt, bool& fail) { + std::vector tokens = explode(txt, ","); + if (tokens.size() < 3) { + fail = true; + return Color(); + } + + Color res; + res.r = MIN(255, from_string(tokens[0], fail)); if (is_percent(tokens[0])) res.r = (Uint8)MIN(255.0f, (float)res.r * 2.55f); + res.g = MIN(255, from_string(tokens[1], fail)); if (is_percent(tokens[1])) res.g = (Uint8)MIN(255.0f, (float)res.g * 2.55f); + res.b = MIN(255, from_string(tokens[2], fail)); if (is_percent(tokens[2])) res.b = (Uint8)MIN(255.0f, (float)res.b * 2.55f); + if(tokens.size() >= 4) { + res.a = MIN(255, from_string(tokens[3], fail)); if (is_percent(tokens[3])) res.a = (Uint8)MIN(255.0f, (float)res.a * 2.55f); + } else + res.a = SDL_ALPHA_OPAQUE; + + return res; +} + +////////////////// +// Converts a string to a colour +Color StrToCol(const std::string& str, bool& fail) { + fail = false; + + // Create the temp and copy it there + std::string temp = str; + TrimSpaces(temp); + + if(temp.size() > 0 && temp[temp.size()-1] == ';') { + temp.erase(temp.size()-1); + TrimSpaces(temp); + } + + // Check for a blank string + if (temp.size() == 0) { + fail = true; + return Color(); + } + + // Is the # character present? + if (temp[0] == '#') { // str != "" here + temp.erase(0,1); + stringlwr(temp); + return HexToCol(temp, fail); + } + + // Is the function-style present? + if (temp.size() >= 4) + if (stringcaseequal(temp.substr(0, 4), "rgba")) + return ColFromFunc(temp, fail); + if (temp.size() >= 3) + if (stringcaseequal(temp.substr(0, 3), "rgb")) + return ColFromFunc(temp, fail); + + // like "r,g,b", e.g. this is used in gamescripts + if(temp.find(",") != std::string::npos) + return ColFromSeperatedNums(temp, fail); + + // Check if it's a known predefined color + return GetColorByName(str, fail); +} + +Color StrToCol(const std::string& str) +{ + bool fail = false; + return StrToCol(str, fail); +} + +short stringcasecmp(const std::string& s1, const std::string& s2) { + std::string::const_iterator p1, p2; + p1 = s1.begin(); + p2 = s2.begin(); + short dif; + while(true) { + if(p1 == s1.end()) { + if(p2 == s2.end()) + return 0; + // not at end of s2 + return -1; // s1 < s2 + } + if(p2 == s2.end()) + // not at end of s1 + return 1; // s1 > s2 + + dif = (short)(unsigned char)tolower((unsigned char)*p1) - (short)(unsigned char)tolower((unsigned char)*p2); + if(dif != 0) return dif; // dif > 0 <=> s1 > s2 + + p1++; p2++; + } +} + +bool stringcaseequal(const std::string& s1, const std::string& s2) { + if (s1.size() != s2.size()) return false; + return stringcasecmp(s1, s2) == 0; +} + +bool subStrEqual(const std::string& s1, const std::string s2, size_t p) { + if((s1.size() < p || s2.size() < p) && s1.size() != s2.size()) return false; + for(size_t i = 0; i < p && i < s1.size(); i++) + if(s1[i] != s2[i]) return false; + return true; +} + +bool subStrCaseEqual(const std::string& s1, const std::string s2, size_t p) { + if((s1.size() < p || s2.size() < p) && s1.size() != s2.size()) return false; + for(size_t i = 0; i < p && i < s1.size(); i++) + if(tolower(s1[i]) != tolower(s2[i])) return false; + return true; +} + +static size_t maxStartingEqualStr(const std::list& strs, bool caseSensitive) { + if(strs.size() == 0) return 0; + + size_t l = 0; + while(true) { + int i = 0; + char c = 0; + for(std::list::const_iterator it = strs.begin(); it != strs.end(); ++it, ++i) { + if(it->size() <= l) return l; + if(i == 0) + c = (*it)[l]; + else { + bool equal = false; + if(caseSensitive) equal = (*it)[l] == c; + else equal = tolower((*it)[l]) == tolower(c); + if(!equal) return l; + } + } + + l++; + } +} + +size_t maxStartingEqualStr(const std::list& strs) { + return maxStartingEqualStr(strs, true); +} + +size_t maxStartingCaseEqualStr(const std::list& strs) { + return maxStartingEqualStr(strs, false); +} + + +std::vector explode(const std::string& str, const std::string& delim) { + std::vector result; + + size_t delim_len = delim.size(); + std::string rest = str; + size_t pos; + while((pos = rest.find(delim)) != std::string::npos) { + result.push_back(rest.substr(0,pos)); + rest.erase(0,pos+delim_len); + } + result.push_back(rest); + + return result; +} + +// reads up to maxlen-1 chars from fp +void freadstr(std::string& result, size_t maxlen, FILE *fp) { + if (!fp) return; + + char buf[1024]; + size_t ret, c; + result = ""; + + for(size_t len = 0; len < maxlen; len += sizeof(buf)) { + c = MIN(sizeof(buf), maxlen - len); + ret = fread(buf, 1, c, fp); + if(ret > 0) + result.append(buf, ret); + if(ret < c) + break; + } +} + + +size_t fwrite(const std::string& txt, size_t len, FILE* fp) { + size_t len_of_txt = MIN(txt.size()+1, len-1); + size_t ret = fwrite(txt.c_str(), 1, len_of_txt, fp); + if(ret != len_of_txt) + return ret; + for(; len_of_txt < len; len_of_txt++) + if(fwrite("\0", 1, 1, fp) == 0) + return len_of_txt; + return len; +} + + +size_t findLastPathSep(const std::string& path) { + size_t slash = path.rfind('\\'); + size_t slash2 = path.rfind('/'); + if(slash == std::string::npos) + slash = slash2; + else if(slash2 != std::string::npos) + slash = MAX(slash, slash2); + return slash; +} + + +void stringlwr(std::string& txt) { + for(std::string::iterator i = txt.begin(); i != txt.end(); i++) + *i = tolower((unsigned char)*i); +} + +std::string stringtolower(const std::string& txt) +{ + std::string res; + for(std::string::const_iterator i = txt.begin(); i != txt.end(); i++) + res += tolower((unsigned char)*i); + return res; +} + + +bool strincludes(const std::string& str, const std::string& what) { + return str.find(what) != std::string::npos; +} + +std::string GetFileExtension(const std::string& path) { + std::string filename = GetBaseFilename(path); + size_t p = filename.rfind('.'); + if(p == std::string::npos) return ""; + return filename.substr(p+1); +} + +std::string GetBaseFilename(const std::string& filename) { + size_t p = findLastPathSep(filename); + if(p == std::string::npos) return filename; + return filename.substr(p+1); +} + +std::string GetDirName(const std::string& filename) { + size_t p = findLastPathSep(filename); + if(p == std::string::npos) return ""; + return filename.substr(0, p); +} + +std::string GetBaseFilenameWithoutExt(const std::string& filename) { + std::string f = GetBaseFilename(filename); + size_t p = f.rfind('.'); + if(p == std::string::npos) return f; + return f.substr(0,p); +} + +std::list SplitFilename(const std::string& filename, size_t numPartsFromRight) { + std::list ret; + std::string restFn = filename; + while(ret.size() < numPartsFromRight) { + std::string next = GetBaseFilename(restFn); + ret.push_front(next); + if(next.size() == restFn.size()) break; + restFn.erase(restFn.size() - next.size() - 1); + } + return ret; +} + + + +void ucfirst(std::string& text) +{ + if (text == "") return; + + text[0] = toupper(text[0]); + bool wasalpha = isalpha((unsigned char)text[0]) != 0; + + for (std::string::iterator it=text.begin()+1;it != text.end();it++) { + if (isalpha((unsigned char)*it)) { + if (wasalpha) + *it = tolower((unsigned char)*it); + else + *it = toupper((unsigned char)*it); + wasalpha = true; + } else { + wasalpha = false; + } + } + + +} + + +///////////////////////// +// Find a substring in a string +// WARNING: does NOT support UTF8, use Utf8StringCaseFind instead +size_t stringcasefind(const std::string& text, const std::string& search_for) +{ + if (text.size() == 0 || search_for.size() == 0 || search_for.size() > text.size()) + return std::string::npos; + + std::string::const_iterator it1 = text.begin(); + std::string::const_iterator it2 = search_for.begin(); + + size_t number_of_same = 0; + size_t result = 0; + + // Go through the text + while (it1 != text.end()) { + char c1 = (char)tolower((unsigned char)*it1); + char c2 = (char)tolower((unsigned char)*it2); + + // The two characters are the same + if (c1 == c2) { + number_of_same++; // If number of same characters equals to the size of the substring, we've found it! + if (number_of_same == search_for.size()) + return result - number_of_same + 1; + it2++; + } else { + number_of_same = 0; + it2 = search_for.begin(); + } + + result++; + it1++; + } + + return std::string::npos; // Not found +} + +///////////////////////// +// Find a substring in a string, starts searching from the end of the text +// WARNING: does NOT support UTF8 +size_t stringcaserfind(const std::string& text, const std::string& search_for) +{ + // HINT: simply the above one with reverse iterators + + if (text.size() == 0 || search_for.size() == 0 || search_for.size() > text.size()) + return std::string::npos; + + std::string::const_reverse_iterator it1 = text.rbegin(); + std::string::const_reverse_iterator it2 = search_for.rbegin(); + + size_t number_of_same = 0; + size_t result = 0; + + // Go through the text + while (it1 != text.rend()) { + char c1 = (char)tolower((unsigned char)*it1); + char c2 = (char)tolower((unsigned char)*it2); + + // The two characters are the same + if (c1 == c2) { + number_of_same++; // If number of same characters equals to the size of the substring, we've found it! + if (number_of_same == search_for.size()) + return text.size() - result - 1; + it2++; + } else { + number_of_same = 0; + it2 = search_for.rbegin(); + } + + result++; + it1++; + } + + return std::string::npos; // Not found +} + +///////////////// +// Get next word from a string +std::string GetNextWord(std::string::const_iterator it, const std::string& str) +{ + // Check + if (str == "" || it == str.end()) + return ""; + + // Check + if (it == str.end()) + return ""; + + // Get the word + std::string res; + while (it != str.end()) { + if (isspace((unsigned char)*it)) + return res; + res += *it; + it++; + } + + return res; +} + +//////////////////////// +// Checks for standalone < and > and replaces them with the corresponding entities +std::string HtmlEntityUnpairedBrackets(const std::string &txt) +{ + // Check + if (!txt.size()) + return ""; + + // Get the positions of unclosed brackets + bool wait_for_close = false; + size_t wait_for_close_pos = 0; + std::list unpaired_pos; + size_t curpos = 0; + for (std::string::const_iterator it = txt.begin(); it != txt.end(); it++, curpos++) { + if (*it == '<') { + if (wait_for_close) + unpaired_pos.push_back(wait_for_close_pos); + wait_for_close = true; + wait_for_close_pos = curpos; + } + + // One character after the < character + if (wait_for_close && curpos == wait_for_close_pos + 1) { + // Make sure it's a a-z A-Z letter or a slash + if (!((*it >= 'a' && *it <= 'z') || (*it >= 'A' && *it <= 'Z') || *it == '/')) { + unpaired_pos.push_back(wait_for_close_pos); + wait_for_close = false; + wait_for_close_pos = 0; + } + } + + // Closing bracket + if (wait_for_close && *it == '>') { + wait_for_close = false; + wait_for_close_pos = 0; + } + } + + if (wait_for_close) + unpaired_pos.push_back(wait_for_close_pos); + + // Replace the unclosed brackets with html entities + std::string result; + size_t startpos = 0; + for (std::list::iterator it = unpaired_pos.begin(); it != unpaired_pos.end(); it++) { + result += txt.substr(startpos, *it - startpos) + "<"; + startpos = *it + 1; + } + + // Last chunk + if (startpos < txt.size()) + result += txt.substr(startpos); + + return result; +} + + +//////////////////// +// Helper function for AutoDetectLinks +static std::string GetLink(std::string::const_iterator& it, const std::string::const_iterator& end, size_t& pos) +{ +/* +The URI standard, RFC 2396, + +; HTTP + +httpurl = "http://" hostport [ "/" hpath [ "?" search ]] +hpath = hsegment *[ "/" hsegment ] +hsegment = *[ char | ";" | ":" | "@" | "&" | "=" ] +search = *[ char | ";" | ":" | "@" | "&" | "=" ] + +lowalpha = ... +hialpha = ... +digit = ... + +alpha = lowalpha | hialpha +safe = "$" | "-" | "_" | "." | "+" +extra = "!" | "*" | "'" | "(" | ")" | "," +national = "{" | "}" | "|" | "\" | "^" | "~" | "[" | "]" | "`" +punctuation = "<" | ">" | "#" | "%" | <"> + +reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" +hex = digit | "A" | "B" | "C" | "D" | "E" | "F" | "a" | "b" | "c" | "d" | "e" | "f" +escape = "%" hex hex + +unreserved = alpha | digit | safe | extra +char = unreserved | escape +xchar = unreserved | reserved | escape +digits = 1*digit +*/ + + const std::string valid_url_chars = "/" "%" "?" // reserved + ";" ":" "@" "&" "=" // search + "$" "-" "_" "." "+" // safe + "!" "*" "'" "(" ")" "," // extra + "{" "}" "|" "\\" "^" "~" "[" "]" "`" // national + "#" "\""; // punctuation (part of) + + std::string link; + bool was_dot = false; + bool was_ques = false; + for (; it != end; it++, ++pos) { + // Breaking characters + if (!isalnum((unsigned char)*it) && valid_url_chars.find(*it) == std::string::npos) { + if (was_ques) { + link.resize(link.size() - 1); + it--; + was_ques = false; + } + break; + } + + // Multiple question marks + if (*it == '?') { + if (was_ques) { + link.resize(link.size() - 1); + it--; + was_ques = false; + break; + } + was_ques = true; + } else + was_ques = false; + + // Multiple dots + if (*it == '.') { + if (was_dot) { + link.resize(link.size() - 1); + it--; + was_dot = false; + break; + } + was_dot = true; + } else + was_dot = false; + + link += *it; + } + + if ((was_ques || was_dot) && link.size()) { + link.resize(link.size() - 1); + } + + TrimSpaces(link); + + return link; +} + +////////////////////////// +// Automatically find hyperlinks in the given text and encapsulate them with and +std::string AutoDetectLinks(const std::string& text) +{ + static const std::string prefixes[] = { "www.", "http://", "https://", "mailto:", "ftp://" }; + + std::string result; + size_t pos = 0; + bool in_tag = false; + for (std::string::const_iterator it = text.begin(); it != text.end(); it++, pos++) { + if (*it == '<') { + in_tag = true; + result += *it; + continue; + } + + if (*it == '>') { + in_tag = false; + result += *it; + continue; + } + + // Do not search inside html tags + if (in_tag) { + result += *it; + continue; + } + + for (size_t i = 0; i < sizeof(prefixes)/sizeof(std::string); ++i) { + if (text.size() - pos > prefixes[i].size() + 4) { // 4 = minimum length of the address, for example a.de + if (stringcaseequal(text.substr(pos, prefixes[i].size()), prefixes[i])) { + + // Get the link + std::string link = GetLink(it, text.end(), pos); + + // Add the link + result += "" + link + ""; + break; + } + } + } + + if (it != text.end()) + result += *it; + else + break; + } + + return result; +} + +std::string EscapeHtmlTags( const std::string & src ) +{ + std::string ret ( src ); + + replace( ret, "&", "&" ); + replace( ret, "<", "<" ); + replace( ret, ">", ">" ); + replace( ret, "\"", """ ); + replace( ret, "\'", "'" ); + + return ret; +} + +// Base 64 encoding +// Copied from wget sources +std::string Base64Encode(const std::string &data) +{ + std::string dest; + /* Conversion table. */ + static const char tbl[64] = { + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', + 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', + 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', + 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' + }; + /* Access bytes in DATA as unsigned char, otherwise the shifts below + don't work for data with MSB set. */ + const unsigned char *s = (const unsigned char *)data.c_str(); + /* Theoretical ANSI violation when length < 3. */ + const unsigned char *end = s + data.length() - 2; + + /* Transform the 3x8 bits to 4x6 bits, as required by base64. */ + for (; s < end; s += 3) + { + dest += tbl[s[0] >> 2]; + dest += tbl[((s[0] & 3) << 4) + (s[1] >> 4)]; + dest += tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)]; + dest += tbl[s[2] & 0x3f]; + } + + /* Pad the result if necessary... */ + switch (data.length() % 3) + { + case 1: + dest += tbl[s[0] >> 2]; + dest += tbl[(s[0] & 3) << 4]; + dest += '='; + dest += '='; + break; + case 2: + dest += tbl[s[0] >> 2]; + dest += tbl[((s[0] & 3) << 4) + (s[1] >> 4)]; + dest += tbl[((s[1] & 0xf) << 2)]; + dest += '='; + break; + } + + return dest; +} + +// Substitute space with + and all non-alphanum symbols with %XX +std::string UrlEncode(const std::string &data) +{ + std::string ret; + for( size_t f=0; f VectorD2 from_string< VectorD2 >(const std::string& s, bool& fail) { + std::string tmp = s; + TrimSpaces(tmp); + if(tmp.size() > 2 && tmp[0] == '(' && tmp[tmp.size()-1] == ')') + tmp = tmp.substr(1, tmp.size() - 2); + size_t f = tmp.find(','); + if(f == std::string::npos) { fail = true; return VectorD2(); } + VectorD2 v; + fail = false; + v.x = from_string(tmp.substr(0, f), fail); + if(fail) return VectorD2(); + v.y = from_string(tmp.substr(f + 1), fail); + if(fail) return VectorD2(); + return v; +} diff --git a/src/StringUtils.h b/src/StringUtils.h new file mode 100644 index 000000000..5c15e8c88 --- /dev/null +++ b/src/StringUtils.h @@ -0,0 +1,370 @@ +/* + OpenLieroX + + string utilities + + code under LGPL + created 01-05-2007 + by Albert Zeyer and Dark Charlie +*/ + +#ifndef __STRINGUTILS_H__ +#define __STRINGUTILS_H__ + +#include // for Uint32 +#include // for FILE +#include +#include +#include +#include +#include +#include +#include "Color.h" // for StrToCol +#include "Iterator.h" + +// +// C-string handling routines +// +// HINT: these are obsolete, use std::string where possible!!! + +// Secure c-string handling macros +// WARNING: don't use expressions like buf[i++] with the macros, because the "i" variable will be incremented twice in some macros! +#define fix_markend(chrarray) \ + chrarray[sizeof(chrarray)-1] = '\0'; +#define fix_strnlen(chrarray) \ + strnlen(chrarray,sizeof(chrarray)) +#define fix_strncpy(chrarray, src) \ + { strncpy(chrarray, src, sizeof(chrarray)); \ + chrarray[sizeof(chrarray)-1] = '\0'; } +#define fix_strncat(chrarray, src) \ + { size_t destlen = strnlen(chrarray, sizeof(chrarray)); \ + strncpy(&chrarray[destlen], src, sizeof(chrarray)-destlen); \ + chrarray[sizeof(chrarray)-1] = '\0'; } +#define dyn_markend(dest, len) \ + dest[len-1] = '\0'; +#define dyn_strncpy(dest, src, len) \ + { strncpy(dest, src, len); \ + dest[len-1] = '\0'; } +#define dyn_strncat(dest, src, len) \ + { size_t destlen = strnlen(dest, len); \ + strncpy(&dest[destlen], src, len-destlen); \ + dest[len-1] = '\0'; } + + +// Strnlen definition for compilers that don't have it +#if !defined(__USE_GNU) && _MSC_VER <= 1200 + inline size_t strnlen(const char *str, size_t maxlen) { + register size_t i; + for(i = 0; (i < maxlen) && str[i]; ++i) {} + return i; + } +#endif + +// Misc cross-compiler compatibility problem solutions +#ifdef WIN32 +#if (defined(_MSC_VER) && (_MSC_VER <= 1200)) + inline int strncasecmp(const char *str1, const char *str2, size_t l) { + return _strnicmp(str1, str2, l); + } +#endif +# define vsnprintf _vsnprintf +# define snprintf _snprintf +# define stricmp _stricmp +# define fcloseall _fcloseall +# define strcasecmp stricmp +#else +inline void strlwr(char* string) { + if(string) + while( *string ) { + *string = (char)tolower( *string ); + string++; + } +} +#endif + + +///////////// +// Case-insensitive comparison of two chars, behaves like stringcasecmp +int chrcasecmp(const char c1, const char c2); + +///////////// +// C-string itoa for non-windows compilers (on Windows it's defined in windows.h) +#ifndef WIN32 +// TODOL remove this +inline char* itoa(int val, char* buf, int base) { + int i = 29; // TODO: bad style + buf[i+1] = '\0'; + + do { + buf = "0123456789abcdefghijklmnopqrstuvwxyz"[val % base] + buf; + --i, val /= base; + } while(val && i); + + return &buf[i+1]; +} + +// Cross-compiler compatibility +# define stricmp strcasecmp +#endif + + +// +// C++ string (std::string) routines +// +// HINT: use these where possible + +void TrimSpaces(std::string& szLine); +bool replace(const std::string& text, const std::string& what, const std::string& with, std::string& result); +bool replace(std::string& text, const std::string& what, const std::string& with); +std::string replacemax(const std::string& text, const std::string& what, const std::string& with, std::string& result, int max); +std::string replacemax(const std::string& text, const std::string& what, const std::string& with, int max); +std::string strip(const std::string& text, int width); +bool stripdot(std::string& text, int width); +void ucfirst(std::string& text); +std::string ReadUntil(const std::string& text, char until_character = '\n'); // will return whole text if not found +std::string ReadUntil(const std::string& text, std::string::const_iterator& start, char until_character, const std::string& alternative = ""); +std::string ReadUntil(FILE* fp, char until_character = '\n'); +Color StrToCol(const std::string& str); +Color StrToCol(const std::string& str, bool& fail); +std::vector explode(const std::string& str, const std::string& delim); +void freadstr(std::string& result, size_t maxlen, FILE *fp); +size_t fwrite(const std::string& txt, size_t len, FILE* fp); +size_t findLastPathSep(const std::string& path); +void stringlwr(std::string& txt); +std::string stringtolower(const std::string& txt); +bool strincludes(const std::string& str, const std::string& what); +short stringcasecmp(const std::string& s1, const std::string& s2); +bool stringcaseequal(const std::string& s1, const std::string& s2); +bool subStrEqual(const std::string& s1, const std::string s2, size_t p); +bool subStrCaseEqual(const std::string& s1, const std::string s2, size_t p); +inline bool strStartsWith(const std::string& str, const std::string& start) { if(start.size() > str.size()) return false; return str.substr(0,start.size()) == start; } +inline bool strCaseStartsWith(const std::string& str, const std::string& start) { if(start.size() > str.size()) return false; return subStrCaseEqual(str,start,start.size()); } +size_t maxStartingEqualStr(const std::list& strs); +size_t maxStartingCaseEqualStr(const std::list& strs); +std::vector splitstring(const std::string& str, size_t maxlen, size_t maxwidth, class CFont& font); +std::string splitStringWithNewLine(const std::string& str, size_t maxlen, size_t maxwidth, class CFont& font); +std::string GetFileExtension(const std::string& filename); +std::string GetBaseFilename(const std::string& filename); +std::string GetBaseFilenameWithoutExt(const std::string& filename); +std::list SplitFilename(const std::string& filename, size_t numPartsFromRight = (size_t)-1); // splits fn by PathSep +std::string GetDirName(const std::string& filename); +size_t stringcasefind(const std::string& text, const std::string& search_for); +size_t stringcaserfind(const std::string& text, const std::string& search_for); +std::string GetNextWord(std::string::const_iterator it, const std::string& str); +std::string Base64Encode(const std::string &data); +std::string UrlEncode(const std::string &data); // Substitute space with + and all non-alphanum symbols with %XX +std::string AutoDetectLinks(const std::string& text); +std::string HtmlEntityUnpairedBrackets(const std::string &txt); +size_t GetPosByTextWidth(const std::string& text, int width, CFont *fnt); +std::string ColToHex(Color col); +std::string EscapeHtmlTags( const std::string & src ); // Escape all "<" and ">" and "&" + +bool strSeemsLikeChatCommand(const std::string& str); + +inline size_t subStrCount(const std::string& str, const std::string& substr) { + size_t c = 0, p = 0; + while((p = str.find(substr, p)) != std::string::npos) { c++; p++; } + return c; +} + + +typedef void (*PrintOutFct) (const std::string&); +inline void NullOut(const std::string&) {} + +// returns true if last char was a newline +bool PrettyPrint(const std::string& prefix, const std::string& buf, PrintOutFct printOutFct, bool firstLineWithPrefix = true); + + +Iterator::Ref HexDump(Iterator::Ref start, PrintOutFct printOutFct, size_t mark = (size_t)-1, size_t count = (size_t)-1); + + + + +inline std::string FixedWidthStr_RightFill(const std::string& str, size_t w, char c) { + assert(str.size() <= w); + return str + std::string(str.size() - w, c); +} + +inline std::string FixedWidthStr_LeftFill(const std::string& str, size_t w, char c) { + assert(str.size() <= w); + return std::string(w - str.size(), c) + str; +} + +inline void StripQuotes(std::string& value) { + if( value.size() >= 2 ) + if( value[0] == '"' && value[value.size()-1] == '"' ) + value = value.substr( 1, value.size()-2 ); +} + +//////////////////// +// Read a fixed-length C-string from a file +inline std::string freadfixedcstr(FILE *fp, size_t maxlen) { + std::string fileData; + freadstr(fileData, maxlen, fp); + return ReadUntil(fileData, '\0'); +} + +/////////////////// +// Convert a numerical position to iterator +inline std::string::iterator PositionToIterator(std::string& str, size_t pos) { + std::string::iterator res = str.begin(); + for (size_t i=0; i < pos && res != str.end(); ++i, res++) {} + return res; +} + + +// Conversion functions from string to numbers + +template +T from_string(const std::string& s, std::ios_base& (*f)(std::ios_base&), bool& failed) { + std::istringstream iss(s); T t = T(); + failed = (iss >> f >> t).fail(); + return t; +} + +template +T from_string(const std::string& s, std::ios_base& (*f)(std::ios_base&)) { + std::istringstream iss(s); T t = T(); + iss >> f >> t; + return t; +} + +template +T from_string(const std::string& s, bool& failed) { + std::istringstream iss(s); T t = T(); + failed = (iss >> t).fail(); + return t; +} + + +// Conversion functions from numbers to string + +template +std::string to_string(T val) { + std::ostringstream oss; + oss << val; + return oss.str(); +} + +template<> +inline std::string to_string(bool val) { + if(val) return "true"; else return "false"; +} + +template<> +inline std::string to_string(const char* val) { + if(val) return val; else return ""; +} + +template<> +inline bool from_string(const std::string& s, bool& fail) { + std::string s1(stringtolower(s)); + TrimSpaces(s1); + if( s1 == "true" || s1 == "yes" || s1 == "on" ) return true; + else if( s1 == "false" || s1 == "no" || s1 == "off" ) return false; + return from_string(s, fail) != 0; +} + +template<> VectorD2 from_string< VectorD2 >(const std::string& s, bool& fail); +template<> inline std::string to_string< VectorD2 >(VectorD2 v) { return "(" + to_string(v.x) + "," + to_string(v.y) + ")"; } + +template +T from_string(const std::string& s) { + bool fail; return from_string(s, fail); +} + +inline int atoi(const std::string& str) { return from_string(str); } +inline float atof(const std::string& str) { return from_string(str); } + + +inline std::string ftoa(float val, int precision = -1) +{ + std::string res = to_string(val); + if (precision != -1) { + size_t dotpos = res.find_last_of('.'); + if (dotpos == std::string::npos) { + res += '.'; + for (int i = 0; i < precision; i++) + res += '0'; + } else { + res = res.substr(0, dotpos + precision); + } + } + + return res; +} + +inline std::string itoa(unsigned long num, short base=10) { + std::string buf; + + do { + buf = "0123456789abcdefghijklmnopqrstuvwxyz"[num % base] + buf; + num /= base; + } while(num); + + return buf; +} + +// std::string itoa +inline std::string itoa(long num, short base=10) { + if(num >= 0) + return itoa((unsigned long)num, base); + else + return "-" + itoa((unsigned long)-num, base); +} + +inline std::string itoa(int num, short base=10) { return itoa((long)num,base); } +inline std::string itoa(unsigned int num, short base=10) { return itoa((unsigned long)num,base); } + +// If 64-bit long available? +#ifdef ULLONG_MAX +inline std::string itoa(unsigned long long num, short base=10) { + std::string buf; + + do { + buf = "0123456789abcdefghijklmnopqrstuvwxyz"[num % base] + buf; + num /= base; + } while(num); + + return buf; +} +#endif + +template std::string hex(_T num) { return itoa(num,16); } + + +struct simple_reversestring_hasher { + size_t operator() (const std::string& str) const { + std::string::const_reverse_iterator pos = str.rbegin(); + unsigned short nibble = 0; + size_t result = 0; + for(; pos != str.rend() && nibble < sizeof(size_t)*2; pos++, nibble++) + result += ((size_t)*pos % 16) << nibble*4; + return result; + } +}; + +struct stringcaseless { + bool operator()(const std::string& s1, const std::string& s2) const { + return stringcasecmp(s1,s2) < 0; + } +}; + + +struct const_string_iterator { + const std::string& str; + size_t pos; + + const_string_iterator(const std::string& s, size_t p = 0) : str(s), pos(p) {} + const_string_iterator& operator++() { pos++; return *this; } + const_string_iterator& operator--() { assert(pos > 0); pos--; return *this; } + + bool operator==(const const_string_iterator& i) const { + return &str == &i.str && (pos == i.pos || (pos > str.size() && i.pos > str.size())); + } + bool operator!=(const const_string_iterator& i) const { return !(*this == i); } + + char operator*() const { return str[pos]; } +}; + +#endif diff --git a/src/ThreadPool.h b/src/ThreadPool.h new file mode 100644 index 000000000..f7e2adcb7 --- /dev/null +++ b/src/ThreadPool.h @@ -0,0 +1,93 @@ +/* + * ThreadPool.h + * OpenLieroX + * + * Created by Albert Zeyer on 08.02.09. + * code under LGPL + * + */ + +#ifndef __OLX__THREADPOOL_H__ +#define __OLX__THREADPOOL_H__ + +#include +#include + +struct SDL_mutex; +struct SDL_cond; +struct SDL_Thread; +class ThreadPool; +typedef int (*ThreadFunc) (void*); +struct CmdLineIntf; + +struct Action { + virtual ~Action() {} + virtual int handle() = 0; +}; + +struct ThreadPoolItem { + ThreadPool* pool; + SDL_Thread* thread; + std::string name; + bool working; + bool finished; + bool headless; + SDL_cond* finishedSignal; + SDL_cond* readyForNewWork; + int ret; +}; + +class ThreadPool { +private: + SDL_mutex* mutex; + SDL_cond* awakeThread; + SDL_cond* threadStartedWork; + SDL_cond* threadStatusChanged; + Action* nextAction; bool nextIsHeadless; std::string nextName; + ThreadPoolItem* nextData; + bool quitting; + std::set availableThreads; + std::set usedThreads; + void prepareNewThread(); + static int threadWrapper(void* param); + SDL_mutex* startMutex; +public: + ThreadPool(); + ~ThreadPool(); + + ThreadPoolItem* start(ThreadFunc fct, void* param = NULL, const std::string& name = "unknown worker"); + // WARNING: if you set headless, you cannot use wait() and you should not save the returned ThreadPoolItem* + ThreadPoolItem* start(Action* act, const std::string& name = "unknown worker", bool headless = false); // ThreadPool will own and free the Action + bool wait(ThreadPoolItem* thread, int* status = NULL); + bool waitAll(); + void dumpState(CmdLineIntf& cli) const; +}; + +extern ThreadPool* threadPool; + +void InitThreadPool(); +void UnInitThreadPool(); + + + +template +struct _ThreadFuncWrapper { + typedef int (_T::* FuncPointer)(); + template< FuncPointer _func > + struct Wrapper { + static int wrapper(void* obj) { + return (((_T*)obj) ->* _func)(); + } + + static ThreadPoolItem* startThread(_T* const obj, const std::string& name) { + return threadPool->start((ThreadFunc)&wrapper, (void*)obj, name); + } + }; +}; + +#define StartMemberFuncInThread(T, memberfunc, name) \ +_ThreadFuncWrapper::Wrapper<&memberfunc>::startThread(this, name) + + +#endif + diff --git a/src/Unicode.h b/src/Unicode.h new file mode 100644 index 000000000..e69747237 --- /dev/null +++ b/src/Unicode.h @@ -0,0 +1,171 @@ +/* + OpenLieroX + + UTF8/Unicode conversions + + code under LGPL + created 01-05-2007 + by Albert Zeyer and Dark Charlie +*/ + +#ifndef __UNICODE_H__ +#define __UNICODE_H__ + +#include // for Uint32 +#include + +typedef Uint32 UnicodeChar; +typedef std::basic_string UnicodeString; +typedef Uint16 Utf16Char; +typedef std::basic_string Utf16String; + +struct ConversionItem { + UnicodeChar Unicode; + unsigned char Utf8[4]; + char Ascii; +}; + +#define UNKNOWN_CHARACTER ' ' // Characters not in conversion table +extern ConversionItem tConversionTable[]; + + +/////////////////////// +// Moves the iterator to next unicode character in the string, returns number of bytes skipped +template +inline size_t IncUtf8StringIterator(_Iterator1& it, const _Iterator2& last) { + if(it == last) return 0; + unsigned char c; + size_t res = 1; + for(++it; last != it; ++it, ++res) { + c = *it; + if(!(c&0x80) || ((c&0xC0) == 0xC0)) break; + } + + return res; +} + +template +inline size_t MultIncUtf8StringIterator(_Iterator& it, const _Iterator& last, size_t count) { + size_t res = 0; + for(size_t i = 0; i < count; i++) { + if(it == last) break; + res += IncUtf8StringIterator(it, last); + } + + return res; +} + +/////////////////// +// The iterator points at first byte of the UTF8 encoded character, returns number of bytes skipped +template +inline size_t DecUtf8StringIterator(_Iterator1& it, const _Iterator2& first) { + if(it == first) return 0; + size_t res = 1; + unsigned char c; + --it; + for(; first != it; --it, ++res) { + c = *it; + if(!(c&0x80) || ((c&0xC0) == 0xC0)) break; + } + + return res; +} + +template +inline _Iterator GetMultIncUtf8StringIterator(_Iterator it, const _Iterator& last, size_t count) { + MultIncUtf8StringIterator(it, last, count); + return it; +} + +inline std::string::const_iterator Utf8PositionToIterator(const std::string& str, size_t pos) { + std::string::const_iterator res = str.begin(); + MultIncUtf8StringIterator(res, str.end(), pos); + return res; +} + +inline std::string::iterator Utf8PositionToIterator(std::string& str, size_t pos) { + std::string::iterator res = str.begin(); + MultIncUtf8StringIterator(res, str.end(), pos); + return res; +} + + + +//////////////////////// +// Reads next unicode character from a UTF8 encoded string +// the iterator shows at the next character after this operation +UnicodeChar GetNextUnicodeFromUtf8(std::string::const_iterator &it, const std::string::const_iterator& last, size_t& num_skipped); +inline UnicodeChar GetNextUnicodeFromUtf8(std::string::const_iterator& it, const std::string::const_iterator& last) { + size_t tmp; return GetNextUnicodeFromUtf8(it, last, tmp); } + +inline UnicodeChar GetUnicodeFromUtf8(const std::string& str, size_t pos) { + std::string::const_iterator it = Utf8PositionToIterator(str, pos); + return GetNextUnicodeFromUtf8(it, str.end()); +} + +//////////////////// +// Gets the UTF8 representation of the unicode character (can be more bytes) +std::string GetUtf8FromUnicode(UnicodeChar ch); + + + +inline size_t Utf8StringSize(const std::string& str) { + size_t res = 0; + std::string::const_iterator it = str.begin(); + for(; it != str.end(); IncUtf8StringIterator(it, str.end())) + res++; + + return res; +} + +inline std::string Utf8SubStr(const std::string& str, size_t start, size_t n = (size_t)-1) { + if (n == (size_t)-1) + return std::string(Utf8PositionToIterator(str, start), str.end()); + else + return std::string( + Utf8PositionToIterator(str, start), + Utf8PositionToIterator(str, start + n)); +} + +inline void Utf8Erase(std::string& str, size_t start, size_t n = (size_t)-1) { + std::string::iterator it = Utf8PositionToIterator(str, start); + str.erase(it, GetMultIncUtf8StringIterator(it, str.end(), n)); +} + +inline void Utf8Insert(std::string& str, size_t start, const std::string& s) { + str.insert(Utf8PositionToIterator(str, start), s.begin(), s.end()); +} + +inline void InsertUnicodeChar(std::string& str, size_t pos, UnicodeChar ch) { + std::string tmp = GetUtf8FromUnicode(ch); + Utf8Insert(str, pos, tmp); +} + +// Uppercase/lowercase handling +UnicodeChar UnicodeToLower(UnicodeChar c); +UnicodeChar UnicodeToUpper(UnicodeChar c); + +// Conversion functions + +int FindTableIndex(UnicodeChar c); +char UnicodeCharToAsciiChar(UnicodeChar c); +std::string RemoveSpecialChars(const std::string &Utf8String); +std::string Utf16ToUtf8(const Utf16String& str); +Utf16String Utf8ToUtf16(const std::string& str); +std::string UnicodeToUtf8(const UnicodeString& str); +UnicodeString Utf8ToUnicode(const std::string& str); +#ifdef WIN32 +std::string Utf8ToSystemNative(const std::string& utf8str); +std::string SystemNativeToUtf8(const std::string& natstr); +#else // Other platforms use natively utf8 (at least we suppose so) +inline std::string Utf8ToSystemNative(const std::string& utf8str) { return utf8str; } +inline std::string SystemNativeToUtf8(const std::string& natstr) { return natstr; } +#endif + +size_t TransformRawToUtf8Pos(const std::string& text, size_t pos); +size_t TransformUtf8PosToRaw(const std::string& text, size_t pos); +inline size_t TransformRawToUtf8ToRaw(const std::string& src, size_t srcpos, const std::string& dest) { + return TransformUtf8PosToRaw(dest, TransformRawToUtf8Pos(src, srcpos)); +} + +#endif diff --git a/src/Utils.h b/src/Utils.h new file mode 100644 index 000000000..05859f2b7 --- /dev/null +++ b/src/Utils.h @@ -0,0 +1,66 @@ +/* + OpenLieroX + + various utilities + + code under LGPL + created 01-05-2007 + by Albert Zeyer and Dark Charlie +*/ + +#ifndef __UTILS_H__ +#define __UTILS_H__ + +#include // for size_t +#include +#include +#include +#include "MathLib.h" + +template +bool isSameType(const _src& obj1, const _dst& obj2) { + if(sizeof(_dst) < sizeof(_src)) return isSameType(obj2, obj1); + return dynamic_cast(&obj1) != NULL; +} + + +/* + some very basic math functions +*/ + + +template void SafeAdvance(Iter& it, size_t count, const Iter& end) { + for (size_t i=0; i < count && it != end; i++, it++) {} +} + +template +T& randomChoiceFrom(std::vector& data) { + assert(data.size() > 0); + size_t i = (size_t)GetRandomInt(data.size() - 1); + return data[i]; +} + +template +int highestBit(T d) { + for(int i = sizeof(T) * 8 - 1; i >= 0; --i) + if((1 << i) <= d) return i + 1; + return 0; +} + + +class DontCopyTag { +public: + DontCopyTag() {} +private: + DontCopyTag(const DontCopyTag&) { assert(false); } + DontCopyTag& operator=(const DontCopyTag&) { assert(false); } +}; + + +template +std::vector ListAsVector(const std::list& l) { + return std::vector(l.begin(), l.end()); +} + +#endif + diff --git a/src/eseq_ep1.cpp b/src/eseq_ep1.cpp index 9648ca69b..d7cf6ae0f 100644 --- a/src/eseq_ep1.cpp +++ b/src/eseq_ep1.cpp @@ -1,442 +1,443 @@ -/* ESEQ_EP1.C - Ending sequence for Episode 1. -*/ - -#include "keen.h" -#include "include/game.h" -#include "include/gamedo.h" -#include "include/gamepdo.h" -#include "sdl/CInput.h" -#include "sdl/CTimer.h" -#include "include/eseq_ep1.h" -#include "include/eseq_ep2.h" -#include "include/menu.h" -#include "CGraphics.h" - -#define CMD_MOVE 0 -#define CMD_WAIT 1 -#define CMD_SPAWNSPR 2 -#define CMD_REMOVESPR 3 -#define CMD_FADEOUT 4 -#define CMD_ENDOFQUEUE 5 -#define CMD_ENABLESCROLLING 6 -#define CMD_DISABLESCROLLING 7 - - -// start x,y map scroll position for eseq1_ShipFlys() -#define SHIPFLY_X 32 -#define SHIPFLY_Y 0 - -// worldmap scroll position for eseq1_ReturnsToShip() -#define WM_X 40 -#define WM_Y 540 - -#define LETTER_SHOW_SPD 30 -#define RETURNTOSHIP_WAIT_TIME 600 - -#define SPR_SHIP_RIGHT 115 -#define SPR_SHIP_LEFT 116 -#define SPR_EXCLAMATION 117 -#define SPR_QUESTION 118 -#define SHIPSPD 4 - -#define BACKHOME_SHORT_WAIT_TIME 250 - -int eseq1_ReturnsToShip(stCloneKeenPlus *pCKP) -{ -int i; - - for(i=0;iControl.levelcontrol.levels_completed[i] = 0; - - showmapatpos(80, WM_X, WM_Y, 0, pCKP); - - // draw keen next to his ship - g_pGraphics->drawSprite(168, 85, PMAPLEFTFRAME, 0); - // do not show player when we render the screen - numplayers = 1; - player[0].x = 0; - player[0].y = 0; - player[0].playframe = BlankSprite; - // all objects -> nonexistant - for(i=0;ipollEvents(); - g_pTimer->SpeedThrottle(); - } while(fade.mode != FADE_COMPLETE && !g_pInput->getPressedKey(KQUIT)); - - return 0; -} - - -void addshipqueue(int cmd, int time, int flag1) -{ - shipqueue[ShipQueuePtr].cmd = cmd; - shipqueue[ShipQueuePtr].time = time; - shipqueue[ShipQueuePtr].flag1 = flag1; - ShipQueuePtr++; -} - -int eseq1_ShipFlys(stCloneKeenPlus *pCKP) -{ -char enter,lastenterstate; -int x, y; -int scrollingon; - - scrollingon = 1; - - #define MARK_SPR_NUM 5 - initgame(pCKP); - - // set up the ship's route - ShipQueuePtr = 0; - addshipqueue(CMD_MOVE, 230, DUP); - addshipqueue(CMD_WAIT, 50, 0); - addshipqueue(CMD_MOVE, 2690, DDOWNRIGHT); - addshipqueue(CMD_WAIT, 100, 0); - addshipqueue(CMD_MOVE, 480, DDOWN); - addshipqueue(CMD_WAIT, 150, 0); - addshipqueue(CMD_SPAWNSPR, 0, SPR_QUESTION); - addshipqueue(CMD_DISABLESCROLLING, 0, 0); - addshipqueue(CMD_WAIT, 350, 0); - addshipqueue(CMD_REMOVESPR, 0, 0); - addshipqueue(CMD_WAIT, 50, 0); - addshipqueue(CMD_MOVE, 700, DLEFT); - addshipqueue(CMD_WAIT, 150, 0); - addshipqueue(CMD_SPAWNSPR, 0, SPR_EXCLAMATION); - addshipqueue(CMD_WAIT, 500, 0); - addshipqueue(CMD_REMOVESPR, 0, 0); - addshipqueue(CMD_WAIT, 50, 0); - addshipqueue(CMD_MOVE, 700, DRIGHT); - addshipqueue(CMD_WAIT, 25, 0); - addshipqueue(CMD_ENABLESCROLLING, 0, 0); - addshipqueue(CMD_MOVE, 465, DDOWN); - addshipqueue(CMD_FADEOUT, 0, 0); - addshipqueue(CMD_MOVE, 100, DDOWN); - addshipqueue(CMD_ENDOFQUEUE, 0, 0); - - showmapatpos(81, SHIPFLY_X, SHIPFLY_Y, 0, pCKP); - - objects[MARK_SPR_NUM].type = OBJ_YORP; // doesn't matter - objects[MARK_SPR_NUM].exists = 0; - objects[MARK_SPR_NUM].sprite = SPR_QUESTION; - - numplayers = 1; - // place the player at the center of mars - if (map_findtile(593, &x, &y)) - { // found the tile at the center of mars - player[0].x = ((x<<4)+1)<>CSF)-scroll_x; - objects[MARK_SPR_NUM].scry = (objects[MARK_SPR_NUM].y>>CSF)-scroll_y; - - // execute the current command in the queue - if (fade.dir != FADE_OUT) - { - switch(shipqueue[ShipQueuePtr].cmd) - { - case CMD_MOVE: - switch(shipqueue[ShipQueuePtr].flag1) - { - case DUP: - player[0].y-=SHIPSPD; - player[0].playframe = SPR_SHIP_RIGHT; - break; - case DDOWN: - player[0].y+=SHIPSPD/2; - player[0].playframe = SPR_SHIP_RIGHT; - break; - case DLEFT: - player[0].x-=SHIPSPD; - player[0].playframe = SPR_SHIP_LEFT; - break; - case DRIGHT: - player[0].x+=SHIPSPD; - player[0].playframe = SPR_SHIP_RIGHT; - break; - case DDOWNRIGHT: - player[0].x+=SHIPSPD*2; - player[0].y+=SHIPSPD*0.8; - player[0].playframe = SPR_SHIP_RIGHT; - break; - } - break; - case CMD_SPAWNSPR: - objects[MARK_SPR_NUM].sprite = shipqueue[ShipQueuePtr].flag1; - objects[MARK_SPR_NUM].exists = 1; - break; - case CMD_REMOVESPR: - objects[MARK_SPR_NUM].sprite = shipqueue[ShipQueuePtr].flag1; - objects[MARK_SPR_NUM].exists = 0; - break; - case CMD_ENABLESCROLLING: - scrollingon = 1; - break; - case CMD_DISABLESCROLLING: - scrollingon = 0; - break; - case CMD_WAIT: - break; - case CMD_FADEOUT: - if (fade.dir!=FADE_OUT) - { - fade.dir = FADE_OUT; - fade.curamt = PAL_FADE_SHADES; - fade.fadetimer = 0; - fade.mode = FADE_GO; - fade.rate = FADE_NORM; - } - break; - default: break; - } - // decrease the time remaining - if (shipqueue[ShipQueuePtr].time) - { - shipqueue[ShipQueuePtr].time--; - } - else - { // no time left on this command, go to next cmd - ShipQueuePtr++; - } - } - - if (fade.dir==FADE_OUT && fade.mode==FADE_COMPLETE) - { // we're done - return 0; - } - - enter = ( g_pInput->getPressedKey(KENTER) || g_pInput->getPressedKey(KCTRL) || g_pInput->getPressedKey(KALT) ); - if (enter) - { - if (fade.dir!=FADE_OUT) - { - fade.dir = FADE_OUT; - fade.curamt = PAL_FADE_SHADES; - fade.fadetimer = 0; - fade.mode = FADE_GO; - fade.rate = FADE_NORM; - } - } - lastenterstate = enter; - - gamedo_fades(); - gamedo_AnimatedTiles(); - - gamedo_frameskipping(pCKP); - if (scrollingon) gamedo_ScrollTriggers(0); - - g_pInput->pollEvents(); - g_pTimer->SpeedThrottle(); - } while(!g_pInput->getPressedKey(KQUIT)); - return 1; -} - -int eseq1_BackAtHome(stCloneKeenPlus *pCKP) -{ -/*int draw;*/ -int i; -char *text[10]; -char strname[40]; -char tempbuf[200]; -short textline, showtimer; -unsigned short amountshown; -signed int waittimer; -int state; -int enter, lastenterstate; -int dlgX, dlgY, dlgW, dlgH; - - #define STATE_TEXTAPPEARING 0 - #define STATE_WAITASEC 1 - #define STATE_FADING 2 - - // get pointers to all the strings we're going to be using - for(i=0;i<8;i++) - { - sprintf(strname, "EP1_ESEQ_PART2_PAGE%d", i+1); - text[i] = getstring(strname); - } - - textline = 0; - amountshown = 0; - showtimer = 0; - state = STATE_TEXTAPPEARING; - lastenterstate = 1; - waittimer = 0; - - finale_draw("finale.ck1", pCKP->GameData[pCKP->Resources.GameSelected-1].DataDirectory); - scrollx_buf = scroll_x = 0; - scrolly_buf = scroll_y = 0; - - numplayers = 1; - player[0].x = 16; - player[0].y = 16; - player[0].playframe = BlankSprite; - - dlgX = GetStringAttribute("EP1_ESEQ_PART2_PAGE1", "LEFT"); - dlgY = GetStringAttribute("EP1_ESEQ_PART2_PAGE1", "TOP"); - dlgW = GetStringAttribute("EP1_ESEQ_PART2_PAGE1", "WIDTH"); - dlgH = GetStringAttribute("EP1_ESEQ_PART2_PAGE1", "HEIGHT"); - - fade.mode = FADE_GO; - fade.rate = FADE_NORM; - fade.dir = FADE_IN; - fade.curamt = 0; - fade.fadetimer = 0; - do - { - enter = ( g_pInput->getPressedKey(KENTER) || g_pInput->getPressedKey(KCTRL) || g_pInput->getPressedKey(KALT) ); - - sb_dialogbox(dlgX, dlgY, dlgW, dlgH); - - // draw the current text line up to the amount currently shown - strcpy(tempbuf, text[textline]); - tempbuf[amountshown] = 0; - g_pGraphics->sb_font_draw( (unsigned char*) tempbuf, (dlgX+1)*8, (dlgY+1)*8); - - if (state==STATE_TEXTAPPEARING) - { - if (enter) goto fullshow; - if (showtimer > LETTER_SHOW_SPD) - { // it's time to show a new letter - amountshown++; - if (amountshown > strlen(text[textline])) - { // reached end of line - state = STATE_WAITASEC; -// if (textline==8) - // waittimer = -BACKHOME_SHORT_WAIT_TIME*3; - // else - waittimer = -BACKHOME_SHORT_WAIT_TIME*2; - } - // if the last letter shown is a dash/cr ('Billy...are you a-'), - // show the rest of the text immediately - // (for when the mom shouts "WHAT IS THIS ONE-EYED GREEN THING..." - if (text[textline][amountshown]==13 && \ - text[textline][amountshown-1]=='-') - { - fullshow: ; - amountshown = strlen(text[textline]); - state = STATE_WAITASEC; - waittimer = -BACKHOME_SHORT_WAIT_TIME*3; - } - showtimer = 0; - } else showtimer++; - - // user pressed enter - if (enter) - { // show all text immediately - - } - } - else if (state==STATE_WAITASEC) - { - if (enter) goto nextline; - if (waittimer7) - { // end of text - break; - } - } - } - } - - if (fade.dir==FADE_OUT && fade.mode==FADE_COMPLETE) - return 0; - - gamedo_fades(); - gamedo_frameskipping_blitonly(); - - lastenterstate = enter; - - g_pInput->pollEvents(); - g_pTimer->SpeedThrottle(); - if (g_pInput->getPressedKey(KQUIT)) return 1; - } while(1); - - finale_draw("finale.ck1", pCKP->GameData[pCKP->Resources.GameSelected-1].DataDirectory); - eseq_ToBeContinued(pCKP); - return 1; -} - -void eseq_ToBeContinued(stCloneKeenPlus *pCKP) -{ -int i; -char *text; -int dlgX, dlgY, dlgW, dlgH; - - // remove all objects because eseq_showmsg will call drawobjects - for(i=0;igetPressedKey(KQUIT)) return; - g_pInput->pollEvents(); - g_pTimer->SpeedThrottle(); - } while(fade.mode == FADE_GO); -} +/* ESEQ_EP1.C + Ending sequence for Episode 1. +*/ + +#include "keen.h" +#include "include/game.h" +#include "include/gamedo.h" +#include "include/gamepdo.h" +#include "sdl/CInput.h" +#include "sdl/CTimer.h" +#include "include/eseq_ep1.h" +#include "include/eseq_ep2.h" +#include "include/menu.h" +#include "CGraphics.h" +#include "StringUtils.h" + +#define CMD_MOVE 0 +#define CMD_WAIT 1 +#define CMD_SPAWNSPR 2 +#define CMD_REMOVESPR 3 +#define CMD_FADEOUT 4 +#define CMD_ENDOFQUEUE 5 +#define CMD_ENABLESCROLLING 6 +#define CMD_DISABLESCROLLING 7 + + +// start x,y map scroll position for eseq1_ShipFlys() +#define SHIPFLY_X 32 +#define SHIPFLY_Y 0 + +// worldmap scroll position for eseq1_ReturnsToShip() +#define WM_X 40 +#define WM_Y 540 + +#define LETTER_SHOW_SPD 30 +#define RETURNTOSHIP_WAIT_TIME 600 + +#define SPR_SHIP_RIGHT 115 +#define SPR_SHIP_LEFT 116 +#define SPR_EXCLAMATION 117 +#define SPR_QUESTION 118 +#define SHIPSPD 4 + +#define BACKHOME_SHORT_WAIT_TIME 250 + +int eseq1_ReturnsToShip(stCloneKeenPlus *pCKP) +{ +int i; + + for(i=0;iControl.levelcontrol.levels_completed[i] = 0; + + showmapatpos(80, WM_X, WM_Y, 0, pCKP); + + // draw keen next to his ship + g_pGraphics->drawSprite(168, 85, PMAPLEFTFRAME, 0); + // do not show player when we render the screen + numplayers = 1; + player[0].x = 0; + player[0].y = 0; + player[0].playframe = BlankSprite; + // all objects -> nonexistant + for(i=0;ipollEvents(); + g_pTimer->SpeedThrottle(); + } while(fade.mode != FADE_COMPLETE && !g_pInput->getPressedKey(KQUIT)); + + return 0; +} + + +void addshipqueue(int cmd, int time, int flag1) +{ + shipqueue[ShipQueuePtr].cmd = cmd; + shipqueue[ShipQueuePtr].time = time; + shipqueue[ShipQueuePtr].flag1 = flag1; + ShipQueuePtr++; +} + +int eseq1_ShipFlys(stCloneKeenPlus *pCKP) +{ +char enter,lastenterstate; +int x, y; +int scrollingon; + + scrollingon = 1; + + #define MARK_SPR_NUM 5 + initgame(pCKP); + + // set up the ship's route + ShipQueuePtr = 0; + addshipqueue(CMD_MOVE, 230, DUP); + addshipqueue(CMD_WAIT, 50, 0); + addshipqueue(CMD_MOVE, 2690, DDOWNRIGHT); + addshipqueue(CMD_WAIT, 100, 0); + addshipqueue(CMD_MOVE, 480, DDOWN); + addshipqueue(CMD_WAIT, 150, 0); + addshipqueue(CMD_SPAWNSPR, 0, SPR_QUESTION); + addshipqueue(CMD_DISABLESCROLLING, 0, 0); + addshipqueue(CMD_WAIT, 350, 0); + addshipqueue(CMD_REMOVESPR, 0, 0); + addshipqueue(CMD_WAIT, 50, 0); + addshipqueue(CMD_MOVE, 700, DLEFT); + addshipqueue(CMD_WAIT, 150, 0); + addshipqueue(CMD_SPAWNSPR, 0, SPR_EXCLAMATION); + addshipqueue(CMD_WAIT, 500, 0); + addshipqueue(CMD_REMOVESPR, 0, 0); + addshipqueue(CMD_WAIT, 50, 0); + addshipqueue(CMD_MOVE, 700, DRIGHT); + addshipqueue(CMD_WAIT, 25, 0); + addshipqueue(CMD_ENABLESCROLLING, 0, 0); + addshipqueue(CMD_MOVE, 465, DDOWN); + addshipqueue(CMD_FADEOUT, 0, 0); + addshipqueue(CMD_MOVE, 100, DDOWN); + addshipqueue(CMD_ENDOFQUEUE, 0, 0); + + showmapatpos(81, SHIPFLY_X, SHIPFLY_Y, 0, pCKP); + + objects[MARK_SPR_NUM].type = OBJ_YORP; // doesn't matter + objects[MARK_SPR_NUM].exists = 0; + objects[MARK_SPR_NUM].sprite = SPR_QUESTION; + + numplayers = 1; + // place the player at the center of mars + if (map_findtile(593, &x, &y)) + { // found the tile at the center of mars + player[0].x = ((x<<4)+1)<>CSF)-scroll_x; + objects[MARK_SPR_NUM].scry = (objects[MARK_SPR_NUM].y>>CSF)-scroll_y; + + // execute the current command in the queue + if (fade.dir != FADE_OUT) + { + switch(shipqueue[ShipQueuePtr].cmd) + { + case CMD_MOVE: + switch(shipqueue[ShipQueuePtr].flag1) + { + case DUP: + player[0].y-=SHIPSPD; + player[0].playframe = SPR_SHIP_RIGHT; + break; + case DDOWN: + player[0].y+=SHIPSPD/2; + player[0].playframe = SPR_SHIP_RIGHT; + break; + case DLEFT: + player[0].x-=SHIPSPD; + player[0].playframe = SPR_SHIP_LEFT; + break; + case DRIGHT: + player[0].x+=SHIPSPD; + player[0].playframe = SPR_SHIP_RIGHT; + break; + case DDOWNRIGHT: + player[0].x+=SHIPSPD*2; + player[0].y+=SHIPSPD*0.8; + player[0].playframe = SPR_SHIP_RIGHT; + break; + } + break; + case CMD_SPAWNSPR: + objects[MARK_SPR_NUM].sprite = shipqueue[ShipQueuePtr].flag1; + objects[MARK_SPR_NUM].exists = 1; + break; + case CMD_REMOVESPR: + objects[MARK_SPR_NUM].sprite = shipqueue[ShipQueuePtr].flag1; + objects[MARK_SPR_NUM].exists = 0; + break; + case CMD_ENABLESCROLLING: + scrollingon = 1; + break; + case CMD_DISABLESCROLLING: + scrollingon = 0; + break; + case CMD_WAIT: + break; + case CMD_FADEOUT: + if (fade.dir!=FADE_OUT) + { + fade.dir = FADE_OUT; + fade.curamt = PAL_FADE_SHADES; + fade.fadetimer = 0; + fade.mode = FADE_GO; + fade.rate = FADE_NORM; + } + break; + default: break; + } + // decrease the time remaining + if (shipqueue[ShipQueuePtr].time) + { + shipqueue[ShipQueuePtr].time--; + } + else + { // no time left on this command, go to next cmd + ShipQueuePtr++; + } + } + + if (fade.dir==FADE_OUT && fade.mode==FADE_COMPLETE) + { // we're done + return 0; + } + + enter = ( g_pInput->getPressedKey(KENTER) || g_pInput->getPressedKey(KCTRL) || g_pInput->getPressedKey(KALT) ); + if (enter) + { + if (fade.dir!=FADE_OUT) + { + fade.dir = FADE_OUT; + fade.curamt = PAL_FADE_SHADES; + fade.fadetimer = 0; + fade.mode = FADE_GO; + fade.rate = FADE_NORM; + } + } + lastenterstate = enter; + + gamedo_fades(); + gamedo_AnimatedTiles(); + + gamedo_frameskipping(pCKP); + if (scrollingon) gamedo_ScrollTriggers(0); + + g_pInput->pollEvents(); + g_pTimer->SpeedThrottle(); + } while(!g_pInput->getPressedKey(KQUIT)); + return 1; +} + +int eseq1_BackAtHome(stCloneKeenPlus *pCKP) +{ +/*int draw;*/ +int i; + std::string text[10]; + std::string strname; + std::string tempbuf; +short textline, showtimer; +unsigned short amountshown; +signed int waittimer; +int state; +int enter, lastenterstate; +int dlgX, dlgY, dlgW, dlgH; + + #define STATE_TEXTAPPEARING 0 + #define STATE_WAITASEC 1 + #define STATE_FADING 2 + + // get pointers to all the strings we're going to be using + for(i=0;i<8;i++) + { + strname = "EP1_ESEQ_PART2_PAGE" + itoa(i+1); + text[i] = getstring(strname); + } + + textline = 0; + amountshown = 0; + showtimer = 0; + state = STATE_TEXTAPPEARING; + lastenterstate = 1; + waittimer = 0; + + finale_draw("finale.ck1", pCKP->GameData[pCKP->Resources.GameSelected-1].DataDirectory); + scrollx_buf = scroll_x = 0; + scrolly_buf = scroll_y = 0; + + numplayers = 1; + player[0].x = 16; + player[0].y = 16; + player[0].playframe = BlankSprite; + + dlgX = GetStringAttribute("EP1_ESEQ_PART2_PAGE1", "LEFT"); + dlgY = GetStringAttribute("EP1_ESEQ_PART2_PAGE1", "TOP"); + dlgW = GetStringAttribute("EP1_ESEQ_PART2_PAGE1", "WIDTH"); + dlgH = GetStringAttribute("EP1_ESEQ_PART2_PAGE1", "HEIGHT"); + + fade.mode = FADE_GO; + fade.rate = FADE_NORM; + fade.dir = FADE_IN; + fade.curamt = 0; + fade.fadetimer = 0; + do + { + enter = ( g_pInput->getPressedKey(KENTER) || g_pInput->getPressedKey(KCTRL) || g_pInput->getPressedKey(KALT) ); + + sb_dialogbox(dlgX, dlgY, dlgW, dlgH); + + // draw the current text line up to the amount currently shown + tempbuf = text[textline]; + tempbuf.erase(amountshown); + g_pGraphics->sb_font_draw( tempbuf, (dlgX+1)*8, (dlgY+1)*8); + + if (state==STATE_TEXTAPPEARING) + { + if (enter) goto fullshow; + if (showtimer > LETTER_SHOW_SPD) + { // it's time to show a new letter + amountshown++; + if (amountshown > text[textline].size()) + { // reached end of line + state = STATE_WAITASEC; +// if (textline==8) + // waittimer = -BACKHOME_SHORT_WAIT_TIME*3; + // else + waittimer = -BACKHOME_SHORT_WAIT_TIME*2; + } + // if the last letter shown is a dash/cr ('Billy...are you a-'), + // show the rest of the text immediately + // (for when the mom shouts "WHAT IS THIS ONE-EYED GREEN THING..." + if (text[textline][amountshown]==13 && \ + text[textline][amountshown-1]=='-') + { + fullshow: ; + amountshown = text[textline].size(); + state = STATE_WAITASEC; + waittimer = -BACKHOME_SHORT_WAIT_TIME*3; + } + showtimer = 0; + } else showtimer++; + + // user pressed enter + if (enter) + { // show all text immediately + + } + } + else if (state==STATE_WAITASEC) + { + if (enter) goto nextline; + if (waittimer7) + { // end of text + break; + } + } + } + } + + if (fade.dir==FADE_OUT && fade.mode==FADE_COMPLETE) + return 0; + + gamedo_fades(); + gamedo_frameskipping_blitonly(); + + lastenterstate = enter; + + g_pInput->pollEvents(); + g_pTimer->SpeedThrottle(); + if (g_pInput->getPressedKey(KQUIT)) return 1; + } while(1); + + finale_draw("finale.ck1", pCKP->GameData[pCKP->Resources.GameSelected-1].DataDirectory); + eseq_ToBeContinued(pCKP); + return 1; +} + +void eseq_ToBeContinued(stCloneKeenPlus *pCKP) +{ +int i; + std::string text; +int dlgX, dlgY, dlgW, dlgH; + + // remove all objects because eseq_showmsg will call drawobjects + for(i=0;igetPressedKey(KQUIT)) return; + g_pInput->pollEvents(); + g_pTimer->SpeedThrottle(); + } while(fade.mode == FADE_GO); +} diff --git a/src/eseq_ep2.cpp b/src/eseq_ep2.cpp index 71e4b0ffa..167040c4d 100644 --- a/src/eseq_ep2.cpp +++ b/src/eseq_ep2.cpp @@ -1,714 +1,716 @@ -/* ESEQ_EP2.C - Ending sequence for Episode 2. -*/ - -#include "keen.h" -#include "include/game.h" -#include "include/gamedo.h" -#include "include/gamepdo.h" -#include "sdl/CTimer.h" -#include "sdl/CInput.h" -#include "sdl/sound/CSound.h" -#include "include/eseq_ep2.h" -#include "include/eseq_ep1.h" -#include "include/menu.h" -#include "include/enemyai.h" -#include "CGraphics.h" - -#define CMD_MOVE 0 -#define CMD_WAIT 1 -#define CMD_SPAWNSPR 2 -#define CMD_REMOVESPR 3 -#define CMD_FADEOUT 4 -#define CMD_ENDOFQUEUE 5 -#define CMD_ENABLESCROLLING 6 -#define CMD_DISABLESCROLLING 7 - -stShipQueue shipqueue[32]; -int ShipQueuePtr; - -#define LETTER_SHOW_SPD 30 - -// start x,y map scroll position for eseq2_TantalusRay() -#define TANTALUS_X 0 -#define TANTALUS_Y 0 - -#define TANTALUS_SPD_X 21 -#define TANTALUS_SPD_Y 9 - -#define TANTALUS_SPRITE 58 - -#define TAN_DELAY_BEFORE_FIRE 500 - -#define TAN_STATE_WAITBEFOREFIRE 0 -#define TAN_STATE_FIRING 1 -#define TAN_STATE_EARTH_EXPLODING 2 -#define TAN_STATE_CHUNKS_FLYING 3 -#define TAN_STATE_GAMEOVER 4 - -#define EARTHCHUNK_BIG_UP 64 -#define EARTHCHUNK_BIG_DN 66 -#define EARTHCHUNK_SMALL_UP 68 -#define EARTHCHUNK_SMALL_DN 70 - -int eseq2_TantalusRay(stCloneKeenPlus *pCKP) -{ -char enter,lastenterstate; -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; - fade.curamt = PAL_FADE_SHADES; - fade.fadetimer = 0; - do - { - gamedo_fades(); - g_pInput->pollEvents(); - g_pTimer->SpeedThrottle(); } while(fade.mode!=FADE_COMPLETE); - - pCKP->Control.levelcontrol.dark = 0; - g_pGraphics->initPalette(pCKP->Control.levelcontrol.dark); - - initgame(pCKP); - state = TAN_STATE_WAITBEFOREFIRE; - - showmapatpos(81,TANTALUS_X, TANTALUS_Y, 0, pCKP); - - AllPlayersInvisible(); - numplayers = 1; - player[0].hideplayer = 0; - objects[player[0].useObject].onscreen = 1; - - // place the player (which is actually the tantalus ray) at the mouth - // of the vorticon mothership - if (map_findtile(593, &x, &y)) - { // found the tile - player[0].x = ((x<<4)-1)< TAN_DELAY_BEFORE_FIRE) - { - g_pSound->playStereofromCoord(SOUND_KEEN_FIRE, PLAY_NOW, objects[o].scrx); - state = TAN_STATE_FIRING; - timer = 0; - } - else timer++; - break; - case TAN_STATE_FIRING: - - if (tantalus_animtimer>5) - { - tantalus_animframe ^= 1; - player[0].playframe = TANTALUS_SPRITE + tantalus_animframe; - } - else tantalus_animtimer++; - - player[0].x += TANTALUS_SPD_X; - player[0].y += TANTALUS_SPD_Y; - - t = getmaptileat((player[0].x>>CSF)+(sprites[TANTALUS_SPRITE].xsize/2), (player[0].y>>CSF)+(sprites[TANTALUS_SPRITE].ysize/2)); - if (t==586) - { // hit center of earth - state = TAN_STATE_EARTH_EXPLODING; - player[0].playframe = BlankSprite; - timer = 0; - spawnedcount = 0; - srand(300); - o = spawn_object(player[0].x+(24<playSound(SOUND_EARTHPOW, PLAY_NOW); - } - break; - case TAN_STATE_EARTH_EXPLODING: - if (!timer) - { - if (spawnedcount<16) o = spawn_object(player[0].x+((rand()%32)< 4) - { - objects[o].sprite = EARTHCHUNK_SMALL_DN; - } - else - { - objects[o].sprite = EARTHCHUNK_SMALL_UP; - } - } - - break; - case 6: - o = spawn_object(player[0].x+(16<playSound(SOUND_GAME_OVER, PLAY_NOW); - SetGameOver(pCKP); - break; - } - spawnedcount++; - timer = 60; - } - else timer--; - break; - case TAN_STATE_GAMEOVER: - break; - } - - if (fade.dir==FADE_OUT && fade.mode==FADE_COMPLETE) - { // we're done - return 0; - } - - enter = (g_pInput->getPressedCommand(KENTER) || g_pInput->getPressedCommand(KCTRL) || g_pInput->getPressedCommand(KALT) ); - if (enter && state==TAN_STATE_GAMEOVER) - { - if (fade.dir!=FADE_OUT) - { - fade.dir = FADE_OUT; - fade.curamt = PAL_FADE_SHADES; - fade.fadetimer = 0; - fade.rate = FADE_NORM; - fade.mode = FADE_GO; - } - } - lastenterstate = enter; - - gamedo_fades(); - if (state!=TAN_STATE_GAMEOVER) gamedo_AnimatedTiles(); - - gamedo_frameskipping(pCKP); - gamedo_enemyai(pCKP); - - if(((player[0].x>>CSF)-scroll_x) > 160-16) map_scroll_right(); - if (((player[0].y>>CSF)-scroll_y) > 100) - { - map_scroll_down(); - } - - g_pInput->pollEvents(); - g_pTimer->SpeedThrottle(); - } while(!g_pInput->getPressedCommand(KQUIT)); - return 1; -} - -void eseq2_vibrate(stCloneKeenPlus *pCKP) -{ -int xamt, yamt; -int xdir, ydir; -int vibratetimes; -//int enter,lastenterstate; -int i; -int x,y,w,h; - - vibratetimes = 0; - - #define VIBRATE_AMT 16 - #define VIBRATE_NUM_FRAMES 500 - - xamt = yamt = 0; - xdir = 0; ydir = 0; - do - { - - // undo the scroll from last time - if (!xdir) - { - for(i=0;i>CSF)-scroll_x; - objects[i].scry = (objects[i].y>>CSF)-scroll_y; - } - } - - // show the frame - gamedo_frameskipping(pCKP); - vibratetimes++; - - g_pInput->pollEvents(); - g_pTimer->SpeedThrottle(); - } while(!g_pInput->getPressedCommand(KQUIT) && vibratetimes < VIBRATE_NUM_FRAMES); - - // display the "uh-oh." - x = GetStringAttribute("EP2_AfterVibrateString", "LEFT"); - y = GetStringAttribute("EP2_AfterVibrateString", "TOP"); - w = GetStringAttribute("EP2_AfterVibrateString", "WIDTH"); - h = GetStringAttribute("EP2_AfterVibrateString", "HEIGHT"); - - eseq_showmsg(getstring("EP2_AfterVibrateString"),x,y,w,h,1, pCKP); -} - - -#define HEADFOREARTH_X 0 -#define HEADFOREARTH_Y 0 - -#define HEADFOREARTH_WAIT_TIME 600 - -#define SPR_SHIP_RIGHT_EP2 132 -#define SPR_SHIP_LEFT_EP2 133 -#define SPR_VORTICON_MOTHERSHIP 72 - -#define HEADSFOREARTH_X 3 -#define HEADSFOREARTH_Y 15 -#define HEADSFOREARTH_W 33 -#define HEADSFOREARTH_H 8 - -void eseq_showmsg(char *text, int boxleft, int boxtop, int boxwidth, int boxheight, char autodismiss, stCloneKeenPlus *pCKP) -{ -//int draw; -//int i; - -char tempbuf[1024]; -char textline, showtimer; -unsigned int amountshown; -int waittimer; -int cancel, lastcancelstate; - - textline = 0; - amountshown = 0; - showtimer = 0; - lastcancelstate = 1; - waittimer = 0; - - do - { - gamedo_fades(); - gamedo_AnimatedTiles(); - gamedo_render_drawobjects(pCKP); - - cancel = (g_pInput->getPressedCommand(KENTER) || g_pInput->getPressedCommand(KCTRL) || g_pInput->getPressedCommand(KALT)); - - // draw the text up to the amount currently shown - strcpy(tempbuf, text); - tempbuf[amountshown] = 0; - sb_dialogbox(boxleft,boxtop,boxwidth,boxheight); - g_pGraphics->sb_font_draw( (unsigned char*)tempbuf, (boxleft+1)*8, (boxtop+1+textline)*8); - - gamedo_frameskipping_blitonly(); - gamedo_render_eraseobjects(); - - if (showtimer > LETTER_SHOW_SPD) - { // it's time to show a new letter - if (amountshown < strlen(text)) - { - amountshown++; - } - showtimer = 0; - } else showtimer++; - - // user pressed enter or some other key - if (cancel && !lastcancelstate) - { - if (amountshown < strlen(text)) - { - amountshown = strlen(text); - } - else return; - } - - // when all text is shown wait a sec then return - if (autodismiss) - { - if (amountshown >= strlen(text)) - { - if (waittimer > HEADFOREARTH_WAIT_TIME) return; - waittimer++; - } - } - - - lastcancelstate = cancel; - - g_pInput->pollEvents(); - g_pTimer->SpeedThrottle(); - } while(!g_pInput->getPressedCommand(KQUIT)); - return; -} - -int eseq2_HeadsForEarth(stCloneKeenPlus *pCKP) -{ -char enter,lastenterstate; -int x, y; -int downtimer; -int afterfadewaittimer; - - initgame(pCKP); - - // set up the ship's route - ShipQueuePtr = 0; - addshipqueue(CMD_WAIT, 10, 0); - addshipqueue(CMD_MOVE, 2360, DDOWNRIGHT); - addshipqueue(CMD_FADEOUT, 0, 0); - - showmapatpos(81, HEADFOREARTH_X, HEADFOREARTH_Y, 0, pCKP); - - numplayers = 1; - // place the player near the vorticon mothership - if (map_findtile(593, &x, &y)) - { - player[0].x = ((x<<4)+2)< 6) - { - player[0].y++; - downtimer = 0; - } - else downtimer++; - break; - case CMD_WAIT: - break; - case CMD_FADEOUT: - if (fade.dir!=FADE_OUT) - { - fade.dir = FADE_OUT; - fade.curamt = PAL_FADE_SHADES; - fade.fadetimer = 0; - fade.rate = FADE_NORM; - fade.mode = FADE_GO; - } - break; - default: break; - } - // decrease the time remaining - if (shipqueue[ShipQueuePtr].time) - { - shipqueue[ShipQueuePtr].time--; - } - else - { // no time left on this command, go to next cmd - ShipQueuePtr++; - } - } - - if (fade.dir==FADE_OUT && fade.mode==FADE_COMPLETE) - { - if (afterfadewaittimer > 80) - { - return 0; - } - else afterfadewaittimer++; - } - - enter = (g_pInput->getPressedCommand(KENTER)||g_pInput->getPressedCommand(KCTRL)||g_pInput->getPressedCommand(KALT)); - if (enter && !lastenterstate) - { - if (fade.dir!=FADE_OUT) - { - fade.dir = FADE_OUT; - fade.curamt = PAL_FADE_SHADES; - fade.fadetimer = 0; - fade.rate = FADE_NORM; - fade.mode = FADE_GO; - } - } - lastenterstate = enter; - - gamedo_fades(); - gamedo_AnimatedTiles(); - - gamedo_frameskipping(pCKP); - gamedo_ScrollTriggers(0); - - g_pInput->pollEvents(); - g_pTimer->SpeedThrottle(); - } while(!g_pInput->getPressedCommand(KQUIT)); - return 1; -} - -#define LIMPSHOME_X 0 -#define LIMPSHOME_Y 344 - -int eseq2_LimpsHome(stCloneKeenPlus *pCKP) -{ -char enter,lastenterstate; -//int x, y; -int downtimer; -int afterfadewaittimer = 0; - - initgame(pCKP); - - // set up the ship's route - ShipQueuePtr = 0; - addshipqueue(CMD_WAIT, 10, 0); - addshipqueue(CMD_MOVE, 1600, DUPLEFT); - addshipqueue(CMD_FADEOUT, 0, 0); - - showmapatpos(81, LIMPSHOME_X, LIMPSHOME_Y, 0, pCKP); - - numplayers = 1; - player[0].x = (10 <<4< 80) - { - return 0; - } - else afterfadewaittimer++; - } - - enter = (g_pInput->getPressedCommand(KENTER)||g_pInput->getPressedCommand(KCTRL)||g_pInput->getPressedCommand(KALT)); - if (enter && !lastenterstate) - { - if (fade.dir!=FADE_OUT) - { - fade.dir = FADE_OUT; - fade.curamt = PAL_FADE_SHADES; - fade.fadetimer = 0; - fade.rate = FADE_NORM; - fade.mode = FADE_GO; - } - } - lastenterstate = enter; - - gamedo_fades(); - gamedo_AnimatedTiles(); - - gamedo_frameskipping(pCKP); - - g_pInput->pollEvents(); - g_pTimer->SpeedThrottle(); - } while(!g_pInput->getPressedCommand(KQUIT)); - return 1; -} - -int eseq2_SnowedOutside(stCloneKeenPlus *pCKP) -{ -int curpage; -int lastpage; -char tempstr[80]; -char *text; -//int enter, lastenterstate; -int dlgX, dlgY, dlgW, dlgH; - - scrollx_buf = scroll_x = 0; - scrolly_buf = scroll_y = 0; - finale_draw("finale.ck2", pCKP->GameData[pCKP->Resources.GameSelected-1].DataDirectory); - - curpage = 1; - fade.mode = FADE_GO; - fade.rate = FADE_NORM; - fade.dir = FADE_IN; - fade.curamt = 0; - fade.fadetimer = 0; - - numplayers = 1; - player[0].x = player[0].y = 0; - player[0].playframe = BlankSprite; - - do - { - sprintf(tempstr, "EP2_ESEQ_PART3_PAGE%d", curpage); - text = getstring(tempstr); - dlgX = GetStringAttribute(tempstr, "LEFT"); - dlgY = GetStringAttribute(tempstr, "TOP"); - dlgW = GetStringAttribute(tempstr, "WIDTH"); - dlgH = GetStringAttribute(tempstr, "HEIGHT"); - lastpage = GetStringAttribute(tempstr, "LASTPAGE"); - - eseq_showmsg(text, dlgX, dlgY, dlgW, dlgH, 1, pCKP); - if (lastpage==1) break; - - curpage++; - } while(!g_pInput->getPressedCommand(KQUIT)); - - finale_draw("finale.ck2", pCKP->GameData[pCKP->Resources.GameSelected-1].DataDirectory); - eseq_ToBeContinued(pCKP); - - return 0; -} +/* ESEQ_EP2.C + Ending sequence for Episode 2. +*/ + +#include "keen.h" +#include "include/game.h" +#include "include/gamedo.h" +#include "include/gamepdo.h" +#include "sdl/CTimer.h" +#include "sdl/CInput.h" +#include "sdl/sound/CSound.h" +#include "include/eseq_ep2.h" +#include "include/eseq_ep1.h" +#include "include/menu.h" +#include "include/enemyai.h" +#include "CGraphics.h" +#include "StringUtils.h" + + +#define CMD_MOVE 0 +#define CMD_WAIT 1 +#define CMD_SPAWNSPR 2 +#define CMD_REMOVESPR 3 +#define CMD_FADEOUT 4 +#define CMD_ENDOFQUEUE 5 +#define CMD_ENABLESCROLLING 6 +#define CMD_DISABLESCROLLING 7 + +stShipQueue shipqueue[32]; +int ShipQueuePtr; + +#define LETTER_SHOW_SPD 30 + +// start x,y map scroll position for eseq2_TantalusRay() +#define TANTALUS_X 0 +#define TANTALUS_Y 0 + +#define TANTALUS_SPD_X 21 +#define TANTALUS_SPD_Y 9 + +#define TANTALUS_SPRITE 58 + +#define TAN_DELAY_BEFORE_FIRE 500 + +#define TAN_STATE_WAITBEFOREFIRE 0 +#define TAN_STATE_FIRING 1 +#define TAN_STATE_EARTH_EXPLODING 2 +#define TAN_STATE_CHUNKS_FLYING 3 +#define TAN_STATE_GAMEOVER 4 + +#define EARTHCHUNK_BIG_UP 64 +#define EARTHCHUNK_BIG_DN 66 +#define EARTHCHUNK_SMALL_UP 68 +#define EARTHCHUNK_SMALL_DN 70 + +int eseq2_TantalusRay(stCloneKeenPlus *pCKP) +{ +char enter,lastenterstate; +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; + fade.curamt = PAL_FADE_SHADES; + fade.fadetimer = 0; + do + { + gamedo_fades(); + g_pInput->pollEvents(); + g_pTimer->SpeedThrottle(); } while(fade.mode!=FADE_COMPLETE); + + pCKP->Control.levelcontrol.dark = 0; + g_pGraphics->initPalette(pCKP->Control.levelcontrol.dark); + + initgame(pCKP); + state = TAN_STATE_WAITBEFOREFIRE; + + showmapatpos(81,TANTALUS_X, TANTALUS_Y, 0, pCKP); + + AllPlayersInvisible(); + numplayers = 1; + player[0].hideplayer = 0; + objects[player[0].useObject].onscreen = 1; + + // place the player (which is actually the tantalus ray) at the mouth + // of the vorticon mothership + if (map_findtile(593, &x, &y)) + { // found the tile + player[0].x = ((x<<4)-1)< TAN_DELAY_BEFORE_FIRE) + { + g_pSound->playStereofromCoord(SOUND_KEEN_FIRE, PLAY_NOW, objects[o].scrx); + state = TAN_STATE_FIRING; + timer = 0; + } + else timer++; + break; + case TAN_STATE_FIRING: + + if (tantalus_animtimer>5) + { + tantalus_animframe ^= 1; + player[0].playframe = TANTALUS_SPRITE + tantalus_animframe; + } + else tantalus_animtimer++; + + player[0].x += TANTALUS_SPD_X; + player[0].y += TANTALUS_SPD_Y; + + t = getmaptileat((player[0].x>>CSF)+(sprites[TANTALUS_SPRITE].xsize/2), (player[0].y>>CSF)+(sprites[TANTALUS_SPRITE].ysize/2)); + if (t==586) + { // hit center of earth + state = TAN_STATE_EARTH_EXPLODING; + player[0].playframe = BlankSprite; + timer = 0; + spawnedcount = 0; + srand(300); + o = spawn_object(player[0].x+(24<playSound(SOUND_EARTHPOW, PLAY_NOW); + } + break; + case TAN_STATE_EARTH_EXPLODING: + if (!timer) + { + if (spawnedcount<16) o = spawn_object(player[0].x+((rand()%32)< 4) + { + objects[o].sprite = EARTHCHUNK_SMALL_DN; + } + else + { + objects[o].sprite = EARTHCHUNK_SMALL_UP; + } + } + + break; + case 6: + o = spawn_object(player[0].x+(16<playSound(SOUND_GAME_OVER, PLAY_NOW); + SetGameOver(pCKP); + break; + } + spawnedcount++; + timer = 60; + } + else timer--; + break; + case TAN_STATE_GAMEOVER: + break; + } + + if (fade.dir==FADE_OUT && fade.mode==FADE_COMPLETE) + { // we're done + return 0; + } + + enter = (g_pInput->getPressedCommand(KENTER) || g_pInput->getPressedCommand(KCTRL) || g_pInput->getPressedCommand(KALT) ); + if (enter && state==TAN_STATE_GAMEOVER) + { + if (fade.dir!=FADE_OUT) + { + fade.dir = FADE_OUT; + fade.curamt = PAL_FADE_SHADES; + fade.fadetimer = 0; + fade.rate = FADE_NORM; + fade.mode = FADE_GO; + } + } + lastenterstate = enter; + + gamedo_fades(); + if (state!=TAN_STATE_GAMEOVER) gamedo_AnimatedTiles(); + + gamedo_frameskipping(pCKP); + gamedo_enemyai(pCKP); + + if(((player[0].x>>CSF)-scroll_x) > 160-16) map_scroll_right(); + if (((player[0].y>>CSF)-scroll_y) > 100) + { + map_scroll_down(); + } + + g_pInput->pollEvents(); + g_pTimer->SpeedThrottle(); + } while(!g_pInput->getPressedCommand(KQUIT)); + return 1; +} + +void eseq2_vibrate(stCloneKeenPlus *pCKP) +{ +int xamt, yamt; +int xdir, ydir; +int vibratetimes; +//int enter,lastenterstate; +int i; +int x,y,w,h; + + vibratetimes = 0; + + #define VIBRATE_AMT 16 + #define VIBRATE_NUM_FRAMES 500 + + xamt = yamt = 0; + xdir = 0; ydir = 0; + do + { + + // undo the scroll from last time + if (!xdir) + { + for(i=0;i>CSF)-scroll_x; + objects[i].scry = (objects[i].y>>CSF)-scroll_y; + } + } + + // show the frame + gamedo_frameskipping(pCKP); + vibratetimes++; + + g_pInput->pollEvents(); + g_pTimer->SpeedThrottle(); + } while(!g_pInput->getPressedCommand(KQUIT) && vibratetimes < VIBRATE_NUM_FRAMES); + + // display the "uh-oh." + x = GetStringAttribute("EP2_AfterVibrateString", "LEFT"); + y = GetStringAttribute("EP2_AfterVibrateString", "TOP"); + w = GetStringAttribute("EP2_AfterVibrateString", "WIDTH"); + h = GetStringAttribute("EP2_AfterVibrateString", "HEIGHT"); + + eseq_showmsg(getstring("EP2_AfterVibrateString"),x,y,w,h,1, pCKP); +} + + +#define HEADFOREARTH_X 0 +#define HEADFOREARTH_Y 0 + +#define HEADFOREARTH_WAIT_TIME 600 + +#define SPR_SHIP_RIGHT_EP2 132 +#define SPR_SHIP_LEFT_EP2 133 +#define SPR_VORTICON_MOTHERSHIP 72 + +#define HEADSFOREARTH_X 3 +#define HEADSFOREARTH_Y 15 +#define HEADSFOREARTH_W 33 +#define HEADSFOREARTH_H 8 + +void eseq_showmsg(const std::string& text, int boxleft, int boxtop, int boxwidth, int boxheight, char autodismiss, stCloneKeenPlus *pCKP) +{ +//int draw; +//int i; + + std::string tempbuf; +char textline, showtimer; +unsigned int amountshown; +int waittimer; +int cancel, lastcancelstate; + + textline = 0; + amountshown = 0; + showtimer = 0; + lastcancelstate = 1; + waittimer = 0; + + do + { + gamedo_fades(); + gamedo_AnimatedTiles(); + gamedo_render_drawobjects(pCKP); + + cancel = (g_pInput->getPressedCommand(KENTER) || g_pInput->getPressedCommand(KCTRL) || g_pInput->getPressedCommand(KALT)); + + // draw the text up to the amount currently shown + tempbuf = text; + tempbuf.erase(amountshown); + sb_dialogbox(boxleft,boxtop,boxwidth,boxheight); + g_pGraphics->sb_font_draw( tempbuf, (boxleft+1)*8, (boxtop+1+textline)*8); + + gamedo_frameskipping_blitonly(); + gamedo_render_eraseobjects(); + + if (showtimer > LETTER_SHOW_SPD) + { // it's time to show a new letter + if (amountshown < text.size()) + { + amountshown++; + } + showtimer = 0; + } else showtimer++; + + // user pressed enter or some other key + if (cancel && !lastcancelstate) + { + if (amountshown < text.size()) + { + amountshown = text.size(); + } + else return; + } + + // when all text is shown wait a sec then return + if (autodismiss) + { + if (amountshown >= text.size()) + { + if (waittimer > HEADFOREARTH_WAIT_TIME) return; + waittimer++; + } + } + + + lastcancelstate = cancel; + + g_pInput->pollEvents(); + g_pTimer->SpeedThrottle(); + } while(!g_pInput->getPressedCommand(KQUIT)); + return; +} + +int eseq2_HeadsForEarth(stCloneKeenPlus *pCKP) +{ +char enter,lastenterstate; +int x, y; +int downtimer; +int afterfadewaittimer; + + initgame(pCKP); + + // set up the ship's route + ShipQueuePtr = 0; + addshipqueue(CMD_WAIT, 10, 0); + addshipqueue(CMD_MOVE, 2360, DDOWNRIGHT); + addshipqueue(CMD_FADEOUT, 0, 0); + + showmapatpos(81, HEADFOREARTH_X, HEADFOREARTH_Y, 0, pCKP); + + numplayers = 1; + // place the player near the vorticon mothership + if (map_findtile(593, &x, &y)) + { + player[0].x = ((x<<4)+2)< 6) + { + player[0].y++; + downtimer = 0; + } + else downtimer++; + break; + case CMD_WAIT: + break; + case CMD_FADEOUT: + if (fade.dir!=FADE_OUT) + { + fade.dir = FADE_OUT; + fade.curamt = PAL_FADE_SHADES; + fade.fadetimer = 0; + fade.rate = FADE_NORM; + fade.mode = FADE_GO; + } + break; + default: break; + } + // decrease the time remaining + if (shipqueue[ShipQueuePtr].time) + { + shipqueue[ShipQueuePtr].time--; + } + else + { // no time left on this command, go to next cmd + ShipQueuePtr++; + } + } + + if (fade.dir==FADE_OUT && fade.mode==FADE_COMPLETE) + { + if (afterfadewaittimer > 80) + { + return 0; + } + else afterfadewaittimer++; + } + + enter = (g_pInput->getPressedCommand(KENTER)||g_pInput->getPressedCommand(KCTRL)||g_pInput->getPressedCommand(KALT)); + if (enter && !lastenterstate) + { + if (fade.dir!=FADE_OUT) + { + fade.dir = FADE_OUT; + fade.curamt = PAL_FADE_SHADES; + fade.fadetimer = 0; + fade.rate = FADE_NORM; + fade.mode = FADE_GO; + } + } + lastenterstate = enter; + + gamedo_fades(); + gamedo_AnimatedTiles(); + + gamedo_frameskipping(pCKP); + gamedo_ScrollTriggers(0); + + g_pInput->pollEvents(); + g_pTimer->SpeedThrottle(); + } while(!g_pInput->getPressedCommand(KQUIT)); + return 1; +} + +#define LIMPSHOME_X 0 +#define LIMPSHOME_Y 344 + +int eseq2_LimpsHome(stCloneKeenPlus *pCKP) +{ +char enter,lastenterstate; +//int x, y; +int downtimer; +int afterfadewaittimer = 0; + + initgame(pCKP); + + // set up the ship's route + ShipQueuePtr = 0; + addshipqueue(CMD_WAIT, 10, 0); + addshipqueue(CMD_MOVE, 1600, DUPLEFT); + addshipqueue(CMD_FADEOUT, 0, 0); + + showmapatpos(81, LIMPSHOME_X, LIMPSHOME_Y, 0, pCKP); + + numplayers = 1; + player[0].x = (10 <<4< 80) + { + return 0; + } + else afterfadewaittimer++; + } + + enter = (g_pInput->getPressedCommand(KENTER)||g_pInput->getPressedCommand(KCTRL)||g_pInput->getPressedCommand(KALT)); + if (enter && !lastenterstate) + { + if (fade.dir!=FADE_OUT) + { + fade.dir = FADE_OUT; + fade.curamt = PAL_FADE_SHADES; + fade.fadetimer = 0; + fade.rate = FADE_NORM; + fade.mode = FADE_GO; + } + } + lastenterstate = enter; + + gamedo_fades(); + gamedo_AnimatedTiles(); + + gamedo_frameskipping(pCKP); + + g_pInput->pollEvents(); + g_pTimer->SpeedThrottle(); + } while(!g_pInput->getPressedCommand(KQUIT)); + return 1; +} + +int eseq2_SnowedOutside(stCloneKeenPlus *pCKP) +{ +int curpage; +int lastpage; + std::string tempstr; + std::string text; +//int enter, lastenterstate; +int dlgX, dlgY, dlgW, dlgH; + + scrollx_buf = scroll_x = 0; + scrolly_buf = scroll_y = 0; + finale_draw("finale.ck2", pCKP->GameData[pCKP->Resources.GameSelected-1].DataDirectory); + + curpage = 1; + fade.mode = FADE_GO; + fade.rate = FADE_NORM; + fade.dir = FADE_IN; + fade.curamt = 0; + fade.fadetimer = 0; + + numplayers = 1; + player[0].x = player[0].y = 0; + player[0].playframe = BlankSprite; + + do + { + tempstr = "EP2_ESEQ_PART3_PAGE" + itoa(curpage); + text = getstring(tempstr); + dlgX = GetStringAttribute(tempstr, "LEFT"); + dlgY = GetStringAttribute(tempstr, "TOP"); + dlgW = GetStringAttribute(tempstr, "WIDTH"); + dlgH = GetStringAttribute(tempstr, "HEIGHT"); + lastpage = GetStringAttribute(tempstr, "LASTPAGE"); + + eseq_showmsg(text, dlgX, dlgY, dlgW, dlgH, 1, pCKP); + if (lastpage==1) break; + + curpage++; + } while(!g_pInput->getPressedCommand(KQUIT)); + + finale_draw("finale.ck2", pCKP->GameData[pCKP->Resources.GameSelected-1].DataDirectory); + eseq_ToBeContinued(pCKP); + + return 0; +} diff --git a/src/fileio.cpp b/src/fileio.cpp index 8f7cc704b..2d84d3c8a 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -1,536 +1,532 @@ -/* FILEIO.C - Functions responsible for loading data from files, such as the one that - decodes the level map files (loadmap()) and the one that loads in the - tile attribute data contained in ep?attr.dat (loadtileattributes()). - The functions for loading the graphics (EGALATCH&EGASPRIT) are in latch.c. -*/ - -#include "keen.h" -#include "sdl/CVideoDriver.h" -#include "sdl/sound/CSound.h" -#include "hqp/CMusic.h" -#include "include/fileio.h" -#include "include/fileio/rle.h" -#include "vorticon/CPlayer.h" -#include "CLogFile.h" -#include "CGraphics.h" -#include -#include -#include - -extern CPlayer *Player; - -unsigned int curmapx, curmapy; -unsigned char mapdone; -void addmaptile(unsigned int t) -{ - map.mapdata[curmapx][curmapy] = t; - curmapx++; - if (curmapx >= map.xsize) - { - curmapx = 0; - curmapy++; - - if (curmapy >= map.ysize) mapdone = 1; - } -} - -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; - - FILE *fp; - - // Let's define which files need to be read! - memset(p_GameData->FileList,0,MAX_NUMBER_OF_FILES*MAX_STRING_LENGTH); - if(p_GameData->Episode >= 1 && p_GameData->Episode <= 3) - { - sprintf(p_GameData->FileList[1],"keen%d.exe",p_GameData->Episode); - sprintf(p_GameData->FileList[2],"egahead.ck%d",p_GameData->Episode); - sprintf(p_GameData->FileList[3],"egasprit.ck%d",p_GameData->Episode); - sprintf(p_GameData->FileList[4],"egalatch.ck%d",p_GameData->Episode); - sprintf(p_GameData->FileList[5],"finale.ck%d",p_GameData->Episode); - - // Levels! - sprintf(p_GameData->FileList[6],"level01.ck%d",p_GameData->Episode); - sprintf(p_GameData->FileList[7],"level02.ck%d",p_GameData->Episode); - sprintf(p_GameData->FileList[8],"level03.ck%d",p_GameData->Episode); - sprintf(p_GameData->FileList[9],"level04.ck%d",p_GameData->Episode); - sprintf(p_GameData->FileList[10],"level05.ck%d",p_GameData->Episode); - sprintf(p_GameData->FileList[11],"level06.ck%d",p_GameData->Episode); - sprintf(p_GameData->FileList[12],"level07.ck%d",p_GameData->Episode); - sprintf(p_GameData->FileList[13],"level08.ck%d",p_GameData->Episode); - sprintf(p_GameData->FileList[14],"level09.ck%d",p_GameData->Episode); - sprintf(p_GameData->FileList[15],"level10.ck%d",p_GameData->Episode); - sprintf(p_GameData->FileList[16],"level11.ck%d",p_GameData->Episode); - sprintf(p_GameData->FileList[17],"level12.ck%d",p_GameData->Episode); - sprintf(p_GameData->FileList[18],"level13.ck%d",p_GameData->Episode); - sprintf(p_GameData->FileList[19],"level14.ck%d",p_GameData->Episode); - sprintf(p_GameData->FileList[20],"level15.ck%d",p_GameData->Episode); - sprintf(p_GameData->FileList[21],"level16.ck%d",p_GameData->Episode); - sprintf(p_GameData->FileList[22],"level80.ck%d",p_GameData->Episode); - sprintf(p_GameData->FileList[23],"level81.ck%d",p_GameData->Episode); - sprintf(p_GameData->FileList[24],"level90.ck%d",p_GameData->Episode); - - // Other - if(p_GameData->Episode == 1) - sprintf(p_GameData->FileList[24],"sounds.ck%d",p_GameData->Episode); - } - - // Rename all the the files in the directory to lower case - if(!renameFilenamesLowerCase(p_GameData->DataDirectory)) - { - g_pLogFile->ftextOut(PURPLE,"WARNING: There was an error while trying to format correctly the game data."); - g_pLogFile->ftextOut(PURPLE,"Please check, if you have write permissions on the game data directory and it is accessible
"); - } - - // Finally check if they really exist! - char buf[MAX_STRING_LENGTH]; - int c=0; - for(c = 0 ; c < MAX_NUMBER_OF_FILES ; c++) - { - if(p_GameData->FileList[c][0] == 0) // If there are no more files! - break; - - memset(buf,0,MAX_STRING_LENGTH*sizeof(char)); - strcat(buf,"data/"); - strcat(buf,p_GameData->DataDirectory); - if(*(p_GameData->DataDirectory) != 0) - strcat(buf,"/"); - strcat(buf,p_GameData->FileList[c]); - - if((fp = fopen(buf,"r")) != NULL) - { - fclose(fp); - } - else - { - g_pLogFile->ftextOut("Error! File \"%s\" was not found! Please add it to the configured directory.
", p_GameData->FileList[c]); - p_GameData->Episode = -1; - ok++; - } - } - - if(ok==0) - g_pLogFile->ftextOut("Game data of Episode %d is complete.
", p_GameData->Episode); - - return ok; -} - -char NessieAlreadySpawned; -void addobjectlayertile(unsigned int t, stCloneKeenPlus *pCKP) -{ -int o; - switch(t) - { - case 0: break; // blank - case 255: // player start - - //Player[0].setCoord(curmapx << 4 << CSF, curmapy << 4 << CSF); - - player[0].x = curmapx << 4 << CSF; - player[0].y = curmapy << 4 << CSF; - map.objectlayer[curmapx][curmapy] = 0; - break; - case NESSIE_PATH: // spawn nessie at first occurance of her path - if (pCKP->Control.levelcontrol.episode==3) - { - if (!NessieAlreadySpawned) - { - o = spawn_object(curmapx<<4<Control.levelcontrol.levels_completed[t&0x00ff]) - { - 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 - { - map.objectlayer[curmapx][curmapy] = t; - } - break; - } - - curmapx++; - if (curmapx >= map.xsize) - { - curmapx = 0; - curmapy++; - if (curmapy >= map.ysize) mapdone = 1; - } -} - -void addenemytile(unsigned int t, stCloneKeenPlus *pCKP) -{ -int o,x; - map.objectlayer[curmapx][curmapy] = t; - - if (t) - { - if (t==255) - { - if(curmapx >= map.xsize-2) // Edge bug. Keen would fall in some levels without this. - curmapx = 4; - - if(curmapy >= map.ysize-2) // Edge bug. Keen would fall in some levels without this. - curmapx = 4; - - //Player[0].setCoord(curmapx << 4 << CSF, ((curmapy << 4) + 8) << CSF); - - player[0].x = curmapx << 4 << CSF; - player[0].y = ((curmapy << 4) + 8) << CSF; - } - else - { - switch(t) - { - case 0: break; - case -1: break; - case 1: // yorp (ep1) vort (ep2&3) - if (pCKP->Control.levelcontrol.episode==1) - { - x = curmapx; - - if (TileProperty[map.mapdata[x][curmapy+1]][BLEFT]) x--; - spawn_object(x<<4<Control.levelcontrol.episode==1) - { - // those bastards. sometimes embedding garg's in the floor in - // the original maps. - if(TileProperty[map.mapdata[curmapx+1][curmapy+1]][BLEFT]) - { - if (pCKP->Control.levelcontrol.chglevelto==7) - { - spawn_object(curmapx<<4<Control.levelcontrol.episode==1) - { - spawn_object(curmapx<<4<Control.levelcontrol.episode==2) - { - spawn_object(curmapx<<4<Control.levelcontrol.episode==3) - { - spawn_object(curmapx<<4<Control.levelcontrol.episode==1) - spawn_object(curmapx<<4<Control.levelcontrol.episode==2) - spawn_object(curmapx<<4<Control.levelcontrol.episode==3) - spawn_object(curmapx<<4<Control.levelcontrol.episode==1) - { - o = spawn_object(curmapx<<4<Control.levelcontrol.chglevelto==13) - { - objects[o].hasbeenonscreen = 1; - } - } - else if (pCKP->Control.levelcontrol.episode==2) - spawn_object(curmapx<<4<Control.levelcontrol.episode==3) - { - if(TileProperty[map.mapdata[curmapx][curmapy+1]][BLEFT]) - { - spawn_object(curmapx<<4<Control.levelcontrol.episode==1) - { - o = spawn_object((((curmapx+1)<<4)+4)<Control.levelcontrol.episode==2) - { - o = spawn_object(curmapx<<4<Control.levelcontrol.episode==3) - { - o = spawn_object(curmapx<<4<Control.levelcontrol.episode==2) - { - o = spawn_object(curmapx<<4<Control.levelcontrol.canexit = 0; // can't exit till spark is shot - } - else - { - o = spawn_object(curmapx<<4<Control.levelcontrol.episode==3) - { - o = spawn_object(curmapx<<4<Control.levelcontrol.episode==1) - { - o = spawn_object(((curmapx<<4)-4)<Control.levelcontrol.episode==3) - { - o = spawn_object(curmapx<<4<Control.levelcontrol.episode==1) +/* FILEIO.C + Functions responsible for loading data from files, such as the one that + decodes the level map files (loadmap()) and the one that loads in the + tile attribute data contained in ep?attr.dat (loadtileattributes()). + The functions for loading the graphics (EGALATCH&EGASPRIT) are in latch.c. +*/ + +#include "keen.h" +#include "sdl/CVideoDriver.h" +#include "sdl/sound/CSound.h" +#include "hqp/CMusic.h" +#include "include/fileio.h" +#include "include/fileio/rle.h" +#include "vorticon/CPlayer.h" +#include "CLogFile.h" +#include "CGraphics.h" +#include +#include +#include +#include "StringUtils.h" + +extern CPlayer *Player; + +unsigned int curmapx, curmapy; +unsigned char mapdone; +void addmaptile(unsigned int t) +{ + map.mapdata[curmapx][curmapy] = t; + curmapx++; + if (curmapx >= map.xsize) + { + curmapx = 0; + curmapy++; + + if (curmapy >= map.ysize) mapdone = 1; + } +} + +bool renameFilenamesLowerCase(const std::string& 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.c_str()); + + 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; + + FILE *fp; + + // Let's define which files need to be read! + if(p_GameData->Episode >= 1 && p_GameData->Episode <= 3) + { + p_GameData->FileList[1] = "keen" + itoa(p_GameData->Episode) + ".exe"; + p_GameData->FileList[2] = "egahead.ck" + itoa(p_GameData->Episode); + p_GameData->FileList[3] = "egasprit.ck" + itoa(p_GameData->Episode); + p_GameData->FileList[4] = "egalatch.ck" + itoa(p_GameData->Episode); + p_GameData->FileList[5] = "finale.ck" + itoa(p_GameData->Episode); + + // Levels! + p_GameData->FileList[6] = "level01.ck" + itoa(p_GameData->Episode); + p_GameData->FileList[7] = "level02.ck" + itoa(p_GameData->Episode); + p_GameData->FileList[8] = "level03.ck" + itoa(p_GameData->Episode); + p_GameData->FileList[9] = "level04.ck" + itoa(p_GameData->Episode); + p_GameData->FileList[10] = "level05.ck" + itoa(p_GameData->Episode); + p_GameData->FileList[11] = "level06.ck" + itoa(p_GameData->Episode); + p_GameData->FileList[12] = "level07.ck" + itoa(p_GameData->Episode); + p_GameData->FileList[13] = "level08.ck" + itoa(p_GameData->Episode); + p_GameData->FileList[14] = "level09.ck" + itoa(p_GameData->Episode); + p_GameData->FileList[15] = "level10.ck" + itoa(p_GameData->Episode); + p_GameData->FileList[16] = "level11.ck" + itoa(p_GameData->Episode); + p_GameData->FileList[17] = "level12.ck" + itoa(p_GameData->Episode); + p_GameData->FileList[18] = "level13.ck" + itoa(p_GameData->Episode); + p_GameData->FileList[19] = "level14.ck" + itoa(p_GameData->Episode); + p_GameData->FileList[20] = "level15.ck" + itoa(p_GameData->Episode); + p_GameData->FileList[21] = "level16.ck" + itoa(p_GameData->Episode); + p_GameData->FileList[22] = "level80.ck" + itoa(p_GameData->Episode); + p_GameData->FileList[23] = "level81.ck" + itoa(p_GameData->Episode); + p_GameData->FileList[24] = "level90.ck" + itoa(p_GameData->Episode); + + // Other + if(p_GameData->Episode == 1) + p_GameData->FileList[24] = "sounds.ck" + itoa(p_GameData->Episode); + } + + // Rename all the the files in the directory to lower case + if(!renameFilenamesLowerCase(p_GameData->DataDirectory)) + { + g_pLogFile->ftextOut(PURPLE,"WARNING: There was an error while trying to format correctly the game data."); + g_pLogFile->ftextOut(PURPLE,"Please check, if you have write permissions on the game data directory and it is accessible
"); + } + + // Finally check if they really exist! + int c=0; + for(c = 0 ; c < MAX_NUMBER_OF_FILES ; c++) + { + if(p_GameData->FileList[c][0] == 0) // If there are no more files! + break; + + std::string buf = "data/" + p_GameData->DataDirectory; + if(p_GameData->DataDirectory != "") + buf += "/"; + buf += p_GameData->FileList[c]; + + if((fp = fopen(buf.c_str(),"r")) != NULL) + { + fclose(fp); + } + else + { + g_pLogFile->ftextOut("Error! File \"%s\" was not found! Please add it to the configured directory.
", p_GameData->FileList[c].c_str()); + p_GameData->Episode = -1; + ok++; + } + } + + if(ok==0) + g_pLogFile->ftextOut("Game data of Episode %d is complete.
", p_GameData->Episode); + + return ok; +} + +char NessieAlreadySpawned; +void addobjectlayertile(unsigned int t, stCloneKeenPlus *pCKP) +{ +int o; + switch(t) + { + case 0: break; // blank + case 255: // player start + + //Player[0].setCoord(curmapx << 4 << CSF, curmapy << 4 << CSF); + + player[0].x = curmapx << 4 << CSF; + player[0].y = curmapy << 4 << CSF; + map.objectlayer[curmapx][curmapy] = 0; + break; + case NESSIE_PATH: // spawn nessie at first occurance of her path + if (pCKP->Control.levelcontrol.episode==3) + { + if (!NessieAlreadySpawned) + { + o = spawn_object(curmapx<<4<Control.levelcontrol.levels_completed[t&0x00ff]) + { + 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 + { + map.objectlayer[curmapx][curmapy] = t; + } + break; + } + + curmapx++; + if (curmapx >= map.xsize) + { + curmapx = 0; + curmapy++; + if (curmapy >= map.ysize) mapdone = 1; + } +} + +void addenemytile(unsigned int t, stCloneKeenPlus *pCKP) +{ +int o,x; + map.objectlayer[curmapx][curmapy] = t; + + if (t) + { + if (t==255) + { + if(curmapx >= map.xsize-2) // Edge bug. Keen would fall in some levels without this. + curmapx = 4; + + if(curmapy >= map.ysize-2) // Edge bug. Keen would fall in some levels without this. + curmapx = 4; + + //Player[0].setCoord(curmapx << 4 << CSF, ((curmapy << 4) + 8) << CSF); + + player[0].x = curmapx << 4 << CSF; + player[0].y = ((curmapy << 4) + 8) << CSF; + } + else + { + switch(t) + { + case 0: break; + case -1: break; + case 1: // yorp (ep1) vort (ep2&3) + if (pCKP->Control.levelcontrol.episode==1) { - spawn_object(curmapx<<4<Control.levelcontrol.episode==3) - { - spawn_object(curmapx<<4<Control.levelcontrol.episode==3) - { - spawn_object(curmapx<<4<Control.levelcontrol.episode==3) - { - o = spawn_object(curmapx<<4<Control.levelcontrol.episode==3) - { - o = spawn_object(curmapx<<4<fadePalette(20); - g_pLogFile->ftextOut(PURPLE,"unknown enemy type %d at (%d,%d)
", t, curmapx, curmapy); - //while(g_pInput->getPressedCommand(KENTER)); - - break; - } - } - } - curmapx++; - if (curmapx >= map.xsize) - { - curmapx = 0; - curmapy++; - if (curmapy >= map.ysize) mapdone = 1; - } -} - -unsigned int fgeti(FILE *fp) { -unsigned int temp1, temp2; - temp1 = fgetc(fp); + case 2: // garg (ep1) baby vorticon (ep2&3) + if (pCKP->Control.levelcontrol.episode==1) + { + // those bastards. sometimes embedding garg's in the floor in + // the original maps. + if(TileProperty[map.mapdata[curmapx+1][curmapy+1]][BLEFT]) + { + if (pCKP->Control.levelcontrol.chglevelto==7) + { + spawn_object(curmapx<<4<Control.levelcontrol.episode==1) + { + spawn_object(curmapx<<4<Control.levelcontrol.episode==2) + { + spawn_object(curmapx<<4<Control.levelcontrol.episode==3) + { + spawn_object(curmapx<<4<Control.levelcontrol.episode==1) + spawn_object(curmapx<<4<Control.levelcontrol.episode==2) + spawn_object(curmapx<<4<Control.levelcontrol.episode==3) + spawn_object(curmapx<<4<Control.levelcontrol.episode==1) + { + o = spawn_object(curmapx<<4<Control.levelcontrol.chglevelto==13) + { + objects[o].hasbeenonscreen = 1; + } + } + else if (pCKP->Control.levelcontrol.episode==2) + spawn_object(curmapx<<4<Control.levelcontrol.episode==3) + { + if(TileProperty[map.mapdata[curmapx][curmapy+1]][BLEFT]) + { + spawn_object(curmapx<<4<Control.levelcontrol.episode==1) + { + o = spawn_object((((curmapx+1)<<4)+4)<Control.levelcontrol.episode==2) + { + o = spawn_object(curmapx<<4<Control.levelcontrol.episode==3) + { + o = spawn_object(curmapx<<4<Control.levelcontrol.episode==2) + { + o = spawn_object(curmapx<<4<Control.levelcontrol.canexit = 0; // can't exit till spark is shot + } + else + { + o = spawn_object(curmapx<<4<Control.levelcontrol.episode==3) + { + o = spawn_object(curmapx<<4<Control.levelcontrol.episode==1) + { + o = spawn_object(((curmapx<<4)-4)<Control.levelcontrol.episode==3) + { + o = spawn_object(curmapx<<4<Control.levelcontrol.episode==1) + { + spawn_object(curmapx<<4<Control.levelcontrol.episode==3) + { + spawn_object(curmapx<<4<Control.levelcontrol.episode==3) + { + spawn_object(curmapx<<4<Control.levelcontrol.episode==3) + { + o = spawn_object(curmapx<<4<Control.levelcontrol.episode==3) + { + o = spawn_object(curmapx<<4<fadePalette(20); + g_pLogFile->ftextOut(PURPLE,"unknown enemy type %d at (%d,%d)
", t, curmapx, curmapy); + //while(g_pInput->getPressedCommand(KENTER)); + + break; + } + } + } + curmapx++; + if (curmapx >= map.xsize) + { + curmapx = 0; + curmapy++; + if (curmapy >= map.ysize) mapdone = 1; + } +} + +unsigned int fgeti(FILE *fp) { +unsigned int temp1, temp2; + temp1 = fgetc(fp); temp2 = fgetc(fp); - return (temp2<<8) | temp1; -} - -unsigned long fgetl(FILE *fp) { -unsigned int temp1, temp2, temp3, temp4; - temp1 = fgetc(fp); - temp2 = fgetc(fp); - temp3 = fgetc(fp); - temp4 = fgetc(fp); - return (temp4<<24) | (temp3<<16) | (temp2<<8) | temp1; -} - -unsigned int loadmap(char filename[MAX_STRING_LENGTH], char *path, int lvlnum, int isworldmap, stCloneKeenPlus *pCKP) -{ + return (temp2<<8) | temp1; +} + +unsigned long fgetl(FILE *fp) { +unsigned int temp1, temp2, temp3, temp4; + temp1 = fgetc(fp); + temp2 = fgetc(fp); + temp3 = fgetc(fp); + temp4 = fgetc(fp); + return (temp4<<24) | (temp3<<16) | (temp2<<8) | temp1; +} + +unsigned int loadmap(const std::string& filename, const std::string& path, int lvlnum, int isworldmap, stCloneKeenPlus *pCKP) +{ FILE *fp; -char fname[256]; -int t; +int t; unsigned int c; int numruns = 0; int gottenazero; @@ -538,50 +534,47 @@ int resetcnt, resetpt; NessieAlreadySpawned = 0; map.isworldmap = isworldmap; - - char buffer[256]; - - formatPathString(buffer, path); - sprintf(fname, "%s%s", buffer, filename); - fp = fopen(fname, "rb"); + std::string buffer = formatPathString(path); + std::string fname = buffer + filename; + fp = fopen(fname.c_str(), "rb"); if (!fp) { // only record this error message on build platforms that log errors // to a file and not to the screen. - g_pLogFile->ftextOut("loadmap(): unable to open file %s
", fname); + g_pLogFile->ftextOut("loadmap(): unable to open file %s
", fname.c_str()); return 1; - } - g_pLogFile->ftextOut("loadmap(): file %s opened. Loading...
", fname); - - // decompress map RLEW data - curmapx = curmapy = mapdone = 0; - - unsigned int *filebuf; // big File Buffer for the uncompression - filebuf = (unsigned int*) malloc(500000*sizeof(int)); - - if(filebuf == NULL) - { - g_pLogFile->ftextOut("loadmap(): unable to allocate memory for unpacking the level file
", fname); - return 1; - } - - int finsize; // Final size - - finsize = unRLEW(fp, filebuf); - - c=0; - - if(finsize == -1) - { - rewind(fp); - while(!feof(fp)) - { - filebuf[c] = fgeti(fp); - c++; - } - } - + } + g_pLogFile->ftextOut("loadmap(): file %s opened. Loading...
", fname.c_str()); + + // decompress map RLEW data + curmapx = curmapy = mapdone = 0; + + unsigned int *filebuf; // big File Buffer for the uncompression + filebuf = (unsigned int*) malloc(500000*sizeof(int)); + + if(filebuf == NULL) + { + g_pLogFile->ftextOut("loadmap(): unable to allocate memory for unpacking the level file
", fname.c_str()); + return 1; + } + + int finsize; // Final size + + finsize = unRLEW(fp, filebuf); + + c=0; + + if(finsize == -1) + { + rewind(fp); + while(!feof(fp)) + { + filebuf[c] = fgeti(fp); + c++; + } + } + map.xsize = filebuf[2]; map.ysize = filebuf[3]; @@ -591,162 +584,163 @@ int resetcnt, resetpt; g_pLogFile->textOut(RED,"loadmap(): level is too big
"); return 1; } - - c=18; - - while(c < ((filebuf[9] / 2)+18)) // Check against Tilesize - { - t = filebuf[c]; - if(!mapdone) - addmaptile(t); - - if(t > 255) - { - t=0; // If there are some invalid values in the file - } - - c++; - } - + + c=18; + + while(c < ((filebuf[9] / 2)+18)) // Check against Tilesize + { + t = filebuf[c]; + if(!mapdone) + addmaptile(t); + + if(t > 255) + { + t=0; // If there are some invalid values in the file + } + + c++; + } + // now do the enemies gottenazero = 0; // get enemy/objectlayer data curmapx = curmapy = mapdone = numruns = 0; - resetcnt = resetpt = 0; - - while(!mapdone) - { - t = filebuf[c]; - - if (t==0 && !gottenazero) - { - curmapx = curmapy = 0; - gottenazero = 1; - } - if (map.isworldmap) addobjectlayertile(t, pCKP); else addenemytile(t, pCKP); - if (++resetcnt==resetpt) curmapx=curmapy=0; - - c++; - } - - free(filebuf); - - fclose(fp); - - // HQ Sounds. Load Music for a level if you have HQP - g_pMusicPlayer->stop(); - - if((fp=fopen("data/hqp/music/table.cfg","rt")) != NULL) - { - char buf1[MAX_STRING_LENGTH]; - char buf2[MAX_STRING_LENGTH]; - - memset(buf1,0,sizeof(char)*MAX_STRING_LENGTH); - memset(buf2,0,sizeof(char)*MAX_STRING_LENGTH); - - while(!feof(fp)) - { - fscanf(fp,"%s",buf1); - - if(strcmp(buf1,filename) == 0) - { - fscanf(fp,"%s",buf2); - break; - } - else - fgets(buf1,MAX_STRING_LENGTH,fp); - } - - - fclose(fp); - - if(*buf2 != 0) - { - strcpy(buf1,"data/hqp/music/"); - strcat(buf1,buf2); - g_pMusicPlayer->load(g_pSound->getAudioSpec(),buf1); - g_pMusicPlayer->play(); - } - } - - // Didn't it work? Don't matter. HQP is optional, so continue - - // install enemy stoppoints as needed - if (pCKP->Control.levelcontrol.episode==1 && lvlnum==13) + resetcnt = resetpt = 0; + + while(!mapdone) + { + t = filebuf[c]; + + if (t==0 && !gottenazero) + { + curmapx = curmapy = 0; + gottenazero = 1; + } + if (map.isworldmap) addobjectlayertile(t, pCKP); else addenemytile(t, pCKP); + if (++resetcnt==resetpt) curmapx=curmapy=0; + + c++; + } + + free(filebuf); + + fclose(fp); + + // HQ Sounds. Load Music for a level if you have HQP + g_pMusicPlayer->stop(); + + if((fp=fopen("data/hqp/music/table.cfg","rt")) != NULL) + { + static const int MAX_STRING_LENGTH = 256; + char buf1[MAX_STRING_LENGTH]; + char buf2[MAX_STRING_LENGTH]; + + memset(buf1,0,sizeof(char)*MAX_STRING_LENGTH); + memset(buf2,0,sizeof(char)*MAX_STRING_LENGTH); + + while(!feof(fp)) + { + fscanf(fp,"%s",buf1); + + if(strcmp(buf1,filename.c_str()) == 0) + { + fscanf(fp,"%s",buf2); + break; + } + else + fgets(buf1,MAX_STRING_LENGTH,fp); + } + + + fclose(fp); + + if(*buf2 != 0) + { + strcpy(buf1,"data/hqp/music/"); + strcat(buf1,buf2); + g_pMusicPlayer->load(g_pSound->getAudioSpec(),buf1); + g_pMusicPlayer->play(); + } + } + + // Didn't it work? Don't matter. HQP is optional, so continue + + // install enemy stoppoints as needed + if (pCKP->Control.levelcontrol.episode==1 && lvlnum==13) { map.objectlayer[94][13] = GARG_STOPPOINT; - map.objectlayer[113][13] = GARG_STOPPOINT; - map.objectlayer[48][6] = GARG_STOPPOINT; - map.objectlayer[80][5] = GARG_STOPPOINT; - map.objectlayer[87][5] = GARG_STOPPOINT; - map.objectlayer[39][18] = GARG_STOPPOINT; - } - else if (pCKP->Control.levelcontrol.episode==3 && lvlnum==6) - { - map.objectlayer[40][7] = BALL_NOPASSPOINT; + map.objectlayer[113][13] = GARG_STOPPOINT; + map.objectlayer[48][6] = GARG_STOPPOINT; + map.objectlayer[80][5] = GARG_STOPPOINT; + map.objectlayer[87][5] = GARG_STOPPOINT; + map.objectlayer[39][18] = GARG_STOPPOINT; + } + else if (pCKP->Control.levelcontrol.episode==3 && lvlnum==6) + { + map.objectlayer[40][7] = BALL_NOPASSPOINT; map.objectlayer[50][7] = BALL_NOPASSPOINT; } else if (pCKP->Control.levelcontrol.episode==3 && lvlnum==9) - { - map.objectlayer[45][106] = BALL_NOPASSPOINT; - - } - else if (pCKP->Control.levelcontrol.episode==3 && lvlnum==4) - { - map.objectlayer[94][17] = BALL_NOPASSPOINT; - } - - return 0; -} - -char loadstrings_AddAttr(char *attr, int stringIndex) -{ -char stAttrName[80]; -char stAttrValue[80]; -int attrvalue; -int RAMAllocSize; -char *copyPtr; + { + map.objectlayer[45][106] = BALL_NOPASSPOINT; + + } + else if (pCKP->Control.levelcontrol.episode==3 && lvlnum==4) + { + map.objectlayer[94][17] = BALL_NOPASSPOINT; + } + + return 0; +} + +char loadstrings_AddAttr(char *attr, int stringIndex) +{ +char stAttrName[80]; +char stAttrValue[80]; +int attrvalue; +int RAMAllocSize; +char *copyPtr; unsigned int i; - + // if the attribute does not have an equals sign bail - if (!strstr(attr, "=")) - { - g_pLogFile->ftextOut("loadstrings_AddAttr(): '%s' is not a valid attribute definition.
", attr); - return 1; - } - - // split the attribute up into it's name and it's value - copyPtr = stAttrName; - for(i=0;i", attr); + return 1; + } + + // split the attribute up into it's name and it's value + copyPtr = stAttrName; + for(i=0;itextOut(RED,"loadstrings_AddAttr(): Unable to allocate space for attribute name ('%s').
", stAttrName); - return 1; - } + + // malloc space for the attribute name + RAMAllocSize = strlen(stAttrName) + 1; + strings[stringIndex].attrnames[strings[stringIndex].numAttributes] = (unsigned char*) malloc(RAMAllocSize+1); + if (!strings[stringIndex].attrnames[strings[stringIndex].numAttributes]) + { + g_pLogFile->textOut(RED,"loadstrings_AddAttr(): Unable to allocate space for attribute name ('%s').
", stAttrName); + return 1; + } // copy the data into the strings structure memcpy(strings[stringIndex].attrnames[strings[stringIndex].numAttributes], stAttrName, RAMAllocSize); @@ -761,16 +755,14 @@ char loadstrings(const char *fname) { FILE *fp; char state; -unsigned char stName[80]; -unsigned char stString[1024]; -unsigned char stAttr[80]; +char stName[80]; +char stString[1024]; +char stAttr[80]; int i,c; -int nameIndex, stringIndex; +int nameIndex, stringIndex; int attrIndex=0; int waitChar, gotoState; char highlight; -int RAMSize; -char *RAMPtr; #define STSTATE_WAITCHAR 0 #define STSTATE_READNAME 1 @@ -789,8 +781,8 @@ g_pLogFile->ftextOut("loadstrings(): Opening string file '%s'.
", fname); // let us know which ones are in use (and need to be free()d at shutdown) for(i=0;iftextOut("loadstrings(): Opening string file '%s'.
", fname); /* save the string to the strings[] structure */ - // we're going to malloc() an area and copy the name, then the string, - // into it. We'll need room for both the name and the string, plus - // null-terminators for each. - RAMSize = strlen( (char*) stName) + strlen((char*)stString) + 2; - RAMPtr = (char*) malloc(RAMSize); - if (!RAMPtr) - { - g_pLogFile->ftextOut(RED,"loadstrings(): Could not allocate memory for string '%s'
", stName); - return 1; - } - - // assign our pointers - strings[numStrings].name = (unsigned char*) &RAMPtr[0]; - strings[numStrings].stringptr = (unsigned char*) &RAMPtr[strlen((char*)stName)+1]; - // copy the string info to the newly malloc()'d memory area - memcpy(strings[numStrings].name, stName, strlen((char*)stName)+1); - memcpy(strings[numStrings].stringptr, stString, strlen((char*)stString)+1); + strings[numStrings].name = stName; + strings[numStrings].stringptr = stString; numStrings++; // read the name of the next string @@ -946,95 +923,77 @@ g_pLogFile->ftextOut("loadstrings(): Opening string file '%s'.
", fname); g_pLogFile->ftextOut("loadstrings(): loaded %d strings from '%s'.
", numStrings, fname); fclose(fp); return 0; -} - -int freestrings(void) -{ +} + +int freestrings(void) +{ int i,j; int NumStringsFreed; NumStringsFreed = 0; for(i=0;i +#include +#include char loadstrings(const char *fname); unsigned int fgeti(FILE *fp); unsigned long fgetl(FILE *fp); -void formatPathString(char *output, const char *path); + std::string formatPathString(const std::string& path); -#ifdef __cplusplus -} #endif diff --git a/src/fileio/CExeFile.cpp b/src/fileio/CExeFile.cpp index 3a8542c0f..504bbcc9f 100644 --- a/src/fileio/CExeFile.cpp +++ b/src/fileio/CExeFile.cpp @@ -6,12 +6,15 @@ */ #include "CExeFile.h" -#include +#include #include #include +#include "../StringUtils.h" + + using namespace std; -CExeFile::CExeFile(int episode, char *datadirectory) { +CExeFile::CExeFile(int episode, const std::string& datadirectory) { m_episode = episode; m_datadirectory = datadirectory; m_data = NULL; @@ -23,12 +26,11 @@ CExeFile::~CExeFile() { bool CExeFile::readData() { - char filename[256]; unsigned char *m_data_temp; - sprintf(filename, "data/%skeen%d.exe", m_datadirectory, m_episode); + std::string filename = "data/" + m_datadirectory + "keen" + itoa(m_episode) + ".exe"; - ifstream File(filename,ios::binary); + std::ifstream File(filename.c_str(),ios::binary); if(!File) return false; diff --git a/src/fileio/CExeFile.h b/src/fileio/CExeFile.h index 347c3074d..664f0af54 100644 --- a/src/fileio/CExeFile.h +++ b/src/fileio/CExeFile.h @@ -12,11 +12,11 @@ #define CEXEFILE_H_ #include -using namespace std; +#include class CExeFile { public: - CExeFile(int episode, char *datadirectory); + CExeFile(int episode, const std::string& datadirectory); virtual ~CExeFile(); bool readData(); @@ -27,10 +27,10 @@ private: int m_datasize; int m_episode; unsigned char *m_data; - char *m_datadirectory; + std::string m_datadirectory; int get_bit(int *p_bit_count, unsigned char *fin, int *posin); - int unlzexe(unsigned char *fin, vector *outbuffer); + int unlzexe(unsigned char *fin, std::vector *outbuffer); }; #endif /* CEXEFILE_H_ */ diff --git a/src/fileio/CParser.cpp b/src/fileio/CParser.cpp index c717d8de8..c7511b46b 100644 --- a/src/fileio/CParser.cpp +++ b/src/fileio/CParser.cpp @@ -83,7 +83,7 @@ bool CParser::saveParseFile(void) // open, write on the file and close if((fp=fopen(CONFIGFILENAME,"wt"))) { - list::iterator i; + std::list::iterator i; for(i=m_filebuffer.begin() ; i != m_filebuffer.end() ; ++i ) fprintf(fp,"%s",*i); @@ -104,7 +104,7 @@ bool CParser::saveParseFile(void) // open, write on the file and close int CParser::getIntValue(const char *keyword, const char *category) { // The getter will search for category and than for keyword. After that, read the value and return it! - list::iterator i; + std::list::iterator i; char *line; @@ -152,7 +152,7 @@ void CParser::saveIntValue(const char *keyword, const char *category,int value) // 2.- category exists, but keyword not // 3.- category and keyword exist, only the value must be changed - list::iterator i; + std::list::iterator i; char *line; diff --git a/src/fileio/CParser.h b/src/fileio/CParser.h index 3d460fcfd..2d157bf3b 100644 --- a/src/fileio/CParser.h +++ b/src/fileio/CParser.h @@ -10,7 +10,6 @@ #include #include -using namespace std; class CParser { @@ -43,7 +42,7 @@ public: private: bool m_isOpen; - list m_filebuffer; + std::list m_filebuffer; }; diff --git a/src/fileio/CPatcher.cpp b/src/fileio/CPatcher.cpp index 5fd930460..2c9091b4f 100644 --- a/src/fileio/CPatcher.cpp +++ b/src/fileio/CPatcher.cpp @@ -10,11 +10,11 @@ #include #include -CPatcher::CPatcher(int episode, int version,unsigned char *data, char *datadir) { +CPatcher::CPatcher(int episode, int version,unsigned char *data, const std::string& datadir) { m_episode = episode; m_version = version; m_data = data; - strcpy(m_datadirectory, datadir); + m_datadirectory = datadir; } CPatcher::~CPatcher() { @@ -35,7 +35,7 @@ void CPatcher::patchMemory() // change to the proper directory chdir("data"); - chdir(m_datadirectory); + chdir(m_datadirectory.c_str()); // TODO: Extend this part further with more commands while(!m_TextList.empty()) @@ -108,7 +108,7 @@ bool CPatcher::loadPatchfile() { bool ret = false; chdir("data"); - chdir(m_datadirectory); + chdir(m_datadirectory.c_str()); // Detect the patchfile DIR *dir = opendir("."); struct dirent *dp; @@ -122,7 +122,7 @@ bool CPatcher::loadPatchfile() // The file was found! now read it into the memory! char* buf; - ifstream Patchfile(dp->d_name); + std::ifstream Patchfile(dp->d_name); while(!Patchfile.eof()) { @@ -157,12 +157,12 @@ bool CPatcher::loadPatchfile() return ret; } -void CPatcher::patchMemfromFile(const char *patch_file_name, int offset) +void CPatcher::patchMemfromFile(const std::string& patch_file_name, int offset) { unsigned char *buf_to_patch; unsigned char byte; - ifstream Patchfile(patch_file_name, ios::binary); + std::ifstream Patchfile(patch_file_name.c_str(), std::ios::binary); if(!Patchfile) return; diff --git a/src/fileio/CPatcher.h b/src/fileio/CPatcher.h index b47565619..e4de4427c 100644 --- a/src/fileio/CPatcher.h +++ b/src/fileio/CPatcher.h @@ -9,15 +9,15 @@ #define CPATCHER_H_ #include -using namespace std; +#include class CPatcher { public: - CPatcher(int episode, int version,unsigned char *data, char *datadir); + CPatcher(int episode, int version,unsigned char *data, const std::string& datadir); virtual ~CPatcher(); void patchMemory(); - void patchMemfromFile(const char *patch_file_name, int offset); + void patchMemfromFile(const std::string& patch_file_name, int offset); private: @@ -26,9 +26,9 @@ private: int m_episode; int m_version; unsigned char *m_data; - char m_datadirectory[256]; - - list m_TextList; + std::string m_datadirectory; + + std::list m_TextList; }; diff --git a/src/fileio/story.cpp b/src/fileio/story.cpp index dddb22231..84e33f50b 100644 --- a/src/fileio/story.cpp +++ b/src/fileio/story.cpp @@ -12,24 +12,19 @@ #include "../include/fileio.h" #include "../fileio/CExeFile.h" #include "../CLogFile.h" +#include "../StringUtils.h" -int readStoryText(char **ptext, int episode, char *path) +int readStoryText(char **ptext, int episode, const std::string& path) { + std::string buf2 = formatPathString(path); + std::string buf = buf2 + "storytxt.ck" + itoa(episode); + FILE *fp; - char buf[256]; - char buf2[256]; - - memset(buf,0,256*sizeof(char)); - - formatPathString(buf2,path); - - sprintf(buf,"%sstorytxt.ck%d",buf2,episode); - - if((fp=fopen(buf,"rt"))==NULL) + if((fp=fopen(buf.c_str(),"rt"))==NULL) { - sprintf(buf,"%skeen%d.exe",buf2,episode); + buf = buf2 + "keen" + itoa(episode) + ".exe"; - if((fp=fopen(buf,"rb"))!=NULL) + if((fp=fopen(buf.c_str(),"rb"))!=NULL) { unsigned char *filebuf; int startflag=0, endflag=0; // where story begins and ends! diff --git a/src/finale.cpp b/src/finale.cpp index bab9e885f..b470884ad 100644 --- a/src/finale.cpp +++ b/src/finale.cpp @@ -1,135 +1,133 @@ -/* FINALE.C - Code for displaying the FINALE.CK? files. - Thanks to Andrew Durdin for FIN2BMP, from which I got - the decompression algorithm. -*/ - -#include "keen.h" -#include "include/fileio.h" -#include "CGraphics.h" - -int finale_x; -int finale_y; -int finale_count; -int finale_planecol; -int finale_plane_length; -int finale_done; - -// used internally by finale_draw() -void finale_plot(int pix) -{ -int mask; - - mask = 128; - do - { - if (pix & mask) - { - if (finale_planecol==1) - { - g_pGraphics->sb_setpixel(finale_x, finale_y, finale_planecol); - } - else - { // merge with previous planes - g_pGraphics->sb_setpixel(finale_x, finale_y, g_pGraphics->sb_getpixel(finale_x, finale_y) | finale_planecol); - } - } - else if (finale_planecol==1) - { - g_pGraphics->sb_setpixel(finale_x, finale_y, 0); - } - - finale_x++; - if (finale_x > 319) - { - finale_x = 0; - finale_y++; - } - - finale_count++; - if (finale_count >= finale_plane_length) - { - finale_x = finale_y = 0; - finale_count = 0; - finale_planecol <<= 1; - if (finale_planecol > 8) finale_done = 1; - } - - if (mask==1) - { - return; - } - else - { - mask >>= 1; - } - - } while(1); - -} - -// draws a finale.ck? file into the upper-left corner of the scrollbuffer -void finale_draw(const char *filename, const char *path) -{ -char fname[256]; -FILE *fp; -int cmdbyte; -int bytecount; -int repeatbyte; -int i; -char buffer[256]; - - - formatPathString(buffer,path); - - - map_unregister_all_animtiles(); - - sprintf(fname, "%s%s", buffer,filename); - fp = fopen(fname, "rb"); - if (!fp) - { - crashflag = 1; - why_term_ptr = "finale_draw(): cannot open finake.ck? file."; - return; - } - - finale_plane_length = fgetl(fp)*2; //length of a plane when decompressed - finale_planecol = 1; - finale_x = finale_y = 0; - finale_count = 0; - finale_done = 0; - - /* decompress/draw the image */ - do - { - cmdbyte = fgetc(fp); - if (cmdbyte<0) - { // EOF - return; - } - - if (cmdbyte & 0x80) - { - //N + 1 bytes of data follows - bytecount = (cmdbyte & 0x7F) + 1; - for(i=0;isb_setpixel(finale_x, finale_y, finale_planecol); + } + else + { // merge with previous planes + g_pGraphics->sb_setpixel(finale_x, finale_y, g_pGraphics->sb_getpixel(finale_x, finale_y) | finale_planecol); + } + } + else if (finale_planecol==1) + { + g_pGraphics->sb_setpixel(finale_x, finale_y, 0); + } + + finale_x++; + if (finale_x > 319) + { + finale_x = 0; + finale_y++; + } + + finale_count++; + if (finale_count >= finale_plane_length) + { + finale_x = finale_y = 0; + finale_count = 0; + finale_planecol <<= 1; + if (finale_planecol > 8) finale_done = 1; + } + + if (mask==1) + { + return; + } + else + { + mask >>= 1; + } + + } while(1); + +} + +// draws a finale.ck? file into the upper-left corner of the scrollbuffer +void finale_draw(const std::string& filename, const std::string& path) +{ +FILE *fp; +int cmdbyte; +int bytecount; +int repeatbyte; +int i; + + + std::string buffer = formatPathString(path); + + + map_unregister_all_animtiles(); + + std::string fname = buffer + filename; + fp = fopen(fname.c_str(), "rb"); + if (!fp) + { + crashflag = 1; + why_term_ptr = "finale_draw(): cannot open finake.ck? file."; + return; + } + + finale_plane_length = fgetl(fp)*2; //length of a plane when decompressed + finale_planecol = 1; + finale_x = finale_y = 0; + finale_count = 0; + finale_done = 0; + + /* decompress/draw the image */ + do + { + cmdbyte = fgetc(fp); + if (cmdbyte<0) + { // EOF + return; + } + + if (cmdbyte & 0x80) + { + //N + 1 bytes of data follows + bytecount = (cmdbyte & 0x7F) + 1; + for(i=0;i + +// gamedo.c +int gamedo_ScrollTriggers(int theplayer); +void gamedo_AnimatedTiles(void); + +void gamedo_render_eraseobjects(void); +void gamedo_render_drawdebug(void); +void gamedo_render_erasedebug(void); +void gamedo_fades(void); + +// gamepdo.c + + +// gamepdowm.c +//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, int *levels_completed); + +// game.c +//void SetGameOver(void); +void overrun_detect(void); +void scrolltest(void); +//void gameloop_initialize(void); +void give_keycard(int doortile, int p); +void take_keycard(int doortile, int p); +//void open_door(int doortile, int doorsprite, int mpx, int mpy, int cp, stCloneKeenPlus *pCKP) +void extralifeat(int p); +char spawn_object(int x, int y, int otype); +void common_enemy_ai(int o); +char hitdetect(int object1, int object2); +void freezeplayer(int theplayer); +void unregister_animtiles(int tile); +//void endlevel(int success, stCloneKeenPlus *pCKP) +char checkobjsolid(unsigned int x, unsigned int y, unsigned int cp); +//void initsprites(stCloneKeenPlus *pCKP) +void CopyTileToSprite(int t, int s, int ntilestocopy, int transparent); +void GiveAnkh(int cp); +// map.c +void map_scroll_right(void); +void map_scroll_left(void); +void map_scroll_down(void); +void map_scroll_up(void); +void map_draw_vstripe(unsigned int x, unsigned int mpx); +void map_draw_hstripe(unsigned int y, unsigned int mpy); +void nosb_map_draw_vstripe(unsigned int x, unsigned int mapx); +unsigned int getmaptileat(unsigned int x, unsigned int y); +unsigned int getlevelat(unsigned int x, unsigned int y); +void drawmap(void); +void map_unregister_all_animtiles(void); +void map_deanimate(int x, int y); +int map_isanimated(int x, int y); +void map_animate(int x, int y); +char map_findobject(unsigned int obj, int *xout, int *yout); +char map_findtile(unsigned int tile, int *xout, int *yout); +void map_redraw(void); +void map_chgtile(unsigned int x,unsigned int y, int newtile); +// dos\snddrv.c +void SoundDrv_Stop(void); +void sound_do(void); +void sound_play_stereo(int snd, char mode, short balance); +void sound_play_stereo_from_coord(int snd, char mode, unsigned int xcoordinate); +void sound_play(int snd, char mode); +char sound_is_playing(int snd); +void sound_stop(int snd); +void sound_stop_all(void); +void sound_pause(void); +void sound_resume(void); +char sound_extraction_of_exe_files(char *inputpath, int episode); + +// graphics.c +void DrawBitmap(int xa, int ya, int b); +void freemem(void); +void Graphics_Stop(void); +void /*inline*/ sb_setpixel(int x, int y, unsigned char c); +unsigned char sb_getpixel(int x, int y); +void drawtile(int x, int y, unsigned int t); +void drawtile_direct(int x, int y, unsigned int t); +void drawtilewithmask(int x, int y, unsigned int til, unsigned int tmask); +void drawprioritytile(int x, int y, unsigned int til); +void drawsprite_direct(int x, int y, unsigned int t); +void drawsprite(int x, int y, unsigned int s, int objectnum); +void erasesprite(int x, int y, unsigned int s, int objectnum); +void drawcharacter(int x, int y, int f); +void sb_drawcharacter(int x, int y, int f); +void sb_drawcharacterwithmask(int x, int y, int f, char mask); +void sb_drawcolorcharacter(int x, int y, int f, unsigned short colour, unsigned short bgcolour); +void sb_drawcharacterinverse(int x, int y, int f); +void save_area(int x1, int y1, int x2, int y2); +void restore_area(int x1, int y1, int x2, int y2); +void setvideomode(unsigned char mode); +void addpal(int c, int r, int g, int b); +void pal_init(int dark); +void pal_fade(int fadeamt); +void pal_apply(void); +void font_draw(unsigned char *text, int xoff, int yoff, int highlight); +void sb_font_draw(const unsigned char *text, int xoff, int yoff); +void sb_mask_font_draw(unsigned char *text, int xoff, int yoff, char mask); +void sb_color_font_draw(unsigned char *text, int xoff, int yoff, unsigned int colour, unsigned short bgcolour); +void sb_font_draw_inverse(unsigned char *text, int xoff, int yoff); +// viddrv.c +// fileio.c +//void addmaptile(unsigned int t, stCloneKeenPlus *pCKP); +//void addenemytile(unsigned int t, stCloneKeenPlus *pCKP); +//unsigned int fgeti(FILE *fp); +//unsigned long fgetl(FILE *fp); +//unsigned int loadmap(char *filename, char *path, int lvlnum, int isworldmap); +#include "fileio.h" + +bool loadtileattributes(int episode, int version, unsigned char *filebuf); +int freestrings(void); +std::string getstring(const std::string& name); +int GetStringAttribute(const std::string& stringName, const char *attrName); + +// keydrv.c +char KeyDrv_Start(void); +void KeyDrv_Stop(void); + +// misc.c +void banner(void); +void dialogbox(int x1, int y1, int w, int h); +void sb_dialogbox(int x1, int y1, int w, int h); +void statusbox(void); + +int savegameiswm(char *fname); +void usage(void); +void radar(void); +void SetAllCanSupportPlayer(int o, int state); +void AllPlayersInvisible(void); + +// menu.c +int GetBitmapNumberFromName(const char *bmname); + + +// eseq_ep1.c +void addshipqueue(int cmd, int time, int flag1); + +// latch.c +//char latch_loadgraphics(int episode, char *path); + +// sglre.c +void sgrle_reset(void); +void sgrle_compress(FILE *fp, unsigned char *ptr, unsigned long nbytes); +void sgrle_decompress(FILE *fp, unsigned char *ptr, unsigned long nbytes); +unsigned char sgrle_get_next_byte(FILE *fp); + +// lz.c +char lz_decompress(FILE *lzfile, unsigned char *outbuffer); + +// finale.c +void finale_draw(const std::string& filename, const std::string& path); + +// scalerx.c +//void scale2x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height); + +#endif + diff --git a/src/gamedo.cpp b/src/gamedo.cpp index e760b2a6e..9d354b2a1 100644 --- a/src/gamedo.cpp +++ b/src/gamedo.cpp @@ -1,747 +1,750 @@ -/* GAMEDO.C - Contains all of the gamedo_xxx functions...which are called from the - main game loop. These functions perform some task that is done each - time around the game loop, not directly related to the player. -*/ - -#include "keen.h" - -#include "include/game.h" -#include "include/gamedo.h" -#include "include/gamepdo.h" -#include "include/misc.h" -#include "sdl/CVideoDriver.h" -#include "sdl/CTimer.h" -#include "sdl/CInput.h" -#include "sdl/sound/CSound.h" -#include "CGraphics.h" -#include "vorticon/CPlayer.h" -#include "keenext.h" - -#include "include/enemyai.h" - -extern unsigned long gotPlayX; - -extern unsigned long CurrentTickCount; - -extern unsigned int unknownKey; - -extern CPlayer *Player; - -int animtiletimer, curanimtileframe; - -// gathers data from input controllers: keyboard, joystick, network, -// whatever to populate each player's keytable -unsigned char oldleftkey = 5; -unsigned char oldrightkey = 5; -unsigned char oldupkey = 5; -unsigned char olddownkey = 5; -unsigned char oldctrlkey = 5; -unsigned char oldaltkey = 5; -void gamedo_getInput(stCloneKeenPlus *pCKP) -{ -int i; -int byt; -unsigned int msb, lsb; - - if (demomode==DEMO_PLAYBACK) - { - // time to get a new key block? - if (!demo_RLERunLen) - { - /* get next RLE run length */ - lsb = demo_data[demo_data_index++]; - msb = demo_data[demo_data_index++]; - demo_RLERunLen = (msb<<8) | lsb; - byt = demo_data[demo_data_index++]; // get keys down - - player[0].playcontrol[PA_X] = 0; - player[0].playcontrol[PA_POGO] = 0; - player[0].playcontrol[PA_JUMP] = 0; - player[0].playcontrol[PA_FIRE] = 0; - player[0].playcontrol[PA_STATUS] = 0; - - if (byt & 1) player[0].playcontrol[PA_X] -= 100; - if (byt & 2) player[0].playcontrol[PA_X] += 100; - if (byt & 4) player[0].playcontrol[PA_POGO] = 1; - if (byt & 8) player[0].playcontrol[PA_JUMP] = 1; - if (byt & 16)player[0].playcontrol[PA_FIRE] = 1; - if (byt & 32)player[0].playcontrol[PA_STATUS] = 1; - if (byt & 64) - { // demo STOP command - if (fade.mode!=FADE_GO) endlevel(1, pCKP); - } - } - else - { - // we're still in the last RLE run, don't change any keys - demo_RLERunLen--; - } - - // user trying to cancel the demo? - for(i=0;igetPressedKey(i)) - { - if (fade.mode!=FADE_GO) endlevel(0, pCKP); - } - } - if (g_pInput->getPressedCommand(IC_STATUS)) - { - if (fade.mode!=FADE_GO) endlevel(0, pCKP); - } - - return; - } - - for(Uint8 p=0 ; pgetHoldedCommand(p, IC_LEFT)) - player[p].playcontrol[PA_X] -= 100; - if(g_pInput->getHoldedCommand(p, IC_RIGHT)) - player[p].playcontrol[PA_X] += 100; - - if(g_pInput->getHoldedCommand(p, IC_UP)) - player[p].playcontrol[PA_Y] -= 100; - if(g_pInput->getHoldedCommand(p, IC_DOWN)) - player[p].playcontrol[PA_Y] += 100; - - if(g_pInput->getHoldedCommand(p, IC_JUMP)) - player[p].playcontrol[PA_JUMP] = 1; - if(g_pInput->getHoldedCommand(p, IC_POGO)) - player[p].playcontrol[PA_POGO] = 1; - if(g_pInput->getHoldedCommand(p, IC_FIRE)) - player[p].playcontrol[PA_FIRE] = 1; - if(g_pInput->getHoldedCommand(p, IC_STATUS)) - player[p].playcontrol[PA_STATUS] = 1; - - if (demomode==DEMO_RECORD) - { - if(i) player[p].playcontrol[PA_X] += 100; - fputc(i, demofile); - if(i) player[p].playcontrol[PA_X] -= 100; - fputc(i, demofile); - if(i) player[p].playcontrol[PA_POGO] = 1; - fputc(i, demofile); - if(i) player[p].playcontrol[PA_JUMP] = 1; - fputc(i, demofile); - if(i) player[p].playcontrol[PA_FIRE] = 1; - fputc(i, demofile); - if(i) player[p].playcontrol[PA_STATUS] = 1; - fputc(i, demofile); - } - } -} - -// handles scrolling, for player cp -// returns nonzero if the scroll was changed -int gamedo_ScrollTriggers(int theplayer) -{ -signed int px, py; -int scrollchanged; - - if (player[theplayer].pdie) return 0; - - //px = (Player[theplayer].getCoordX()>>CSF)-scroll_x; - //py = (Player[theplayer].getCoordY()>>CSF)-scroll_y; - - px = (player[theplayer].x>>CSF)-scroll_x; - py = (player[theplayer].y>>CSF)-scroll_y; - - scrollchanged = 0; - - /* left-right scrolling */ - if(px > SCROLLTRIGGERRIGHT && scroll_x < max_scroll_x) - { - map_scroll_right(); - scrollchanged = 1; - } - else if(px < SCROLLTRIGGERLEFT && scroll_x > 32) - { - map_scroll_left(); - scrollchanged = 1; - } - - /* up-down scrolling */ - if (py > SCROLLTRIGGERDOWN && scroll_y < max_scroll_y) - { - map_scroll_down(); - scrollchanged = 1; - } - else if (py < SCROLLTRIGGERUP && scroll_y > 32) - { - map_scroll_up(); - scrollchanged = 1; - } - - return scrollchanged; -} - -// animates animated tiles -void gamedo_AnimatedTiles(void) -{ -int i; - /* animate animated tiles */ - if (animtiletimer>ANIM_TILE_TIME) - { - /* advance to next frame */ - curanimtileframe = (curanimtileframe+1)&7; - /* re-draw all animated tiles */ - for(i=1;idrawTile(animtiles[i].x, animtiles[i].y, animtiles[i].baseframe+((animtiles[i].offset+curanimtileframe)%TileProperty[animtiles[i].baseframe][ANIMATION])); - } - } - animtiletimer = 0; - } - else animtiletimer++; -} - -// do object and enemy AI -void gamedo_enemyai(stCloneKeenPlus *pCKP) -{ -int i; -// handle objects and do enemy AI - for(i=1;i (map.xsize << CSF << 4) || objects[i].y > (map.ysize << CSF << 4)) - continue; - - objects[i].scrx = (objects[i].x>>CSF)-scroll_x; - objects[i].scry = (objects[i].y>>CSF)-scroll_y; - if (objects[i].scrx < -(sprites[objects[i].sprite].xsize) || objects[i].scrx > 320 \ - || objects[i].scry < -(sprites[objects[i].sprite].ysize) || objects[i].scry > 200) - { - objects[i].onscreen = 0; - objects[i].wasoffscreen = 1; - if (objects[i].type==OBJ_ICEBIT) objects[i].exists = 0; - } - else - { - #ifdef TARGET_WIN32 -// if (numplayers>1) -// if (!objects[i].hasbeenonscreen) -// net_sendobjectonscreen(i); - #endif - - objects[i].onscreen = 1; - objects[i].hasbeenonscreen = 1; - } - - if (objects[i].hasbeenonscreen || objects[i].type==OBJ_RAY || \ - objects[i].type==OBJ_ICECHUNK || objects[i].type==OBJ_PLATFORM ||\ - objects[i].type==OBJ_PLATVERT) - { - common_enemy_ai(i); - switch(objects[i].type) - { - //KEEN1 - case OBJ_YORP: yorp_ai(i, pCKP->Control.levelcontrol); break; - case OBJ_GARG: garg_ai(i, pCKP); break; - case OBJ_VORT: vort_ai(i, pCKP, pCKP->Control.levelcontrol); break; - case OBJ_BUTLER: butler_ai(i, pCKP->Control.levelcontrol.hardmode); break; - case OBJ_TANK: tank_ai(i, pCKP->Control.levelcontrol.hardmode); break; - case OBJ_RAY: ray_ai(i, pCKP, pCKP->Control.levelcontrol); break; - case OBJ_DOOR: door_ai(i); break; - case OBJ_ICECHUNK: icechunk_ai(i); break; - case OBJ_ICEBIT: icebit_ai(i); break; - case OBJ_TELEPORTER: teleporter_ai(i, pCKP->Control.levelcontrol); break; - case OBJ_ROPE: rope_ai(i); break; - //KEEN2 - case OBJ_WALKER: walker_ai(i, pCKP->Control.levelcontrol); break; - case OBJ_TANKEP2: tankep2_ai(i, pCKP); break; - case OBJ_PLATFORM: platform_ai(i, pCKP->Control.levelcontrol); break; - case OBJ_BEAR: bear_ai(i, pCKP->Control.levelcontrol, pCKP); break; - case OBJ_SECTOREFFECTOR: se_ai(i, pCKP); break; - case OBJ_BABY: baby_ai(i, pCKP->Control.levelcontrol); break; - case OBJ_EXPLOSION: explosion_ai(i); break; - case OBJ_EARTHCHUNK: earthchunk_ai(i); break; - //KEEN3 - case OBJ_FOOB: foob_ai(i, pCKP); break; - case OBJ_NINJA: ninja_ai(i, pCKP); break; - case OBJ_MEEP: meep_ai(i, pCKP->Control.levelcontrol); break; - case OBJ_SNDWAVE: sndwave_ai(i, pCKP); break; - case OBJ_MOTHER: mother_ai(i, pCKP->Control.levelcontrol); break; - case OBJ_FIREBALL: fireball_ai(i, pCKP); break; - case OBJ_BALL: ballandjack_ai(i, pCKP); break; - case OBJ_JACK: ballandjack_ai(i, pCKP); break; - case OBJ_PLATVERT: platvert_ai(i); break; - case OBJ_NESSIE: nessie_ai(i); break; - - case OBJ_DEMOMSG: break; - default: - crashflag = 1; - crashflag2 = i; - crashflag3 = objects[i].type; - why_term_ptr = "Invalid object flag2 of type flag3"; - break; - } - - objects[i].scrx = (objects[i].x>>CSF)-scroll_x; - objects[i].scry = (objects[i].y>>CSF)-scroll_y; - } - } -} - - -int savew, saveh; - -void gamedo_render_drawobjects(stCloneKeenPlus *pCKP) -{ -unsigned int i; -int x,y,o,tl,xsize,ysize; -int xa,ya; - - // copy player data to their associated objects show they can get drawn - // in the object-drawing loop with the rest of the objects - for( i=0 ;i < numplayers ; i++) - { - o = player[i].useObject; - - if (!player[i].hideplayer) - { - objects[o].sprite = player[i].playframe + playerbaseframes[i]; - } - - else - { - objects[o].sprite = BlankSprite; - } - objects[o].x = player[i].x; - objects[o].y = player[i].y; - objects[o].scrx = (player[i].x>>CSF)-scroll_x; - objects[o].scry = (player[i].y>>CSF)-scroll_y; - - } - - // if we're playing a demo keep the "DEMO" message on the screen - // as an object - if (demomode==DEMO_PLAYBACK) - { - #define DEMO_X_POS 137 - #define DEMO_Y_POS 6 - objects[DemoObjectHandle].exists = 1; - objects[DemoObjectHandle].onscreen = 1; - objects[DemoObjectHandle].type = OBJ_DEMOMSG; - objects[DemoObjectHandle].sprite = DemoSprite; - objects[DemoObjectHandle].x = (DEMO_X_POS+scroll_x)<>CSF)-scroll_x); - objects[i].scry = ((objects[i].y>>CSF)-scroll_y); - g_pGraphics->drawSprite(objects[i].scrx, objects[i].scry, objects[i].sprite, i); - - if (objects[i].honorPriority) - { - // handle priority tiles and tiles with masks - // get the upper-left coordinates to start checking for tiles - x = (((objects[i].x>>CSF)-1)>>4)<<4; - y = (((objects[i].y>>CSF)-1)>>4)<<4; - - // get the xsize/ysize of this sprite--round up to the nearest 16 - xsize = ((sprites[objects[i].sprite].xsize)>>4<<4); - if (xsize != sprites[objects[i].sprite].xsize) xsize+=16; - - ysize = ((sprites[objects[i].sprite].ysize)>>4<<4); - if (ysize != sprites[objects[i].sprite].ysize) ysize+=16; - - // now redraw any priority/masked tiles that we covered up - // with the sprite - for(ya=0;ya<=ysize;ya+=16) - { - for(xa=0;xa<=xsize;xa+=16) - { - tl = getmaptileat(x+xa,y+ya); - if(TileProperty[tl][BEHAVIOR] == 65534) - { - g_pGraphics->drawTilewithmask(x+xa-scroll_x,y+ya-scroll_y,tl,tl+1); - } - else if (TileProperty[tl][BEHAVIOR] == 65535) - { - if ( TileProperty[tl][ANIMATION] > 1 ) - { - tl = (tl-tiles[tl].animOffset)+((tiles[tl].animOffset+curanimtileframe)%TileProperty[tl][ANIMATION]); - } - g_pGraphics->drawPrioritytile(x+xa-scroll_x,y+ya-scroll_y,tl); - } - } - } - } - - } - if(i==0) break; - } - -} - -void gamedo_render_drawdebug(void) -{ -int tl,y; -/*int h;*/ -char debugmsg[80]; - - if (debugmode) - { - if (debugmode==1) - { - savew = 190; - saveh = 80; - g_pGraphics->saveArea(4,4,savew,saveh); - y = 5-8; - sprintf(debugmsg, "p1x/y: %ld/%d", player[0].x, player[0].y); - g_pGraphics->sb_font_draw( (unsigned char*) debugmsg, 5, y+=8); - sprintf(debugmsg, "p2x/y: %ld/%d", player[1].x, player[1].y); - g_pGraphics->sb_font_draw( (unsigned char*) debugmsg, 5, y+=8); - sprintf(debugmsg, "scroll_x/y = %d/%d", (unsigned int)scroll_x, (unsigned int)scroll_y); - g_pGraphics->sb_font_draw( (unsigned char*) debugmsg, 5, y+=8); - sprintf(debugmsg, "scrollbuf_x/y: %d/%d", scrollx_buf, scrolly_buf); - g_pGraphics->sb_font_draw( (unsigned char*) debugmsg, 5, y+=8); - sprintf(debugmsg, "iw,pw: %d/%d", player[0].inhibitwalking, player[0].pwalking); - g_pGraphics->sb_font_draw( (unsigned char*) debugmsg, 5, y+=8); - sprintf(debugmsg, "pinertia_x: %d", player[0].pinertia_x); - g_pGraphics->sb_font_draw( (unsigned char*) debugmsg, 5, y+=8); - sprintf(debugmsg, "psupt: (%d,%d)", player[0].psupportingtile, player[0].psupportingobject); - g_pGraphics->sb_font_draw( (unsigned char*) debugmsg, 5, y+=8); - - sprintf(debugmsg, "lvl,tile = %d,%d", getlevelat((player[0].x>>CSF)+4, (player[0].y>>CSF)+9), tl); - g_pGraphics->sb_font_draw( (unsigned char*) debugmsg, 5, y+=8); - -/* - sprintf(debugmsg, "NOH=%d", NessieObjectHandle); - sb_font_draw(debugmsg, 5, y+=8); - sprintf(debugmsg, "x,y=(%d,%d)", objects[NessieObjectHandle].x,objects[NessieObjectHandle].y); - sb_font_draw(debugmsg, 5, y+=8); - sprintf(debugmsg, " >>CSF=(%d,%d)", objects[NessieObjectHandle].x>>CSF,objects[NessieObjectHandle].y>>CSF); - sb_font_draw(debugmsg, 5, y+=8); - sprintf(debugmsg, " >>CSF>>4=(%d,%d)", objects[NessieObjectHandle].x>>CSF>>4,objects[NessieObjectHandle].y>>CSF>>4); - sb_font_draw(debugmsg, 5, y+=8); - - sprintf(debugmsg, "nessiestate = %d", objects[NessieObjectHandle].ai.nessie.state); - sb_font_draw(debugmsg, 5, y+=8); - sprintf(debugmsg, "pausetimer = %d", objects[NessieObjectHandle].ai.nessie.pausetimer); - sb_font_draw(debugmsg, 5, y+=8); - sprintf(debugmsg, "pausex/y = (%d,%d)", objects[NessieObjectHandle].ai.nessie.pausex,objects[NessieObjectHandle].ai.nessie.pausey); - sb_font_draw(debugmsg, 5, y+=8); - sprintf(debugmsg, "destx/y = %d/%d", objects[NessieObjectHandle].ai.nessie.destx,objects[NessieObjectHandle].ai.nessie.desty); - sb_font_draw(debugmsg, 5, y+=8); - sprintf(debugmsg, " >>CSF = %d/%d", objects[NessieObjectHandle].ai.nessie.destx>>CSF,objects[NessieObjectHandle].ai.nessie.desty>>CSF); - sb_font_draw(debugmsg, 5, y+=8); - sprintf(debugmsg, " >>CSF>>4 = %d/%d", objects[NessieObjectHandle].ai.nessie.destx>>CSF>>4,objects[NessieObjectHandle].ai.nessie.desty>>CSF>>4); - sb_font_draw(debugmsg, 5, y+=8); - sprintf(debugmsg, "mort_swim_amt = %d", objects[NessieObjectHandle].ai.nessie.mortimer_swim_amt); - sb_font_draw(debugmsg, 5, y+=8); - - h = objects[NessieObjectHandle].ai.nessie.tiletrailhead; - - sprintf(debugmsg, "tthead=%d", h); - sb_font_draw(debugmsg, 5, y+=8); - - sprintf(debugmsg, "ttX=%d,%d,%d,%d,%d", objects[NessieObjectHandle].ai.nessie.tiletrailX[0],objects[NessieObjectHandle].ai.nessie.tiletrailX[1],objects[NessieObjectHandle].ai.nessie.tiletrailX[2],objects[NessieObjectHandle].ai.nessie.tiletrailX[3],objects[NessieObjectHandle].ai.nessie.tiletrailX[4]); - sb_font_draw(debugmsg, 5, y+=8); - sprintf(debugmsg, "ttY=%d,%d,%d,%d,%d", objects[NessieObjectHandle].ai.nessie.tiletrailY[0],objects[NessieObjectHandle].ai.nessie.tiletrailY[1],objects[NessieObjectHandle].ai.nessie.tiletrailY[2],objects[NessieObjectHandle].ai.nessie.tiletrailY[3],objects[NessieObjectHandle].ai.nessie.tiletrailY[4]); - sb_font_draw(debugmsg, 5, y+=8); -*/ - } - else if (debugmode==2) - { - savew = map.xsize+4; - saveh = map.ysize+4; - g_pGraphics->saveArea(4,4,savew,saveh); - radar(); - } - } -} - -void gamedo_render_erasedebug(void) -{ - if (debugmode) g_pGraphics->restoreArea(4,4,savew,saveh); -} - -void gamedo_render_eraseobjects(void) -{ -int i; - - // erase all objects. - // note that this is done in the reverse order they are drawn. - // this is necessary or you will see corrupted pixels when - // two objects are occupying the same space. - for(i=0;ieraseSprite(objects[i].scrx, objects[i].scry, objects[i].sprite, i); - } - } -} - -extern int NumConsoleMessages; - -// draws sprites, players, and debug messages (if debug mode is on), -// performs frameskipping and blits the display as needed, -// at end of functions erases all drawn objects from the scrollbuf. -void gamedo_RenderScreen(stCloneKeenPlus *pCKP) -{ - int x,y,bmnum; - - g_pGraphics->renderHQBitmap(); - - gamedo_render_drawobjects(pCKP); - - if(pCKP != NULL) - { - if (pCKP->Control.levelcontrol.gameovermode) - { - // figure out where to center the gameover bitmap and draw it - bmnum = g_pGraphics->getBitmapNumberFromName("GAMEOVER"); - x = (320/2)-(bitmaps[bmnum].xsize/2); - y = (200/2)-(bitmaps[bmnum].ysize/2); - g_pGraphics->drawBitmap(x, y, bmnum); - } - } - - g_pVideoDriver->sb_blit(); // blit scrollbuffer to display - - gamedo_render_erasedebug(); - gamedo_render_eraseobjects(); - - curfps++; -} - -int ctspace=0, lastctspace=0; -void gamedo_HandleFKeys(stCloneKeenPlus *pCKP) -{ -int i; - - if (g_pInput->getHoldedKey(KC) && - g_pInput->getHoldedKey(KT) && - g_pInput->getHoldedKey(KSPACE)) - { - ctspace = 1; - } - else ctspace = 0; - - if (ctspace && !lastctspace) - { - for(i=0;iAddConsoleMsg("All items cheat"); - } - - lastctspace = ctspace; - - // GOD cheat -- toggle god mode - if (g_pInput->getHoldedKey(KG) && g_pInput->getHoldedKey(KO) && g_pInput->getHoldedKey(KD)) - { - for(i=0;iDeleteConsoleMsgs(); - if (player[0].godmode) - g_pVideoDriver->AddConsoleMsg("God mode ON"); - else - g_pVideoDriver->AddConsoleMsg("God mode OFF"); - - g_pSound->playSound(SOUND_GUN_CLICK, PLAY_FORCE); - - // Show a message like in the original game - char **text; - - text = (char**) malloc(sizeof(char*)); - - text[0]= (char*) malloc(MAX_STRING_LENGTH*sizeof(char)); - - if (player[0].godmode) - strcpy(text[0], "Godmode enabled"); - else - strcpy(text[0], "Godmode disabled"); - - showTextMB(1,text,pCKP); - - free(text[0]); - free(text); - } - - - if (pCKP->Option[OPT_CHEATS].value) - { - if (g_pInput->getHoldedKey(KTAB)) // noclip/revive - { - // resurrect any dead players. the rest of the KTAB magic is - // scattered throughout the various functions. - for(i=0;igetPressedKey(KF8)) - { - framebyframe = 1; - #ifdef BUILD_SDL - g_pVideoDriver->AddConsoleMsg("Frame-by-frame mode F8:advance F7:stop"); - #endif - } - // F9 - exit level immediately - if(g_pInput->getPressedKey(KF9)) - { - endlevel(1, pCKP); - } - // F6 - onscreen debug--toggle through debug/radar/off - if(g_pInput->getPressedKey(KF6)) - { - debugmode++; - if (debugmode>2) debugmode=0; - } - // F7 - accelerate mode/frame by frame frame advance - if(g_pInput->getPressedKey(KF7)) - { - if (!framebyframe) acceleratemode=1-acceleratemode; - } - } - - // F10 - change primary player - if(g_pInput->getPressedKey(KF10)) - { - primaryplayer++; - if (primaryplayer>=numplayers) primaryplayer=0; - } - // F3 - save game - if (g_pInput->getPressedKey(KF3)) - game_save_interface(pCKP); - -} - -void gamedo_fades(void) -{ - if (fade.mode != FADE_GO) return; - - if (fade.fadetimer > fade.rate) - { - if (fade.dir==FADE_IN) - { - if (fade.curamt < PAL_FADE_SHADES) - { - fade.curamt++; // coming in from black - } - else - { - fade.curamt--; // coming in from white-out - } - if (fade.curamt==PAL_FADE_SHADES) - { - fade.mode = FADE_COMPLETE; - } - g_pGraphics->fadePalette(fade.curamt); - } - else if (fade.dir==FADE_OUT) - { - fade.curamt--; - if (fade.curamt==0) fade.mode = FADE_COMPLETE; - g_pGraphics->fadePalette(fade.curamt); - } - fade.fadetimer = 0; - } - else - { - fade.fadetimer++; - } -} - -void gamedo_frameskipping(stCloneKeenPlus *pCKP) -{ - if (framebyframe) - { - gamedo_RenderScreen(pCKP); - return; - } - - if (frameskiptimer >= g_pVideoDriver->getFrameskip()) - { - gamedo_RenderScreen(pCKP); - frameskiptimer = 0; - } else frameskiptimer++; - -} - -// same as above but only does a sb_blit, not the full RenderScreen. -// used for intros etc. -void gamedo_frameskipping_blitonly(void) -{ - if (framebyframe) - { - g_pVideoDriver->sb_blit(); - return; - } - - if (frameskiptimer >= g_pVideoDriver->getFrameskip()) - { - g_pVideoDriver->sb_blit(); - frameskiptimer = 0; - } else frameskiptimer++; -} - +/* GAMEDO.C + Contains all of the gamedo_xxx functions...which are called from the + main game loop. These functions perform some task that is done each + time around the game loop, not directly related to the player. +*/ + +#include "keen.h" + +#include "include/game.h" +#include "include/gamedo.h" +#include "include/gamepdo.h" +#include "include/misc.h" +#include "sdl/CVideoDriver.h" +#include "sdl/CTimer.h" +#include "sdl/CInput.h" +#include "sdl/sound/CSound.h" +#include "CGraphics.h" +#include "vorticon/CPlayer.h" +#include "keenext.h" +#include "StringUtils.h" + +#include "include/enemyai.h" + +extern unsigned long gotPlayX; + +extern unsigned long CurrentTickCount; + +extern unsigned int unknownKey; + +extern CPlayer *Player; + +int animtiletimer, curanimtileframe; + +// gathers data from input controllers: keyboard, joystick, network, +// whatever to populate each player's keytable +unsigned char oldleftkey = 5; +unsigned char oldrightkey = 5; +unsigned char oldupkey = 5; +unsigned char olddownkey = 5; +unsigned char oldctrlkey = 5; +unsigned char oldaltkey = 5; +void gamedo_getInput(stCloneKeenPlus *pCKP) +{ +int i; +int byt; +unsigned int msb, lsb; + + if (demomode==DEMO_PLAYBACK) + { + // time to get a new key block? + if (!demo_RLERunLen) + { + /* get next RLE run length */ + lsb = demo_data[demo_data_index++]; + msb = demo_data[demo_data_index++]; + demo_RLERunLen = (msb<<8) | lsb; + byt = demo_data[demo_data_index++]; // get keys down + + player[0].playcontrol[PA_X] = 0; + player[0].playcontrol[PA_POGO] = 0; + player[0].playcontrol[PA_JUMP] = 0; + player[0].playcontrol[PA_FIRE] = 0; + player[0].playcontrol[PA_STATUS] = 0; + + if (byt & 1) player[0].playcontrol[PA_X] -= 100; + if (byt & 2) player[0].playcontrol[PA_X] += 100; + if (byt & 4) player[0].playcontrol[PA_POGO] = 1; + if (byt & 8) player[0].playcontrol[PA_JUMP] = 1; + if (byt & 16)player[0].playcontrol[PA_FIRE] = 1; + if (byt & 32)player[0].playcontrol[PA_STATUS] = 1; + if (byt & 64) + { // demo STOP command + if (fade.mode!=FADE_GO) endlevel(1, pCKP); + } + } + else + { + // we're still in the last RLE run, don't change any keys + demo_RLERunLen--; + } + + // user trying to cancel the demo? + for(i=0;igetPressedKey(i)) + { + if (fade.mode!=FADE_GO) endlevel(0, pCKP); + } + } + if (g_pInput->getPressedCommand(IC_STATUS)) + { + if (fade.mode!=FADE_GO) endlevel(0, pCKP); + } + + return; + } + + for(Uint8 p=0 ; pgetHoldedCommand(p, IC_LEFT)) + player[p].playcontrol[PA_X] -= 100; + if(g_pInput->getHoldedCommand(p, IC_RIGHT)) + player[p].playcontrol[PA_X] += 100; + + if(g_pInput->getHoldedCommand(p, IC_UP)) + player[p].playcontrol[PA_Y] -= 100; + if(g_pInput->getHoldedCommand(p, IC_DOWN)) + player[p].playcontrol[PA_Y] += 100; + + if(g_pInput->getHoldedCommand(p, IC_JUMP)) + player[p].playcontrol[PA_JUMP] = 1; + if(g_pInput->getHoldedCommand(p, IC_POGO)) + player[p].playcontrol[PA_POGO] = 1; + if(g_pInput->getHoldedCommand(p, IC_FIRE)) + player[p].playcontrol[PA_FIRE] = 1; + if(g_pInput->getHoldedCommand(p, IC_STATUS)) + player[p].playcontrol[PA_STATUS] = 1; + + if (demomode==DEMO_RECORD) + { + if(i) player[p].playcontrol[PA_X] += 100; + fputc(i, demofile); + if(i) player[p].playcontrol[PA_X] -= 100; + fputc(i, demofile); + if(i) player[p].playcontrol[PA_POGO] = 1; + fputc(i, demofile); + if(i) player[p].playcontrol[PA_JUMP] = 1; + fputc(i, demofile); + if(i) player[p].playcontrol[PA_FIRE] = 1; + fputc(i, demofile); + if(i) player[p].playcontrol[PA_STATUS] = 1; + fputc(i, demofile); + } + } +} + +// handles scrolling, for player cp +// returns nonzero if the scroll was changed +int gamedo_ScrollTriggers(int theplayer) +{ +signed int px, py; +int scrollchanged; + + if (player[theplayer].pdie) return 0; + + //px = (Player[theplayer].getCoordX()>>CSF)-scroll_x; + //py = (Player[theplayer].getCoordY()>>CSF)-scroll_y; + + px = (player[theplayer].x>>CSF)-scroll_x; + py = (player[theplayer].y>>CSF)-scroll_y; + + scrollchanged = 0; + + /* left-right scrolling */ + if(px > SCROLLTRIGGERRIGHT && scroll_x < max_scroll_x) + { + map_scroll_right(); + scrollchanged = 1; + } + else if(px < SCROLLTRIGGERLEFT && scroll_x > 32) + { + map_scroll_left(); + scrollchanged = 1; + } + + /* up-down scrolling */ + if (py > SCROLLTRIGGERDOWN && scroll_y < max_scroll_y) + { + map_scroll_down(); + scrollchanged = 1; + } + else if (py < SCROLLTRIGGERUP && scroll_y > 32) + { + map_scroll_up(); + scrollchanged = 1; + } + + return scrollchanged; +} + +// animates animated tiles +void gamedo_AnimatedTiles(void) +{ +int i; + /* animate animated tiles */ + if (animtiletimer>ANIM_TILE_TIME) + { + /* advance to next frame */ + curanimtileframe = (curanimtileframe+1)&7; + /* re-draw all animated tiles */ + for(i=1;idrawTile(animtiles[i].x, animtiles[i].y, animtiles[i].baseframe+((animtiles[i].offset+curanimtileframe)%TileProperty[animtiles[i].baseframe][ANIMATION])); + } + } + animtiletimer = 0; + } + else animtiletimer++; +} + +// do object and enemy AI +void gamedo_enemyai(stCloneKeenPlus *pCKP) +{ +int i; +// handle objects and do enemy AI + for(i=1;i (map.xsize << CSF << 4) || objects[i].y > (map.ysize << CSF << 4)) + continue; + + objects[i].scrx = (objects[i].x>>CSF)-scroll_x; + objects[i].scry = (objects[i].y>>CSF)-scroll_y; + if (objects[i].scrx < -(sprites[objects[i].sprite].xsize) || objects[i].scrx > 320 \ + || objects[i].scry < -(sprites[objects[i].sprite].ysize) || objects[i].scry > 200) + { + objects[i].onscreen = 0; + objects[i].wasoffscreen = 1; + if (objects[i].type==OBJ_ICEBIT) objects[i].exists = 0; + } + else + { + #ifdef TARGET_WIN32 +// if (numplayers>1) +// if (!objects[i].hasbeenonscreen) +// net_sendobjectonscreen(i); + #endif + + objects[i].onscreen = 1; + objects[i].hasbeenonscreen = 1; + } + + if (objects[i].hasbeenonscreen || objects[i].type==OBJ_RAY || \ + objects[i].type==OBJ_ICECHUNK || objects[i].type==OBJ_PLATFORM ||\ + objects[i].type==OBJ_PLATVERT) + { + common_enemy_ai(i); + switch(objects[i].type) + { + //KEEN1 + case OBJ_YORP: yorp_ai(i, pCKP->Control.levelcontrol); break; + case OBJ_GARG: garg_ai(i, pCKP); break; + case OBJ_VORT: vort_ai(i, pCKP, pCKP->Control.levelcontrol); break; + case OBJ_BUTLER: butler_ai(i, pCKP->Control.levelcontrol.hardmode); break; + case OBJ_TANK: tank_ai(i, pCKP->Control.levelcontrol.hardmode); break; + case OBJ_RAY: ray_ai(i, pCKP, pCKP->Control.levelcontrol); break; + case OBJ_DOOR: door_ai(i); break; + case OBJ_ICECHUNK: icechunk_ai(i); break; + case OBJ_ICEBIT: icebit_ai(i); break; + case OBJ_TELEPORTER: teleporter_ai(i, pCKP->Control.levelcontrol); break; + case OBJ_ROPE: rope_ai(i); break; + //KEEN2 + case OBJ_WALKER: walker_ai(i, pCKP->Control.levelcontrol); break; + case OBJ_TANKEP2: tankep2_ai(i, pCKP); break; + case OBJ_PLATFORM: platform_ai(i, pCKP->Control.levelcontrol); break; + case OBJ_BEAR: bear_ai(i, pCKP->Control.levelcontrol, pCKP); break; + case OBJ_SECTOREFFECTOR: se_ai(i, pCKP); break; + case OBJ_BABY: baby_ai(i, pCKP->Control.levelcontrol); break; + case OBJ_EXPLOSION: explosion_ai(i); break; + case OBJ_EARTHCHUNK: earthchunk_ai(i); break; + //KEEN3 + case OBJ_FOOB: foob_ai(i, pCKP); break; + case OBJ_NINJA: ninja_ai(i, pCKP); break; + case OBJ_MEEP: meep_ai(i, pCKP->Control.levelcontrol); break; + case OBJ_SNDWAVE: sndwave_ai(i, pCKP); break; + case OBJ_MOTHER: mother_ai(i, pCKP->Control.levelcontrol); break; + case OBJ_FIREBALL: fireball_ai(i, pCKP); break; + case OBJ_BALL: ballandjack_ai(i, pCKP); break; + case OBJ_JACK: ballandjack_ai(i, pCKP); break; + case OBJ_PLATVERT: platvert_ai(i); break; + case OBJ_NESSIE: nessie_ai(i); break; + + case OBJ_DEMOMSG: break; + default: + crashflag = 1; + crashflag2 = i; + crashflag3 = objects[i].type; + why_term_ptr = "Invalid object flag2 of type flag3"; + break; + } + + objects[i].scrx = (objects[i].x>>CSF)-scroll_x; + objects[i].scry = (objects[i].y>>CSF)-scroll_y; + } + } +} + + +int savew, saveh; + +void gamedo_render_drawobjects(stCloneKeenPlus *pCKP) +{ +unsigned int i; +int x,y,o,tl,xsize,ysize; +int xa,ya; + + // copy player data to their associated objects show they can get drawn + // in the object-drawing loop with the rest of the objects + for( i=0 ;i < numplayers ; i++) + { + o = player[i].useObject; + + if (!player[i].hideplayer) + { + objects[o].sprite = player[i].playframe + playerbaseframes[i]; + } + + else + { + objects[o].sprite = BlankSprite; + } + objects[o].x = player[i].x; + objects[o].y = player[i].y; + objects[o].scrx = (player[i].x>>CSF)-scroll_x; + objects[o].scry = (player[i].y>>CSF)-scroll_y; + + } + + // if we're playing a demo keep the "DEMO" message on the screen + // as an object + if (demomode==DEMO_PLAYBACK) + { + #define DEMO_X_POS 137 + #define DEMO_Y_POS 6 + objects[DemoObjectHandle].exists = 1; + objects[DemoObjectHandle].onscreen = 1; + objects[DemoObjectHandle].type = OBJ_DEMOMSG; + objects[DemoObjectHandle].sprite = DemoSprite; + objects[DemoObjectHandle].x = (DEMO_X_POS+scroll_x)<>CSF)-scroll_x); + objects[i].scry = ((objects[i].y>>CSF)-scroll_y); + g_pGraphics->drawSprite(objects[i].scrx, objects[i].scry, objects[i].sprite, i); + + if (objects[i].honorPriority) + { + // handle priority tiles and tiles with masks + // get the upper-left coordinates to start checking for tiles + x = (((objects[i].x>>CSF)-1)>>4)<<4; + y = (((objects[i].y>>CSF)-1)>>4)<<4; + + // get the xsize/ysize of this sprite--round up to the nearest 16 + xsize = ((sprites[objects[i].sprite].xsize)>>4<<4); + if (xsize != sprites[objects[i].sprite].xsize) xsize+=16; + + ysize = ((sprites[objects[i].sprite].ysize)>>4<<4); + if (ysize != sprites[objects[i].sprite].ysize) ysize+=16; + + // now redraw any priority/masked tiles that we covered up + // with the sprite + for(ya=0;ya<=ysize;ya+=16) + { + for(xa=0;xa<=xsize;xa+=16) + { + tl = getmaptileat(x+xa,y+ya); + if(TileProperty[tl][BEHAVIOR] == 65534) + { + g_pGraphics->drawTilewithmask(x+xa-scroll_x,y+ya-scroll_y,tl,tl+1); + } + else if (TileProperty[tl][BEHAVIOR] == 65535) + { + if ( TileProperty[tl][ANIMATION] > 1 ) + { + tl = (tl-tiles[tl].animOffset)+((tiles[tl].animOffset+curanimtileframe)%TileProperty[tl][ANIMATION]); + } + g_pGraphics->drawPrioritytile(x+xa-scroll_x,y+ya-scroll_y,tl); + } + } + } + } + + } + if(i==0) break; + } + +} + +void gamedo_render_drawdebug(void) +{ +int tl,y; +/*int h;*/ + std::string debugmsg; + + if (debugmode) + { + if (debugmode==1) + { + savew = 190; + saveh = 80; + g_pGraphics->saveArea(4,4,savew,saveh); + y = 5-8; + debugmsg = "p1x/y: " + itoa(player[0].x) + "/" + itoa(player[0].y); + g_pGraphics->sb_font_draw( debugmsg, 5, y+=8); + debugmsg = "p2x/y: " + itoa(player[1].x) + "/" + itoa(player[1].y); + g_pGraphics->sb_font_draw( debugmsg, 5, y+=8); + debugmsg = "scroll_x/y = " + itoa(scroll_x) + "/" + itoa(scroll_y); + g_pGraphics->sb_font_draw( debugmsg, 5, y+=8); + debugmsg = "scrollbuf_x/y: " + itoa(scrollx_buf) + "/" + itoa(scrolly_buf); + g_pGraphics->sb_font_draw( debugmsg, 5, y+=8); + debugmsg = "iw,pw: " + itoa(player[0].inhibitwalking) + "/" + itoa(player[0].pwalking); + g_pGraphics->sb_font_draw( debugmsg, 5, y+=8); + debugmsg = "pinertia_x: " + itoa(player[0].pinertia_x); + g_pGraphics->sb_font_draw( debugmsg, 5, y+=8); + debugmsg = "psupt: (" + itoa(player[0].psupportingtile) + "," + itoa(player[0].psupportingobject) + ")"; + g_pGraphics->sb_font_draw( debugmsg, 5, y+=8); + + debugmsg = "lvl,tile = " + itoa(getlevelat((player[0].x>>CSF)+4, (player[0].y>>CSF)+9)) + "," + itoa(tl); + g_pGraphics->sb_font_draw( debugmsg, 5, y+=8); + +/* + sprintf(debugmsg, "NOH=%d", NessieObjectHandle); + sb_font_draw(debugmsg, 5, y+=8); + sprintf(debugmsg, "x,y=(%d,%d)", objects[NessieObjectHandle].x,objects[NessieObjectHandle].y); + sb_font_draw(debugmsg, 5, y+=8); + sprintf(debugmsg, " >>CSF=(%d,%d)", objects[NessieObjectHandle].x>>CSF,objects[NessieObjectHandle].y>>CSF); + sb_font_draw(debugmsg, 5, y+=8); + sprintf(debugmsg, " >>CSF>>4=(%d,%d)", objects[NessieObjectHandle].x>>CSF>>4,objects[NessieObjectHandle].y>>CSF>>4); + sb_font_draw(debugmsg, 5, y+=8); + + sprintf(debugmsg, "nessiestate = %d", objects[NessieObjectHandle].ai.nessie.state); + sb_font_draw(debugmsg, 5, y+=8); + sprintf(debugmsg, "pausetimer = %d", objects[NessieObjectHandle].ai.nessie.pausetimer); + sb_font_draw(debugmsg, 5, y+=8); + sprintf(debugmsg, "pausex/y = (%d,%d)", objects[NessieObjectHandle].ai.nessie.pausex,objects[NessieObjectHandle].ai.nessie.pausey); + sb_font_draw(debugmsg, 5, y+=8); + sprintf(debugmsg, "destx/y = %d/%d", objects[NessieObjectHandle].ai.nessie.destx,objects[NessieObjectHandle].ai.nessie.desty); + sb_font_draw(debugmsg, 5, y+=8); + sprintf(debugmsg, " >>CSF = %d/%d", objects[NessieObjectHandle].ai.nessie.destx>>CSF,objects[NessieObjectHandle].ai.nessie.desty>>CSF); + sb_font_draw(debugmsg, 5, y+=8); + sprintf(debugmsg, " >>CSF>>4 = %d/%d", objects[NessieObjectHandle].ai.nessie.destx>>CSF>>4,objects[NessieObjectHandle].ai.nessie.desty>>CSF>>4); + sb_font_draw(debugmsg, 5, y+=8); + sprintf(debugmsg, "mort_swim_amt = %d", objects[NessieObjectHandle].ai.nessie.mortimer_swim_amt); + sb_font_draw(debugmsg, 5, y+=8); + + h = objects[NessieObjectHandle].ai.nessie.tiletrailhead; + + sprintf(debugmsg, "tthead=%d", h); + sb_font_draw(debugmsg, 5, y+=8); + + sprintf(debugmsg, "ttX=%d,%d,%d,%d,%d", objects[NessieObjectHandle].ai.nessie.tiletrailX[0],objects[NessieObjectHandle].ai.nessie.tiletrailX[1],objects[NessieObjectHandle].ai.nessie.tiletrailX[2],objects[NessieObjectHandle].ai.nessie.tiletrailX[3],objects[NessieObjectHandle].ai.nessie.tiletrailX[4]); + sb_font_draw(debugmsg, 5, y+=8); + sprintf(debugmsg, "ttY=%d,%d,%d,%d,%d", objects[NessieObjectHandle].ai.nessie.tiletrailY[0],objects[NessieObjectHandle].ai.nessie.tiletrailY[1],objects[NessieObjectHandle].ai.nessie.tiletrailY[2],objects[NessieObjectHandle].ai.nessie.tiletrailY[3],objects[NessieObjectHandle].ai.nessie.tiletrailY[4]); + sb_font_draw(debugmsg, 5, y+=8); +*/ + } + else if (debugmode==2) + { + savew = map.xsize+4; + saveh = map.ysize+4; + g_pGraphics->saveArea(4,4,savew,saveh); + radar(); + } + } +} + +void gamedo_render_erasedebug(void) +{ + if (debugmode) g_pGraphics->restoreArea(4,4,savew,saveh); +} + +void gamedo_render_eraseobjects(void) +{ +int i; + + // erase all objects. + // note that this is done in the reverse order they are drawn. + // this is necessary or you will see corrupted pixels when + // two objects are occupying the same space. + for(i=0;ieraseSprite(objects[i].scrx, objects[i].scry, objects[i].sprite, i); + } + } +} + +extern int NumConsoleMessages; + +// draws sprites, players, and debug messages (if debug mode is on), +// performs frameskipping and blits the display as needed, +// at end of functions erases all drawn objects from the scrollbuf. +void gamedo_RenderScreen(stCloneKeenPlus *pCKP) +{ + int x,y,bmnum; + + g_pGraphics->renderHQBitmap(); + + gamedo_render_drawobjects(pCKP); + + if(pCKP != NULL) + { + if (pCKP->Control.levelcontrol.gameovermode) + { + // figure out where to center the gameover bitmap and draw it + bmnum = g_pGraphics->getBitmapNumberFromName("GAMEOVER"); + x = (320/2)-(bitmaps[bmnum].xsize/2); + y = (200/2)-(bitmaps[bmnum].ysize/2); + g_pGraphics->drawBitmap(x, y, bmnum); + } + } + + g_pVideoDriver->sb_blit(); // blit scrollbuffer to display + + gamedo_render_erasedebug(); + gamedo_render_eraseobjects(); + + curfps++; +} + +int ctspace=0, lastctspace=0; +void gamedo_HandleFKeys(stCloneKeenPlus *pCKP) +{ +int i; + + if (g_pInput->getHoldedKey(KC) && + g_pInput->getHoldedKey(KT) && + g_pInput->getHoldedKey(KSPACE)) + { + ctspace = 1; + } + else ctspace = 0; + + if (ctspace && !lastctspace) + { + for(i=0;iAddConsoleMsg("All items cheat"); + } + + lastctspace = ctspace; + + // GOD cheat -- toggle god mode + if (g_pInput->getHoldedKey(KG) && g_pInput->getHoldedKey(KO) && g_pInput->getHoldedKey(KD)) + { + for(i=0;iDeleteConsoleMsgs(); + if (player[0].godmode) + g_pVideoDriver->AddConsoleMsg("God mode ON"); + else + g_pVideoDriver->AddConsoleMsg("God mode OFF"); + + g_pSound->playSound(SOUND_GUN_CLICK, PLAY_FORCE); + + // Show a message like in the original game + char **text; + + text = (char**) malloc(sizeof(char*)); + + static const int MAX_STRING_LENGTH = 256; + text[0]= (char*) malloc(MAX_STRING_LENGTH*sizeof(char)); + + if (player[0].godmode) + strcpy(text[0], "Godmode enabled"); + else + strcpy(text[0], "Godmode disabled"); + + showTextMB(1,text,pCKP); + + free(text[0]); + free(text); + } + + + if (pCKP->Option[OPT_CHEATS].value) + { + if (g_pInput->getHoldedKey(KTAB)) // noclip/revive + { + // resurrect any dead players. the rest of the KTAB magic is + // scattered throughout the various functions. + for(i=0;igetPressedKey(KF8)) + { + framebyframe = 1; + #ifdef BUILD_SDL + g_pVideoDriver->AddConsoleMsg("Frame-by-frame mode F8:advance F7:stop"); + #endif + } + // F9 - exit level immediately + if(g_pInput->getPressedKey(KF9)) + { + endlevel(1, pCKP); + } + // F6 - onscreen debug--toggle through debug/radar/off + if(g_pInput->getPressedKey(KF6)) + { + debugmode++; + if (debugmode>2) debugmode=0; + } + // F7 - accelerate mode/frame by frame frame advance + if(g_pInput->getPressedKey(KF7)) + { + if (!framebyframe) acceleratemode=1-acceleratemode; + } + } + + // F10 - change primary player + if(g_pInput->getPressedKey(KF10)) + { + primaryplayer++; + if (primaryplayer>=numplayers) primaryplayer=0; + } + // F3 - save game + if (g_pInput->getPressedKey(KF3)) + game_save_interface(pCKP); + +} + +void gamedo_fades(void) +{ + if (fade.mode != FADE_GO) return; + + if (fade.fadetimer > fade.rate) + { + if (fade.dir==FADE_IN) + { + if (fade.curamt < PAL_FADE_SHADES) + { + fade.curamt++; // coming in from black + } + else + { + fade.curamt--; // coming in from white-out + } + if (fade.curamt==PAL_FADE_SHADES) + { + fade.mode = FADE_COMPLETE; + } + g_pGraphics->fadePalette(fade.curamt); + } + else if (fade.dir==FADE_OUT) + { + fade.curamt--; + if (fade.curamt==0) fade.mode = FADE_COMPLETE; + g_pGraphics->fadePalette(fade.curamt); + } + fade.fadetimer = 0; + } + else + { + fade.fadetimer++; + } +} + +void gamedo_frameskipping(stCloneKeenPlus *pCKP) +{ + if (framebyframe) + { + gamedo_RenderScreen(pCKP); + return; + } + + if (frameskiptimer >= g_pVideoDriver->getFrameskip()) + { + gamedo_RenderScreen(pCKP); + frameskiptimer = 0; + } else frameskiptimer++; + +} + +// same as above but only does a sb_blit, not the full RenderScreen. +// used for intros etc. +void gamedo_frameskipping_blitonly(void) +{ + if (framebyframe) + { + g_pVideoDriver->sb_blit(); + return; + } + + if (frameskiptimer >= g_pVideoDriver->getFrameskip()) + { + g_pVideoDriver->sb_blit(); + frameskiptimer = 0; + } else frameskiptimer++; +} + diff --git a/src/hqp/CHQBitmap.cpp b/src/hqp/CHQBitmap.cpp index 87b694076..bb86085b0 100644 --- a/src/hqp/CHQBitmap.cpp +++ b/src/hqp/CHQBitmap.cpp @@ -22,9 +22,9 @@ CHQBitmap::~CHQBitmap() { if(m_blackscreen){ SDL_FreeSurface(m_blackscreen); m_blackscreen = NULL;} } -bool CHQBitmap::loadImage(const char *pFilename, int wsize, int hsize) +bool CHQBitmap::loadImage(const std::string& pFilename, int wsize, int hsize) { - SDL_Surface *BitmapSurface = SDL_LoadBMP(pFilename); + SDL_Surface *BitmapSurface = SDL_LoadBMP(pFilename.c_str()); m_active = false; diff --git a/src/hqp/CHQBitmap.h b/src/hqp/CHQBitmap.h index 2e80aecf9..9f7818ebe 100644 --- a/src/hqp/CHQBitmap.h +++ b/src/hqp/CHQBitmap.h @@ -9,6 +9,7 @@ #define CHQBITMAP_H_ #include +#include class CHQBitmap { public: @@ -17,7 +18,7 @@ public: void setScrollposition(unsigned int xpos, unsigned int ypos); void updateHQBitmap(SDL_Surface *m_surface, SDL_Rect *p_srcrect, SDL_Rect *p_dstrect); - bool loadImage(const char *pFilename, int wsize, int hsize); + bool loadImage(const std::string& pFilename, int wsize, int hsize); void setAlphaBlend(Uint8 alpha); void offsetAlphaBlend(Uint8 alpha); diff --git a/src/hqp/hq_sound.cpp b/src/hqp/hq_sound.cpp index 99df5a280..01d284820 100644 --- a/src/hqp/hq_sound.cpp +++ b/src/hqp/hq_sound.cpp @@ -11,17 +11,17 @@ #include "../include/vorbis/oggsupport.h" #include "../CLogFile.h" -short HQSndDrv_Load(SDL_AudioSpec *AudioSpec, stHQSound *psound, const char *soundfile) +short HQSndDrv_Load(SDL_AudioSpec *AudioSpec, stHQSound *psound, const std::string& soundfile) { SDL_AudioSpec AudioFileSpec; SDL_AudioCVT Audio_cvt; psound->sound_buffer = NULL; - char buf[80]; + std::string buf; FILE *fp; - sprintf(buf,"data/hqp/snd/%s.OGG",soundfile); // Start with OGG - if((fp = fopen(buf,"rb")) != NULL) + buf = "data/hqp/snd/" + soundfile + ".OGG"; // Start with OGG + if((fp = fopen(buf.c_str(),"rb")) != NULL) { #ifdef BUILD_WITH_OGG if(openOGGSound(fp, &AudioFileSpec, AudioSpec->format, psound) != 0) @@ -35,12 +35,12 @@ short HQSndDrv_Load(SDL_AudioSpec *AudioSpec, stHQSound *psound, const char *sou #ifndef BUILD_WITH_OGG g_pLogFile->textOut(PURPLE,"Sorry, OGG-Support is disabled!
"); - sprintf(buf,"data/hqp/snd/%s.WAV",soundfile); + buf = "data/hqp/snd/"+ soundfile + ".WAV"; // Check, if it is a wav file or go back to classic sounds - if (SDL_LoadWAV (buf, &AudioFileSpec, &(psound->sound_buffer), &(psound->sound_len)) == NULL) + if (SDL_LoadWAV (buf.c_str(), &AudioFileSpec, &(psound->sound_buffer), &(psound->sound_len)) == NULL) { - g_pLogFile->textOut(PURPLE,"Wave file could not be opened: \"%s\". Trying to load the classical sound
", buf); + g_pLogFile->textOut(PURPLE,"Wave file could not be opened: \"%s\". Trying to load the classical sound
", buf.c_str()); return 1; } @@ -48,18 +48,18 @@ short HQSndDrv_Load(SDL_AudioSpec *AudioSpec, stHQSound *psound, const char *sou } else { - sprintf(buf,"data/hqp/snd/%s.WAV",soundfile); + buf = "data/hqp/snd/" + soundfile + ".WAV"; // Check, if it is a wav file or go back to classic sounds - if (SDL_LoadWAV (buf, &AudioFileSpec, &(psound->sound_buffer), &(psound->sound_len)) == NULL) + if (SDL_LoadWAV (buf.c_str(), &AudioFileSpec, &(psound->sound_buffer), &(psound->sound_len)) == NULL) { - g_pLogFile->textOut(PURPLE,"Wave file could not be opened: \"%s\". Trying to load the classical sounds
", buf); + g_pLogFile->textOut(PURPLE,"Wave file could not be opened: \"%s\". Trying to load the classical sounds
", buf.c_str()); return 1; } } psound->sound_pos = 0; - g_pLogFile->textOut(PURPLE,"File \"%s\" opened successfully!
", buf); + g_pLogFile->textOut(PURPLE,"File \"%s\" opened successfully!
", buf.c_str()); int ret; /* Build AudioCVT (This is needed for the conversion from one format to the one used in the game)*/ diff --git a/src/hqp/hq_sound.h b/src/hqp/hq_sound.h index a126063a5..8d8c905c9 100644 --- a/src/hqp/hq_sound.h +++ b/src/hqp/hq_sound.h @@ -5,15 +5,21 @@ * Author: gerstrong */ -#include +#ifndef __CG_HQ_SOUND_H__ +#define __CG_HQ_SOUND_H__ -typedef struct stHQSound +#include +#include + +struct stHQSound { Uint8 *sound_buffer; Uint32 sound_len; int sound_pos; bool enabled; -} stHQSound; +}; -short HQSndDrv_Load(SDL_AudioSpec *AudioSpec, stHQSound *psound, const char *soundfile); +short HQSndDrv_Load(SDL_AudioSpec *AudioSpec, stHQSound *psound, const std::string& soundfile); void HQSndDrv_Unload(stHQSound *psound); + +#endif diff --git a/src/include/declarations.h b/src/include/declarations.h index 3cf912e15..c05f12015 100644 --- a/src/include/declarations.h +++ b/src/include/declarations.h @@ -1,8 +1,12 @@ +#ifndef __CG_DECLARATIONS_H__ +#define __CG_DECLARATIONS_H__ + +#include +#include #define MAX_COMMANDS 8 #define MAX_SOUND_LENGTH 1024 #define MAX_SOUNDS 50 -#define MAX_STRING_LENGTH 256 #define MAX_NUMBER_OF_FILES 100 @@ -68,10 +72,11 @@ typedef struct stControl typedef struct stGameData { - char DataDirectory[MAX_STRING_LENGTH]; - short Episode; - char Name[MAX_STRING_LENGTH]; - char FileList[MAX_NUMBER_OF_FILES][MAX_STRING_LENGTH]; + std::string DataDirectory; + short Episode; + std::string Name; + std::string FileList[MAX_NUMBER_OF_FILES]; + stGameData() : Episode(0) {} } stGameData; @@ -106,3 +111,5 @@ typedef struct stNewPlayer { stCommand Command; } stNewPlayer; + +#endif diff --git a/src/include/eseq_ep2.h b/src/include/eseq_ep2.h index 00ded39a0..b5188f3f7 100644 --- a/src/include/eseq_ep2.h +++ b/src/include/eseq_ep2.h @@ -5,10 +5,17 @@ * Author: gerstrong */ +#ifndef __CG_ESEQ_EP2_H__ +#define __CG_ESEQ_EP2_H__ + +#include +struct stCloneKeenPlus; + int eseq2_LimpsHome(stCloneKeenPlus *pCKP); int eseq2_TantalusRay(stCloneKeenPlus *pCKP); void eseq2_vibrate(stCloneKeenPlus *pCKP); int eseq2_HeadsForEarth(stCloneKeenPlus *pCKP); int eseq2_SnowedOutside(stCloneKeenPlus *pCKP); -void eseq_showmsg(char *text, int boxleft, int boxtop, int boxwidth, int boxheight, char autodismiss, stCloneKeenPlus *pCKP); +void eseq_showmsg(const std::string& text, int boxleft, int boxtop, int boxwidth, int boxheight, char autodismiss, stCloneKeenPlus *pCKP); +#endif diff --git a/src/include/fileio.h b/src/include/fileio.h index 6991c57f6..831d51e1b 100644 --- a/src/include/fileio.h +++ b/src/include/fileio.h @@ -5,10 +5,17 @@ * Author: gerstrong */ -unsigned int loadmap(char filename[MAX_STRING_LENGTH], char *path, int lvlnum, int isworldmap, stCloneKeenPlus *pCKP); +#ifndef __CG_FILEIO_H__ +#define __CG_FILEIO_H__ + +#include + +unsigned int loadmap(const std::string& filename, const std::string& path, int lvlnum, int isworldmap, stCloneKeenPlus *pCKP); void addmaptile(unsigned int t); void addenemytile(unsigned int t, stCloneKeenPlus *pCKP); short checkConsistencyofGameData(stGameData *p_GameData); -void formatPathString(char *output, const char *path); +std::string formatPathString(const std::string& path); bool renameFilenamesLowerCase(const char *dir_name); void assignChangeTileAttribute(stTile *tile, int episode); + +#endif diff --git a/src/include/fileio/story.h b/src/include/fileio/story.h index 6c051082f..6c7ae39c0 100644 --- a/src/include/fileio/story.h +++ b/src/include/fileio/story.h @@ -5,4 +5,11 @@ * Author: gerstrong */ -int readStoryText(char **ptext, int episode, char *path); +#ifndef __CG_STORY_H__ +#define __CG_STORY_H__ + +#include + +int readStoryText(char **ptext, int episode, const std::string& path); + +#endif diff --git a/src/keen.h b/src/keen.h index 77d06723b..6c51fa217 100644 --- a/src/keen.h +++ b/src/keen.h @@ -1,864 +1,864 @@ -#include -#include -#include - -#ifdef TARGET_DOS - #include - #include - #include - #include - #include "dos\timer.h" -#endif - -#ifdef TARGET_WIN32 - #include -#endif - -#include "vorticon/sounds.h" -#include "funcdefs.h" -#include "fileio/CTileLoader.h" - -#include "include/playeraction.h" - -#define CSF 5 - -//#define OVSIZE 3000 - -// when crashflag is activated by setting it to QUIT_NONFATAL, -// the application will immediately shut down, however the -// "a Fatal Error Occurred" message box will not pop up and -// the sysbeep will not sound. -#define QUIT_NONFATAL 555 - -#define SAVEGAMEVERSION '4' -#define ATTRFILEVERSION 1 - -#define WM_MAP_NUM 80 - -#define MAX_SPRITES 300 -#define MAX_FONT 256 -#define MAX_BITMAPS 20 - -#define MAX_OBJECTS 100 -#define MAX_ANIMTILES 200 - -#define PAL_FADE_SHADES 20 -#define PAL_FADE_WHITEOUT 40 -typedef struct stFade -{ - int mode; - int dir; - int curamt; - int fadetimer; - int rate; -} stFade; -#define NO_FADE 0 -#define FADE_GO 1 -#define FADE_COMPLETE 2 - -#define FADE_IN 1 -#define FADE_OUT 2 -#define FADE_NORM 3 -#define FADE_FAST 1 -#define FADE_SLOW 30 - -#define NO_QUIT 0 -#define QUIT_PROGRAM 1 -#define QUIT_TO_TITLE 2 - -#define MAX_LEVELS 100 -#define SCROLLBUF_XSIZE 512 -#define SCROLLBUF_YSIZE 512 -#define SCROLLBUF_MEMSIZE ((SCROLLBUF_XSIZE)*(SCROLLBUF_YSIZE+300)) -#define SCROLLBUF_NUMTILESX (SCROLLBUF_XSIZE / 16) -#define SCROLLBUF_NUMTILESY (SCROLLBUF_YSIZE / 16) - -#define BLITBUF_XSIZE 320 -#define BLITBUF_YSIZE 200 -#define BLITBUF_MEMSIZE ((BLITBUF_XSIZE)*(BLITBUF_YSIZE+30)) - // for each entry in the animtileinuse array that is nonzero, that - // location on the display is an animated tile which is currently registered - // in animtiles[]. Used in map_draw_hstripe and map_draw_vstripe. - // When drawing a new stripe over one that previously contained an animated - // tile, this lets it know it needs to unregister the animated tile that - // used to be there. the nonzero value corresponds to the associated entry - // in animtiles[]. the x,y pixel position is the index in here * 16. - #define ATILEINUSE_SIZEX 33 - #define ATILEINUSE_SIZEY 33 - - #define MAX_PLAYERS 8 - - #define WORLD_MAP 80 - #define FINAL_MAP 16 - - #define LVLC_NOCOMMAND 0 - #define LVLC_CHANGE_LEVEL 1 - #define LVLC_END_SEQUENCE 2 - #define LVLC_GAME_OVER 3 - #define LVLC_TANTALUS_RAY 4 // switch on tantalus ray pressed - #define LVLC_START_LEVEL 5 - - -typedef struct stMap -{ - unsigned int xsize, ysize; // size of the map - unsigned char isworldmap; // if 1, this is the world map - unsigned int mapdata[256][256]; // the map data - // in-game, contains monsters and special object tags like for switches - // on world map contains level numbers and flags for things like teleporters - unsigned int objectlayer[256][256]; - char firsttime; // used when generating multiplayer positions on world map -} stMap; - - -// Tile information planes -#define ANIMATION 0 -#define BEHAVIOR 1 -#define BUP 2 -#define BRIGHT 3 -#define BDOWN 4 -#define BLEFT 5 - -typedef struct stBitmap -{ - int xsize; - int ysize; - unsigned char *bmptr; - char name[9]; -} stBitmap; - -typedef struct stSprite -{ - char xsize, ysize; - unsigned char imgdata[64][64]; - unsigned char maskdata[64][64]; - // bounding box for hit detection - unsigned int bboxX1, bboxY1; - unsigned int bboxX2, bboxY2; -} stSprite; - -typedef struct stInventory -{ - unsigned long score; - unsigned long extralifeat; - unsigned int charges; // ray gun ammo - signed int lives; - unsigned char HasPogo; - unsigned char HasCardYellow; - unsigned char HasCardRed; - unsigned char HasCardGreen; - unsigned char HasCardBlue; - // ep1 only - unsigned char HasJoystick; - unsigned char HasFuel; - unsigned char HasBattery; - unsigned char HasVacuum; -} stInventory; - -// for strings loaded from "strings.dat" -#define MAX_STRINGS 100 -#define MAX_ATTRIBUTES 16 -typedef struct stString -{ - unsigned char *name; // pointer to malloc'd area containing string name - unsigned char *stringptr; // pointer to malloc'd area containing string - - int numAttributes; - unsigned char *attrnames[MAX_ATTRIBUTES+1]; - unsigned int attrvalues[MAX_ATTRIBUTES+1]; -} stString; - -/* Structs used for different enemies data, these are in a union */ -typedef struct stYorpData -{ - unsigned char state; - - unsigned char looktimes,lookposition; - unsigned char timer, dietimer; - unsigned char walkframe; - unsigned int dist_traveled; - signed int yorpdie_inertia_y; - - unsigned char movedir; -} stYorpData; -typedef struct stGargData -{ - unsigned char state; - - unsigned char looktimes,lookframe; - unsigned char timer, dietimer, keenonsameleveltimer; - unsigned char about_to_charge; - unsigned char walkframe; - unsigned int dist_traveled; - signed int gargdie_inertia_y; - - unsigned char movedir; - unsigned char detectedPlayer, detectedPlayerIndex; -} stGargData; -typedef struct stVortData -{ - unsigned char state; - - unsigned char timer,timer2; - unsigned int animtimer; - unsigned char palflashtimer, palflashamt; - unsigned char frame; - unsigned int dist_traveled; - signed int inertiay; - - char ep1style; // episode 1 style four-shots-to-kill - - unsigned char movedir; - // these hold the animation frames indexes since they're - // different for each episode - int WalkLeftFrame; - int WalkRightFrame; - int LookFrame; - int JumpRightFrame; - int JumpLeftFrame; - int DyingFrame; - int DeadFrame; -} stVortData; -typedef struct stBearData -{ - unsigned char state; - - unsigned char timer,timer2; - unsigned int animtimer; - unsigned char frame; - signed int inertiay; - unsigned char movedir; - unsigned int timesincefire; - unsigned int running; - - int dist_traveled; -} stBearData; -typedef struct stButlerData -{ - unsigned char state; - unsigned char timer,animtimer; - unsigned char frame; - unsigned int dist_traveled; - - unsigned char movedir; -} stButlerData; -typedef struct stTankData -{ - unsigned char state; - - unsigned char timer,animtimer; - unsigned char frame; - unsigned int dist_traveled; - - unsigned char movedir; - - int ponsameleveltime; - unsigned char alreadyfiredcauseonsamelevel; - unsigned char fireafterlook; - - unsigned char detectedPlayer; // 1 if player on same level - unsigned char detectedPlayerIndex; // index of player that was detected - - // for tank2 - unsigned int timetillnextshot; - unsigned int firetimes; - unsigned int timetillcanfire; - unsigned int timetillcanfirecauseonsamelevel; -} stTankData; -typedef struct stRayData -{ - char state; - char direction; - char zapzottimer; - - char dontHitEnable; - unsigned int dontHit; // index of an object type ray will not harm - - // for soundwave - int animframe, animtimer; - int offscreentime; - - // for earth chunks - int baseframe; -} stRayData; -typedef struct stDoorData -{ - char timer; - char distance_traveled; -} stDoorData; -typedef struct stIceChunk -{ - char movedir; - char state; - unsigned int originalX, originalY; - int timer; -} stIceChunk; -typedef struct stTeleportData -{ - char animtimer; - char animframe; - char numframechanges; - - char direction; - int whichplayer; - unsigned int destx; - signed int desty; - - int baseframe; - int idleframe; - - char NoExitingTeleporter; - char snap; - - char fadeamt; - char fadetimer; -} stTeleportData; -typedef struct stRopeData -{ - char state; - int droptimer; - int droptimes; - int stoneX, stoneY; - int vortboss; -} stRopeData; - -typedef struct stWalkerData -{ - unsigned char state; - - unsigned char animtimer, dietimer; - unsigned char walkframe; - signed int walkerdie_inertia_y; - int fallinctimer,fallspeed; - - unsigned char walkdir; - unsigned char kickedplayer[MAX_PLAYERS]; -} stWalkerData; - -typedef struct stPlatformData -{ - unsigned char state; - unsigned char animframe; - unsigned int animtimer; - unsigned int waittimer; - - unsigned char movedir; - unsigned char kickedplayer[MAX_PLAYERS]; -} stPlatformData; - -typedef struct stSEData -{ - unsigned int type; - - unsigned char state; - unsigned int timer; - unsigned int platx, platy; - unsigned int bgtile; - unsigned int dir; - - int counter,destroytiles; - unsigned int frame; - int mx,my; - int blowx,blowy; -} stSEData; - -typedef struct stBabyData -{ - char state; - char dir; - signed int inertia_x, inertia_y; - int jumpdectimer, xdectimer; - int jumpdecrate; - int dietimer; - - char walkframe; - int walktimer; -} stBabyData; - -typedef struct stFoobData -{ - char state; - char dir; - - int animframe, animtimer; - int OnSameLevelTime; - int OffOfSameLevelTime; - int spooktimer; - int SpookedByWho; -} stFoobData; - -typedef struct stNinjaData -{ - char state; - char dir; - - int animframe, animtimer; - unsigned int timetillkick; - - signed int XInertia, YInertia; - unsigned int XFrictionTimer, YFrictionTimer; - unsigned int XFrictionRate, YFrictionRate; - int KickMoveTimer; - int isdying; - int dietimer; -} stNinjaData; - -typedef struct stMotherData -{ - char state; - char dir; - char hittimes; - - int animframe, animtimer; - int timer; -} stMotherData; - -typedef struct stMeepData -{ - char state; - char dir; - - int animframe, animtimer; - int timer; -} stMeepData; - -typedef struct stBallJackData -{ - char dir; - int animframe, animtimer; - int speed; -} stBallJackData; - -#define NESSIETRAILLEN 5 -typedef struct stNessieData -{ - char state; - char leftrightdir, updowndir; - unsigned int baseframe; - - unsigned int tiletrailX[NESSIETRAILLEN+1]; - unsigned int tiletrailY[NESSIETRAILLEN+1]; - int tiletrailhead; - - char animframe, animtimer; - unsigned int destx, desty; - - unsigned int pausetimer; - unsigned int pausex, pausey; - - unsigned int mortimer_swim_amt; - unsigned int mounted[MAX_PLAYERS]; -} stNessieData; - -// and the object structure containing the union of the above structs -typedef struct stObject -{ - unsigned int type; // yorp, vorticon, etc. - unsigned int exists; - unsigned int onscreen; // 1=(scrx,scry) position is visible onscreen - unsigned int hasbeenonscreen; - unsigned int sprite; // which sprite should this object be drawn with - unsigned int x, y; // x,y location in map coords, CSFed - int scrx, scry; // x,y pixel position on screen - - // if type is OBJ_PLAYER, this contains the player number that this object - // is associated with - int AssociatedWithPlayer; - - // if zero, priority tiles will not be honored and object will always - // appear in front of the background - char honorPriority; - - char canbezapped; // if 0 ray will not stop on hitdetect - char zapped; // number of times got hit by keen's raygun - - char inhibitfall; // if 1 common_enemy_ai will not do falling - char cansupportplayer[MAX_PLAYERS]; - - unsigned int blockedl, blockedr, blockedu, blockedd; - signed int xinertia, yinertia; - unsigned char xinertiatimer, yinertiatimer; - - unsigned char touchPlayer; // 1=hit detection with player - unsigned char touchedBy; // which player was hit - // Y position on this object the hit was detected - // this is used for the yorps' bonk-on-the-head thing. - // objects are scanned bottom to top, and first pixel - // touching player is what goes in here. - unsigned char hity; - - unsigned int needinit; // 1=new object--requires initilization - unsigned char wasoffscreen; // set to 1 when object goes offscreen - // data for ai and such, used differently depending on - // what kind of object it is - union ai - { - // ep1 - stYorpData yorp; - stGargData garg; - stVortData vort; - stButlerData butler; - stTankData tank; - stRayData ray; - stDoorData door; - stIceChunk icechunk; - stTeleportData teleport; - stRopeData rope; - // ep2 - stWalkerData walker; - stPlatformData platform; - stBearData bear; - stSEData se; - stBabyData baby; - // ep3 - stFoobData foob; - stNinjaData ninja; - stMeepData meep; - stMotherData mother; - stBallJackData bj; - stNessieData nessie; - } ai; - unsigned char erasedata[64][64]; // backbuffer to erase this object -} stObject; - -// (map) stripe attribute structures, for animated tiles -// slot 0 is not used. data starts at slot 1. see description -// of AnimTileInUse in map structure to see why. -typedef struct stAnimTile -{ - int slotinuse; // if 0, this entry should not be drawn - int x; // x pixel position in scrollbuf[] where tile is - int y; // y pixel position in scrollbuf[] - int baseframe; // base frame, i.e. the first frame of animation - int offset; // offset from base frame -} stAnimTile; - -#define NUM_OBJ_TYPES 40 -// ** objects from KEEN1 -#define OBJ_YORP 1 -#define OBJ_GARG 2 -#define OBJ_VORT 3 -#define OBJ_BUTLER 4 -#define OBJ_TANK 5 -#define OBJ_RAY 6 // keen's raygun blast -#define OBJ_DOOR 7 // an opening door -#define OBJ_ICECHUNK 8 // ice chunk from ice cannon -#define OBJ_ICEBIT 9 // piece of shattered ice chunk -#define OBJ_PLAYER 10 -#define OBJ_TELEPORTER 11 // world map teleporter -#define OBJ_ROPE 12 - -// ** objects from KEEN2 (some of these are in ep3 as well) -#define OBJ_WALKER 13 -#define OBJ_TANKEP2 14 -#define OBJ_PLATFORM 15 -#define OBJ_BEAR 16 -#define OBJ_SECTOREFFECTOR 17 -#define OBJ_BABY 18 -#define OBJ_EXPLOSION 19 -#define OBJ_EARTHCHUNK 20 - -// ** objects from KEEN3 -#define OBJ_FOOB 21 -#define OBJ_NINJA 22 -#define OBJ_MEEP 23 -#define OBJ_SNDWAVE 24 -#define OBJ_MOTHER 25 -#define OBJ_FIREBALL 26 -#define OBJ_BALL 27 -#define OBJ_JACK 28 -#define OBJ_PLATVERT 29 -#define OBJ_NESSIE 30 - -#define OBJ_DEMOMSG 31 - -// default sprites...when an object is spawned it's sprite is set to this -// sprite. the object AI will immediately reset the sprite frame, so it -// wouldn't really matter what these are...except that it does because -// the width and height of the default sprite will determine exactly when -// the object because active the first time it scrolls onto the screen -// from the top or left. if the default sprite is wrong the object may -// suddenly appear on the screen instead of smoothly scrolling on. -#define OBJ_YORP_DEFSPRITE 50 -#define OBJ_GARG_DEFSPRITE 60 -#define OBJ_VORT_DEFSPRITE_EP1 78 -#define OBJ_VORT_DEFSPRITE_EP2 82 -#define OBJ_VORT_DEFSPRITE_EP3 71 -#define OBJ_BUTLER_DEFSPRITE 88 -#define OBJ_TANK_DEFSPRITE 98 -#define OBJ_RAY_DEFSPRITE_EP1 108 -#define OBJ_RAY_DEFSPRITE_EP2 122 -#define OBJ_RAY_DEFSPRITE_EP3 102 -#define OBJ_ICECHUNK_DEFSPRITE 112 -#define OBJ_ICEBIT_DEFSPRITE 113 -#define OBJ_TELEPORTER_DEFSPRITE 180 -#define OBJ_ROPE_DEFSPRITE 184 - -#define OBJ_PLATFORM_DEFSPRITE_EP2 126 -#define OBJ_PLATFORM_DEFSPRITE_EP3 107 -#define OBJ_WALKER_DEFSPRITE 102 -#define OBJ_TANKEP2_DEFSPRITE 112 -#define OBJ_BEAR_DEFSPRITE 88 - -#define OBJ_FOOB_DEFSPRITE 95 -#define OBJ_NINJA_DEFSPRITE 77 -#define OBJ_MOTHER_DEFSPRITE 87 -#define OBJ_BJ_DEFSPRITE 109 -#define OBJ_MEEP_DEFSPRITE 118 - -#define OBJ_BABY_DEFSPRITE_EP2 52 -#define OBJ_BABY_DEFSPRITE_EP3 51 - - -// some directions (mostly for OBJ_ICECHUNK and OBJ_ICEBIT) -#define DUPRIGHT 0 -#define DUPLEFT 1 -#define DUP 2 -#define DDOWN 3 -#define DDOWNRIGHT 4 -#define DDOWNLEFT 5 -#define DLEFT 6 -#define DRIGHT 7 - -// directions for OBJ_EARTHCHUNK -#define EC_UPLEFTLEFT 0 // 22 degrees CC of UP/LEFT -#define EC_UPUPLEFT 1 // 22 degrees C of UP/LEFT -#define EC_UP 2 // straight UP -#define EC_UPUPRIGHT 3 // 22 degrees CC of UP/RIGHT -#define EC_UPRIGHTRIGHT 4 // 22 degrees C of UP/RIGHT -#define EC_DOWNLEFTLEFT 5 // 22 degrees CC of DOWN/LEFT -#define EC_DOWNDOWNLEFT 6 // 22 degrees C of DOWN/LEFT -#define EC_DOWN 7 // straight DOWN -#define EC_DOWNDOWNRIGHT 8 // 22 degrees CC of DOWN/RIGHT -#define EC_DOWNRIGHTRIGHT 9 // 22 degrees C of DOWN/RIGHT - -#define EC_UPLEFT 10 -#define EC_UPRIGHT 11 -#define EC_DOWNLEFT 12 -#define EC_DOWNRIGHT 13 - -// scroll triggers -#define SCROLLTRIGGERRIGHT 194 -#define SCROLLTRIGGERLEFT 110 -#define SCROLLTRIGGERUP 80 -#define SCROLLTRIGGERDOWN 114 - -// this structure contains all the variables used by a player -typedef struct stPlayer -{ - // these coordinates are CSFed - unsigned long x; - unsigned int y; - - unsigned int w; - unsigned int h; - - char isPlaying; - int useObject; - - char godmode; - - // used on world map only - char hideplayer; - char mounted; - - short treshold; // This is used for analog devices like joysticks - signed int pinertia_y; - - unsigned long mapplayx; - signed int mapplayy; - - unsigned char playframe; - - unsigned char pfalling,plastfalling,pfallspeed,pfallspeed_increasetimer; - - unsigned char pwalking,playspeed; - unsigned char pslowingdown; - unsigned char pwalkframe,pwalkframea,pwalkanimtimer; - unsigned char pwalkincreasetimer, pfriction_timer_x, pfriction_timer_y; - signed int pinertia_x,pboost_x,playpushed_x; - int chargedjump; - unsigned char playpushed_decreasetimer; - bool widejump; - - unsigned char blockedl,blockedr,blockedu,blockedd; - unsigned int blockedby; - - unsigned char pjumping, pjumptime, pjumpupspeed_decreasetimer, pjumpdir; - unsigned char pjumpframe, pjumpanimtimer, pjumpupspeed; - unsigned char pjumpnormaltime, pjumpupdecreaserate, pjustjumped; - unsigned char pjustfell; - unsigned char pjumpfloattimer; - - unsigned char pdir,pshowdir,lastpdir; - - char pfiring,pfireframetimer; - char inhibitwalking, inhibitfall; - - int ctrltimer, alttimer; - char keyprocstate; - char wm_lastenterstate; - - char pdie, pdieframe, pdietimer; - int pdietillfly; - signed int pdie_xvect; - int psupportingtile, psupportingobject, lastsupportingobject; - char psliding; - char psemisliding; - bool ppogostick; - int pfrozentime,pfrozenframe,pfrozenanimtimer; - - unsigned char keytable[50]; - unsigned char lastkeytable[50]; - - - // New values - char playcontrol[PA_MAX_ACTIONS]; - char lastplaycontrol[PA_MAX_ACTIONS]; - - char x_friction; - char y_friction; - - // End new values - - unsigned char dpadcount, dpadlastcount; - - unsigned int ankhtime, ankhshieldobject; - - stInventory inventory; -} stPlayer; - -typedef struct stShipQueue -{ - int cmd; - int time; - int flag1; -} stShipQueue; - - -#define TILE_LITTLE_DONE 77 -#define TILE_BIG_DONE1 78 -#define TILE_BIG_DONE2 79 -#define TILE_BIG_DONE3 80 -#define TILE_BIG_DONE4 81 - -#define TILE_TELEPORTER_GREY_IDLE 99 -#define TILE_TELEPORTER_RED_INUSE 338 - -// special level codes on worldmap -#define LVLS_TELEPORTER_BONUS 46 // bonus teleporter in ep1 -#define LVLS_SHIP 20 - -#define TELEPORTING_OUT 0 -#define TELEPORTING_IN 1 - -#define TELEPORT_BONUS_DESTX ((((23085>>CSF>>4)+2)<<4<>CSF>>4)+2)<<4< -#include "include/declarations.h" -#include "keenext.h" -#include "sdl/CSettings.h" - -typedef struct stCloneKeenPlus -{ - stCommand Command[MAX_COMMANDS]; - SDL_Joystick *Joystick; - SDL_Event Event; - stResources Resources; - stGameData *GameData; - stDevice Device; - stControl Control; - stOption Option[NUM_OPTIONS]; - unsigned short numGames; - unsigned short shutdown; -}stCloneKeenPlus; - -// keen.c -void playgame_levelmanager(stCloneKeenPlus *pCKP); -char play_demo(int demonum, stCloneKeenPlus *pCKP, int s); +#include +#include +#include + +#ifdef TARGET_DOS + #include + #include + #include + #include + #include "dos\timer.h" +#endif + +#ifdef TARGET_WIN32 + #include +#endif + +#include "vorticon/sounds.h" +#include "funcdefs.h" +#include "fileio/CTileLoader.h" + +#include "include/playeraction.h" + +#define CSF 5 + +//#define OVSIZE 3000 + +// when crashflag is activated by setting it to QUIT_NONFATAL, +// the application will immediately shut down, however the +// "a Fatal Error Occurred" message box will not pop up and +// the sysbeep will not sound. +#define QUIT_NONFATAL 555 + +#define SAVEGAMEVERSION '4' +#define ATTRFILEVERSION 1 + +#define WM_MAP_NUM 80 + +#define MAX_SPRITES 300 +#define MAX_FONT 256 +#define MAX_BITMAPS 20 + +#define MAX_OBJECTS 100 +#define MAX_ANIMTILES 200 + +#define PAL_FADE_SHADES 20 +#define PAL_FADE_WHITEOUT 40 +typedef struct stFade +{ + int mode; + int dir; + int curamt; + int fadetimer; + int rate; +} stFade; +#define NO_FADE 0 +#define FADE_GO 1 +#define FADE_COMPLETE 2 + +#define FADE_IN 1 +#define FADE_OUT 2 +#define FADE_NORM 3 +#define FADE_FAST 1 +#define FADE_SLOW 30 + +#define NO_QUIT 0 +#define QUIT_PROGRAM 1 +#define QUIT_TO_TITLE 2 + +#define MAX_LEVELS 100 +#define SCROLLBUF_XSIZE 512 +#define SCROLLBUF_YSIZE 512 +#define SCROLLBUF_MEMSIZE ((SCROLLBUF_XSIZE)*(SCROLLBUF_YSIZE+300)) +#define SCROLLBUF_NUMTILESX (SCROLLBUF_XSIZE / 16) +#define SCROLLBUF_NUMTILESY (SCROLLBUF_YSIZE / 16) + +#define BLITBUF_XSIZE 320 +#define BLITBUF_YSIZE 200 +#define BLITBUF_MEMSIZE ((BLITBUF_XSIZE)*(BLITBUF_YSIZE+30)) + // for each entry in the animtileinuse array that is nonzero, that + // location on the display is an animated tile which is currently registered + // in animtiles[]. Used in map_draw_hstripe and map_draw_vstripe. + // When drawing a new stripe over one that previously contained an animated + // tile, this lets it know it needs to unregister the animated tile that + // used to be there. the nonzero value corresponds to the associated entry + // in animtiles[]. the x,y pixel position is the index in here * 16. + #define ATILEINUSE_SIZEX 33 + #define ATILEINUSE_SIZEY 33 + + #define MAX_PLAYERS 8 + + #define WORLD_MAP 80 + #define FINAL_MAP 16 + + #define LVLC_NOCOMMAND 0 + #define LVLC_CHANGE_LEVEL 1 + #define LVLC_END_SEQUENCE 2 + #define LVLC_GAME_OVER 3 + #define LVLC_TANTALUS_RAY 4 // switch on tantalus ray pressed + #define LVLC_START_LEVEL 5 + + +typedef struct stMap +{ + unsigned int xsize, ysize; // size of the map + unsigned char isworldmap; // if 1, this is the world map + unsigned int mapdata[256][256]; // the map data + // in-game, contains monsters and special object tags like for switches + // on world map contains level numbers and flags for things like teleporters + unsigned int objectlayer[256][256]; + char firsttime; // used when generating multiplayer positions on world map +} stMap; + + +// Tile information planes +#define ANIMATION 0 +#define BEHAVIOR 1 +#define BUP 2 +#define BRIGHT 3 +#define BDOWN 4 +#define BLEFT 5 + +typedef struct stBitmap +{ + int xsize; + int ysize; + unsigned char *bmptr; + char name[9]; +} stBitmap; + +typedef struct stSprite +{ + char xsize, ysize; + unsigned char imgdata[64][64]; + unsigned char maskdata[64][64]; + // bounding box for hit detection + unsigned int bboxX1, bboxY1; + unsigned int bboxX2, bboxY2; +} stSprite; + +typedef struct stInventory +{ + unsigned long score; + unsigned long extralifeat; + unsigned int charges; // ray gun ammo + signed int lives; + unsigned char HasPogo; + unsigned char HasCardYellow; + unsigned char HasCardRed; + unsigned char HasCardGreen; + unsigned char HasCardBlue; + // ep1 only + unsigned char HasJoystick; + unsigned char HasFuel; + unsigned char HasBattery; + unsigned char HasVacuum; +} stInventory; + +// for strings loaded from "strings.dat" +#define MAX_STRINGS 100 +#define MAX_ATTRIBUTES 16 +struct stString +{ + std::string name; // pointer to malloc'd area containing string name + std::string stringptr; // pointer to malloc'd area containing string + + int numAttributes; + unsigned char *attrnames[MAX_ATTRIBUTES+1]; + unsigned int attrvalues[MAX_ATTRIBUTES+1]; +}; + +/* Structs used for different enemies data, these are in a union */ +typedef struct stYorpData +{ + unsigned char state; + + unsigned char looktimes,lookposition; + unsigned char timer, dietimer; + unsigned char walkframe; + unsigned int dist_traveled; + signed int yorpdie_inertia_y; + + unsigned char movedir; +} stYorpData; +typedef struct stGargData +{ + unsigned char state; + + unsigned char looktimes,lookframe; + unsigned char timer, dietimer, keenonsameleveltimer; + unsigned char about_to_charge; + unsigned char walkframe; + unsigned int dist_traveled; + signed int gargdie_inertia_y; + + unsigned char movedir; + unsigned char detectedPlayer, detectedPlayerIndex; +} stGargData; +typedef struct stVortData +{ + unsigned char state; + + unsigned char timer,timer2; + unsigned int animtimer; + unsigned char palflashtimer, palflashamt; + unsigned char frame; + unsigned int dist_traveled; + signed int inertiay; + + char ep1style; // episode 1 style four-shots-to-kill + + unsigned char movedir; + // these hold the animation frames indexes since they're + // different for each episode + int WalkLeftFrame; + int WalkRightFrame; + int LookFrame; + int JumpRightFrame; + int JumpLeftFrame; + int DyingFrame; + int DeadFrame; +} stVortData; +typedef struct stBearData +{ + unsigned char state; + + unsigned char timer,timer2; + unsigned int animtimer; + unsigned char frame; + signed int inertiay; + unsigned char movedir; + unsigned int timesincefire; + unsigned int running; + + int dist_traveled; +} stBearData; +typedef struct stButlerData +{ + unsigned char state; + unsigned char timer,animtimer; + unsigned char frame; + unsigned int dist_traveled; + + unsigned char movedir; +} stButlerData; +typedef struct stTankData +{ + unsigned char state; + + unsigned char timer,animtimer; + unsigned char frame; + unsigned int dist_traveled; + + unsigned char movedir; + + int ponsameleveltime; + unsigned char alreadyfiredcauseonsamelevel; + unsigned char fireafterlook; + + unsigned char detectedPlayer; // 1 if player on same level + unsigned char detectedPlayerIndex; // index of player that was detected + + // for tank2 + unsigned int timetillnextshot; + unsigned int firetimes; + unsigned int timetillcanfire; + unsigned int timetillcanfirecauseonsamelevel; +} stTankData; +typedef struct stRayData +{ + char state; + char direction; + char zapzottimer; + + char dontHitEnable; + unsigned int dontHit; // index of an object type ray will not harm + + // for soundwave + int animframe, animtimer; + int offscreentime; + + // for earth chunks + int baseframe; +} stRayData; +typedef struct stDoorData +{ + char timer; + char distance_traveled; +} stDoorData; +typedef struct stIceChunk +{ + char movedir; + char state; + unsigned int originalX, originalY; + int timer; +} stIceChunk; +typedef struct stTeleportData +{ + char animtimer; + char animframe; + char numframechanges; + + char direction; + int whichplayer; + unsigned int destx; + signed int desty; + + int baseframe; + int idleframe; + + char NoExitingTeleporter; + char snap; + + char fadeamt; + char fadetimer; +} stTeleportData; +typedef struct stRopeData +{ + char state; + int droptimer; + int droptimes; + int stoneX, stoneY; + int vortboss; +} stRopeData; + +typedef struct stWalkerData +{ + unsigned char state; + + unsigned char animtimer, dietimer; + unsigned char walkframe; + signed int walkerdie_inertia_y; + int fallinctimer,fallspeed; + + unsigned char walkdir; + unsigned char kickedplayer[MAX_PLAYERS]; +} stWalkerData; + +typedef struct stPlatformData +{ + unsigned char state; + unsigned char animframe; + unsigned int animtimer; + unsigned int waittimer; + + unsigned char movedir; + unsigned char kickedplayer[MAX_PLAYERS]; +} stPlatformData; + +typedef struct stSEData +{ + unsigned int type; + + unsigned char state; + unsigned int timer; + unsigned int platx, platy; + unsigned int bgtile; + unsigned int dir; + + int counter,destroytiles; + unsigned int frame; + int mx,my; + int blowx,blowy; +} stSEData; + +typedef struct stBabyData +{ + char state; + char dir; + signed int inertia_x, inertia_y; + int jumpdectimer, xdectimer; + int jumpdecrate; + int dietimer; + + char walkframe; + int walktimer; +} stBabyData; + +typedef struct stFoobData +{ + char state; + char dir; + + int animframe, animtimer; + int OnSameLevelTime; + int OffOfSameLevelTime; + int spooktimer; + int SpookedByWho; +} stFoobData; + +typedef struct stNinjaData +{ + char state; + char dir; + + int animframe, animtimer; + unsigned int timetillkick; + + signed int XInertia, YInertia; + unsigned int XFrictionTimer, YFrictionTimer; + unsigned int XFrictionRate, YFrictionRate; + int KickMoveTimer; + int isdying; + int dietimer; +} stNinjaData; + +typedef struct stMotherData +{ + char state; + char dir; + char hittimes; + + int animframe, animtimer; + int timer; +} stMotherData; + +typedef struct stMeepData +{ + char state; + char dir; + + int animframe, animtimer; + int timer; +} stMeepData; + +typedef struct stBallJackData +{ + char dir; + int animframe, animtimer; + int speed; +} stBallJackData; + +#define NESSIETRAILLEN 5 +typedef struct stNessieData +{ + char state; + char leftrightdir, updowndir; + unsigned int baseframe; + + unsigned int tiletrailX[NESSIETRAILLEN+1]; + unsigned int tiletrailY[NESSIETRAILLEN+1]; + int tiletrailhead; + + char animframe, animtimer; + unsigned int destx, desty; + + unsigned int pausetimer; + unsigned int pausex, pausey; + + unsigned int mortimer_swim_amt; + unsigned int mounted[MAX_PLAYERS]; +} stNessieData; + +// and the object structure containing the union of the above structs +typedef struct stObject +{ + unsigned int type; // yorp, vorticon, etc. + unsigned int exists; + unsigned int onscreen; // 1=(scrx,scry) position is visible onscreen + unsigned int hasbeenonscreen; + unsigned int sprite; // which sprite should this object be drawn with + unsigned int x, y; // x,y location in map coords, CSFed + int scrx, scry; // x,y pixel position on screen + + // if type is OBJ_PLAYER, this contains the player number that this object + // is associated with + int AssociatedWithPlayer; + + // if zero, priority tiles will not be honored and object will always + // appear in front of the background + char honorPriority; + + char canbezapped; // if 0 ray will not stop on hitdetect + char zapped; // number of times got hit by keen's raygun + + char inhibitfall; // if 1 common_enemy_ai will not do falling + char cansupportplayer[MAX_PLAYERS]; + + unsigned int blockedl, blockedr, blockedu, blockedd; + signed int xinertia, yinertia; + unsigned char xinertiatimer, yinertiatimer; + + unsigned char touchPlayer; // 1=hit detection with player + unsigned char touchedBy; // which player was hit + // Y position on this object the hit was detected + // this is used for the yorps' bonk-on-the-head thing. + // objects are scanned bottom to top, and first pixel + // touching player is what goes in here. + unsigned char hity; + + unsigned int needinit; // 1=new object--requires initilization + unsigned char wasoffscreen; // set to 1 when object goes offscreen + // data for ai and such, used differently depending on + // what kind of object it is + union ai + { + // ep1 + stYorpData yorp; + stGargData garg; + stVortData vort; + stButlerData butler; + stTankData tank; + stRayData ray; + stDoorData door; + stIceChunk icechunk; + stTeleportData teleport; + stRopeData rope; + // ep2 + stWalkerData walker; + stPlatformData platform; + stBearData bear; + stSEData se; + stBabyData baby; + // ep3 + stFoobData foob; + stNinjaData ninja; + stMeepData meep; + stMotherData mother; + stBallJackData bj; + stNessieData nessie; + } ai; + unsigned char erasedata[64][64]; // backbuffer to erase this object +} stObject; + +// (map) stripe attribute structures, for animated tiles +// slot 0 is not used. data starts at slot 1. see description +// of AnimTileInUse in map structure to see why. +typedef struct stAnimTile +{ + int slotinuse; // if 0, this entry should not be drawn + int x; // x pixel position in scrollbuf[] where tile is + int y; // y pixel position in scrollbuf[] + int baseframe; // base frame, i.e. the first frame of animation + int offset; // offset from base frame +} stAnimTile; + +#define NUM_OBJ_TYPES 40 +// ** objects from KEEN1 +#define OBJ_YORP 1 +#define OBJ_GARG 2 +#define OBJ_VORT 3 +#define OBJ_BUTLER 4 +#define OBJ_TANK 5 +#define OBJ_RAY 6 // keen's raygun blast +#define OBJ_DOOR 7 // an opening door +#define OBJ_ICECHUNK 8 // ice chunk from ice cannon +#define OBJ_ICEBIT 9 // piece of shattered ice chunk +#define OBJ_PLAYER 10 +#define OBJ_TELEPORTER 11 // world map teleporter +#define OBJ_ROPE 12 + +// ** objects from KEEN2 (some of these are in ep3 as well) +#define OBJ_WALKER 13 +#define OBJ_TANKEP2 14 +#define OBJ_PLATFORM 15 +#define OBJ_BEAR 16 +#define OBJ_SECTOREFFECTOR 17 +#define OBJ_BABY 18 +#define OBJ_EXPLOSION 19 +#define OBJ_EARTHCHUNK 20 + +// ** objects from KEEN3 +#define OBJ_FOOB 21 +#define OBJ_NINJA 22 +#define OBJ_MEEP 23 +#define OBJ_SNDWAVE 24 +#define OBJ_MOTHER 25 +#define OBJ_FIREBALL 26 +#define OBJ_BALL 27 +#define OBJ_JACK 28 +#define OBJ_PLATVERT 29 +#define OBJ_NESSIE 30 + +#define OBJ_DEMOMSG 31 + +// default sprites...when an object is spawned it's sprite is set to this +// sprite. the object AI will immediately reset the sprite frame, so it +// wouldn't really matter what these are...except that it does because +// the width and height of the default sprite will determine exactly when +// the object because active the first time it scrolls onto the screen +// from the top or left. if the default sprite is wrong the object may +// suddenly appear on the screen instead of smoothly scrolling on. +#define OBJ_YORP_DEFSPRITE 50 +#define OBJ_GARG_DEFSPRITE 60 +#define OBJ_VORT_DEFSPRITE_EP1 78 +#define OBJ_VORT_DEFSPRITE_EP2 82 +#define OBJ_VORT_DEFSPRITE_EP3 71 +#define OBJ_BUTLER_DEFSPRITE 88 +#define OBJ_TANK_DEFSPRITE 98 +#define OBJ_RAY_DEFSPRITE_EP1 108 +#define OBJ_RAY_DEFSPRITE_EP2 122 +#define OBJ_RAY_DEFSPRITE_EP3 102 +#define OBJ_ICECHUNK_DEFSPRITE 112 +#define OBJ_ICEBIT_DEFSPRITE 113 +#define OBJ_TELEPORTER_DEFSPRITE 180 +#define OBJ_ROPE_DEFSPRITE 184 + +#define OBJ_PLATFORM_DEFSPRITE_EP2 126 +#define OBJ_PLATFORM_DEFSPRITE_EP3 107 +#define OBJ_WALKER_DEFSPRITE 102 +#define OBJ_TANKEP2_DEFSPRITE 112 +#define OBJ_BEAR_DEFSPRITE 88 + +#define OBJ_FOOB_DEFSPRITE 95 +#define OBJ_NINJA_DEFSPRITE 77 +#define OBJ_MOTHER_DEFSPRITE 87 +#define OBJ_BJ_DEFSPRITE 109 +#define OBJ_MEEP_DEFSPRITE 118 + +#define OBJ_BABY_DEFSPRITE_EP2 52 +#define OBJ_BABY_DEFSPRITE_EP3 51 + + +// some directions (mostly for OBJ_ICECHUNK and OBJ_ICEBIT) +#define DUPRIGHT 0 +#define DUPLEFT 1 +#define DUP 2 +#define DDOWN 3 +#define DDOWNRIGHT 4 +#define DDOWNLEFT 5 +#define DLEFT 6 +#define DRIGHT 7 + +// directions for OBJ_EARTHCHUNK +#define EC_UPLEFTLEFT 0 // 22 degrees CC of UP/LEFT +#define EC_UPUPLEFT 1 // 22 degrees C of UP/LEFT +#define EC_UP 2 // straight UP +#define EC_UPUPRIGHT 3 // 22 degrees CC of UP/RIGHT +#define EC_UPRIGHTRIGHT 4 // 22 degrees C of UP/RIGHT +#define EC_DOWNLEFTLEFT 5 // 22 degrees CC of DOWN/LEFT +#define EC_DOWNDOWNLEFT 6 // 22 degrees C of DOWN/LEFT +#define EC_DOWN 7 // straight DOWN +#define EC_DOWNDOWNRIGHT 8 // 22 degrees CC of DOWN/RIGHT +#define EC_DOWNRIGHTRIGHT 9 // 22 degrees C of DOWN/RIGHT + +#define EC_UPLEFT 10 +#define EC_UPRIGHT 11 +#define EC_DOWNLEFT 12 +#define EC_DOWNRIGHT 13 + +// scroll triggers +#define SCROLLTRIGGERRIGHT 194 +#define SCROLLTRIGGERLEFT 110 +#define SCROLLTRIGGERUP 80 +#define SCROLLTRIGGERDOWN 114 + +// this structure contains all the variables used by a player +typedef struct stPlayer +{ + // these coordinates are CSFed + unsigned long x; + unsigned int y; + + unsigned int w; + unsigned int h; + + char isPlaying; + int useObject; + + char godmode; + + // used on world map only + char hideplayer; + char mounted; + + short treshold; // This is used for analog devices like joysticks + signed int pinertia_y; + + unsigned long mapplayx; + signed int mapplayy; + + unsigned char playframe; + + unsigned char pfalling,plastfalling,pfallspeed,pfallspeed_increasetimer; + + unsigned char pwalking,playspeed; + unsigned char pslowingdown; + unsigned char pwalkframe,pwalkframea,pwalkanimtimer; + unsigned char pwalkincreasetimer, pfriction_timer_x, pfriction_timer_y; + signed int pinertia_x,pboost_x,playpushed_x; + int chargedjump; + unsigned char playpushed_decreasetimer; + bool widejump; + + unsigned char blockedl,blockedr,blockedu,blockedd; + unsigned int blockedby; + + unsigned char pjumping, pjumptime, pjumpupspeed_decreasetimer, pjumpdir; + unsigned char pjumpframe, pjumpanimtimer, pjumpupspeed; + unsigned char pjumpnormaltime, pjumpupdecreaserate, pjustjumped; + unsigned char pjustfell; + unsigned char pjumpfloattimer; + + unsigned char pdir,pshowdir,lastpdir; + + char pfiring,pfireframetimer; + char inhibitwalking, inhibitfall; + + int ctrltimer, alttimer; + char keyprocstate; + char wm_lastenterstate; + + char pdie, pdieframe, pdietimer; + int pdietillfly; + signed int pdie_xvect; + int psupportingtile, psupportingobject, lastsupportingobject; + char psliding; + char psemisliding; + bool ppogostick; + int pfrozentime,pfrozenframe,pfrozenanimtimer; + + unsigned char keytable[50]; + unsigned char lastkeytable[50]; + + + // New values + char playcontrol[PA_MAX_ACTIONS]; + char lastplaycontrol[PA_MAX_ACTIONS]; + + char x_friction; + char y_friction; + + // End new values + + unsigned char dpadcount, dpadlastcount; + + unsigned int ankhtime, ankhshieldobject; + + stInventory inventory; +} stPlayer; + +typedef struct stShipQueue +{ + int cmd; + int time; + int flag1; +} stShipQueue; + + +#define TILE_LITTLE_DONE 77 +#define TILE_BIG_DONE1 78 +#define TILE_BIG_DONE2 79 +#define TILE_BIG_DONE3 80 +#define TILE_BIG_DONE4 81 + +#define TILE_TELEPORTER_GREY_IDLE 99 +#define TILE_TELEPORTER_RED_INUSE 338 + +// special level codes on worldmap +#define LVLS_TELEPORTER_BONUS 46 // bonus teleporter in ep1 +#define LVLS_SHIP 20 + +#define TELEPORTING_OUT 0 +#define TELEPORTING_IN 1 + +#define TELEPORT_BONUS_DESTX ((((23085>>CSF>>4)+2)<<4<>CSF>>4)+2)<<4< +#include "include/declarations.h" +#include "keenext.h" +#include "sdl/CSettings.h" + +typedef struct stCloneKeenPlus +{ + stCommand Command[MAX_COMMANDS]; + SDL_Joystick *Joystick; + SDL_Event Event; + stResources Resources; + stGameData *GameData; + stDevice Device; + stControl Control; + stOption Option[NUM_OPTIONS]; + unsigned short numGames; + unsigned short shutdown; +}stCloneKeenPlus; + +// keen.c +void playgame_levelmanager(stCloneKeenPlus *pCKP); +char play_demo(int demonum, stCloneKeenPlus *pCKP, int s); diff --git a/src/main.cpp b/src/main.cpp index 5d27463e2..aca842fed 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -572,6 +572,7 @@ demoHeaderCorrupt: ; short readCommandLine(int argc, char *argv[], stCloneKeenPlus *pCKP) { int i; + static const int MAX_STRING_LENGTH = 256; char tempbuf[MAX_STRING_LENGTH]; diff --git a/src/menu.cpp b/src/menu.cpp index b11c07154..cda465583 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -1,1448 +1,1448 @@ - /* MENU.C - The main menu, intro, and other such stuff. -*/ - -#include "keen.h" -#include "pressf10.h" -#include "include/menu.h" -#include "include/misc.h" -#include "sdl/CVideoDriver.h" -#include "include/game.h" -#include "include/gamedo.h" -#include "sdl/CTimer.h" -#include "sdl/sound/CSound.h" -#include "include/eseq_ep2.h" -#include "include/fileio.h" -#include "include/gm_pdowm.h" -#include "include/gamedo.h" -#include "include/main.h" -#include "CGraphics.h" -#include "sdl/video/colourtable.h" -#include "include/gui/dialog.h" -#include "sdl/CInput.h" -#include "vorticon/CDialog.h" -#include "CLogFile.h" -#include "sdl/CSettings.h" -#include -#include -#include -using namespace std; - -#define SELMOVE_SPD 3 - -short openDlgStruct(stDlgStruct *pDlgStruct, stCloneKeenPlus *pCKP); - -void showmapatpos(int level, int xoff, int yoff, int wm, stCloneKeenPlus *pCKP) -{ -int i; -char levelname[MAX_STRING_LENGTH]; -g_pLogFile->ftextOut("showmapatpos(%d, %d, %d, %d);
",level,xoff,yoff,wm); - pCKP->Control.levelcontrol.dark = 0; - g_pGraphics->initPalette(pCKP->Control.levelcontrol.dark); - - initgame(pCKP); // reset scroll - memset(levelname,0,MAX_STRING_LENGTH*sizeof(char)); - sprintf(levelname, "level%02d.ck%d", level, pCKP->Control.levelcontrol.episode); - - short numsel; - if(pCKP->Resources.GameSelected == 0 ) // First time startup. No game has been chosen - numsel = 0; - else - numsel = pCKP->Resources.GameSelected-1; - - loadmap(levelname, pCKP->GameData[numsel].DataDirectory, level, wm, pCKP); - - drawmap(); - for(i=0;isb_blit(); -} - -short loadResourcesforStartMenu(stCloneKeenPlus *pCKP, CGame *Game) -{ - string line; - - ifstream gamescfg("data/games.cfg"); - - if (gamescfg.is_open()) - { - while ( !gamescfg.eof() && pCKP->numGames < 20 ) - { - getline (gamescfg,line); - - if(strncmp(line.data(),"[",strlen("[")) == 0) - { - stGameData *NewGameData; - - pCKP->numGames++; - NewGameData = new stGameData[pCKP->numGames]; - memset(NewGameData,0,pCKP->numGames*sizeof(stGameData)); - memcpy(NewGameData,pCKP->GameData,(pCKP->numGames-1)*sizeof(stGameData)); - - delete[] pCKP->GameData; - - pCKP->GameData = NewGameData; - } - if(strncmp(line.data(),"Name=",strlen("Name=")) == 0) - { - line.copy(pCKP->GameData[pCKP->numGames-1].Name,line.length()-strlen("Name="),strlen("Name=")); - } - if(strncmp(line.data(),"Episode=",strlen("Episode=")) == 0) - { - sscanf(line.data(),"Episode=%hd", &(pCKP->GameData[pCKP->numGames-1].Episode)); - } - if(strncmp(line.data(),"Path=",strlen("Path=")) == 0) - { - unsigned short l = strlen("Path="); - line.copy(pCKP->GameData[pCKP->numGames-1].DataDirectory,line.length()-l,l); - } - } - gamescfg.close(); - } - else - { - g_pLogFile->ftextOut(RED,"loadResourcesforStartMenu(): \"data/games.cfg\" could not be read! Assure, that the directory can be accessed."); - return -1; - } - - if( pCKP->numGames >= 20 ) - g_pLogFile->ftextOut(PURPLE,"parseTheGames(): Warning! Number of games limit in \"data/games.cfg\" reached."); - - if(pCKP->numGames == 0) - { - g_pLogFile->ftextOut(PURPLE,"parseTheGames(): In the file \"data/games.cfg\" no games were found."); - return -1; - } - - unsigned short c=0; - for(c=0 ; c < pCKP->numGames ; c++) - { - checkConsistencyofGameData(&(pCKP->GameData[c])); - } - - // /* Load the graphics of the first game for displaying the menu */ /* Graphics of the first Episode are taken*/ - if(!pCKP->Control.skipstarting) - pCKP->Control.levelcontrol.episode = 1; - else - 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); - Game->loadResources(pCKP->Control.levelcontrol.episode, pCKP->GameData[0].DataDirectory); - - player[0].x = player[0].y = 0; - if(initgamefirsttime(pCKP, 0) != 0) - { - return 1; - } - initgame(pCKP); - - return 0; -} - - -#define MAINMENU_GOTO_DEMO_TIME 4000 - -extern char fade_black; -short loadStartMenu(stCloneKeenPlus *pCKP) -{ - CDialog *GamesMenu; - int i; - - fade.mode = FADE_GO; - fade.rate = FADE_NORM; - fade.dir = FADE_IN; - fade.curamt = 0; - fade.fadetimer = 0; - showmapatpos(90, (104 << 2)+256+256+80, 32-4, 0, pCKP); - - // Prepare the Games Menu - GamesMenu = new CDialog(); - - GamesMenu->setDimensions(2,2,36,15); - - // Show me the games you detected! - for( i=0 ; i < pCKP->numGames ; i++ ) - { - GamesMenu->addOptionText(pCKP->GameData[i].Name); - } - - GamesMenu->animateDialogBox(true); - - do - { - g_pInput->pollEvents(); - g_pTimer->SpeedThrottle(); - - // do fades - gamedo_fades(); - if(fade.mode == FADE_COMPLETE) - GamesMenu->setVisible(true); - - gamedo_AnimatedTiles(); - - // Check the Input - if(g_pInput->getPulsedCommand(IC_DOWN, 80)) - GamesMenu->setNextSelection(); - if(g_pInput->getPulsedCommand(IC_UP, 80)) - GamesMenu->setPrevSelection(); - - if(g_pInput->getPressedCommand(0, IC_STATUS)) - { - fade.dir = FADE_OUT; - fade.curamt = PAL_FADE_SHADES; - fade.fadetimer = 0; - fade.rate = FADE_NORM; - fade.mode = FADE_GO; - pCKP->Resources.GameSelected = GamesMenu->getSelection()+1; - pCKP->Control.levelcontrol.episode = pCKP->GameData[pCKP->Resources.GameSelected-1].Episode; - break; - } - - // Render the Games-Menu - GamesMenu->renderDialog(); - - // blit the scrollbuffer to the display - gamedo_frameskipping_blitonly(); - } while(!g_pInput->getExitEvent()); - - delete GamesMenu; - - return 0; -} - -int mainmenu(stCloneKeenPlus *pCKP,int defaultopt) -{ - - CDialog *MainMenu; - int bmnum; - int x; - int selection; - - for(unsigned int cp=0 ; cpsetDimensions(11,8,18,12); - - // Load the Title Bitmap - bmnum = g_pGraphics->getBitmapNumberFromName("TITLE"); - - MainMenu->addOptionText("1-Player Game"); - MainMenu->addOptionText("2-Player Game"); - MainMenu->addOptionText("Load Game"); - MainMenu->addOptionText("Story"); - MainMenu->addOptionText("High Scores"); - MainMenu->addOptionText("Options"); - MainMenu->addOptionText("Demo"); - MainMenu->addOptionText("Change Game"); - MainMenu->addOptionText("About CG"); - MainMenu->addOptionText("Quit"); - - x = (320/2)-(bitmaps[bmnum].xsize/2); - - g_pGraphics->drawBitmap(x, 0, bmnum); - - MainMenu->animateDialogBox(true); - - do - { - - g_pInput->pollEvents(); - g_pTimer->SpeedThrottle(); - - // do fades - gamedo_fades(); - if(fade.mode == FADE_COMPLETE) - MainMenu->setVisible(true); - - gamedo_AnimatedTiles(); - - // Check the Input - if(g_pInput->getPulsedCommand(IC_DOWN, 80)) - MainMenu->setNextSelection(); - if(g_pInput->getPulsedCommand(IC_UP, 80)) - MainMenu->setPrevSelection(); - - if(g_pInput->getPressedCommand(IC_STATUS)) - { - selection = MainMenu->getSelection(); - break; - } - - - // Render the Games-Menu - MainMenu->renderDialog(); - - // blit the scrollbuffer to the display - gamedo_frameskipping_blitonly(); - - if(g_pInput->getExitEvent()) - { - delete MainMenu; - return MAINMNU_QUIT; - } - - } while(1); - - if (selection==MAINMNU_LOADGAME) - { - int diff; - diff = getDifficulty(pCKP); - if(diff>2) - { - return BACK2MAINMENU; - } - - pCKP->Control.levelcontrol.hardmode = (diff == 1) ? true : false; - - loadslot = save_slot_box(0, pCKP); - if (loadslot) - { - fade.dir = FADE_OUT; - fade.curamt = PAL_FADE_SHADES; - fade.fadetimer = 0; - fade.rate = FADE_NORM; - fade.mode = FADE_GO; - } - bmnum = g_pGraphics->getBitmapNumberFromName("TITLE"); - x = (320/2)-(bitmaps[bmnum].xsize/2); - g_pGraphics->drawBitmap(x, 0, bmnum); - } - else if (selection==MAINMNU_OPTIONS) - { - if (configmenu(pCKP)) - { // need to restart game - return RESTART_GAME; - } - } - else - { - if(selection==MAINMNU_1PLAYER || selection==MAINMNU_2PLAYER) - { - - int diff; - diff = getDifficulty(pCKP); - - if(diff>2) - { - delete MainMenu; - return BACK2MAINMENU; - } - pCKP->Control.levelcontrol.hardmode = (diff == 1) ? true : false; - } - - fade.dir = FADE_OUT; - fade.curamt = PAL_FADE_SHADES; - fade.fadetimer = 0; - fade.rate = FADE_NORM; - fade.mode = FADE_GO; - } - - delete MainMenu; - - return selection; -} - -void initialiazeDlgStruct(stDlgStruct *pDlgStruct) -{ - pDlgStruct->OptionSwitch = (stOptionSwitch*) malloc(pDlgStruct->num_OptionSwitches*sizeof(stOptionSwitch)); - pDlgStruct->Separator = (stSeparator*) malloc(pDlgStruct->num_Separators*sizeof(stSeparator)); - pDlgStruct->StarterSwitch = (stStarterSwitch*) malloc(pDlgStruct->num_StarterSwitch*sizeof(stStarterSwitch)); - pDlgStruct->TextLine = (stTextLine*) malloc(pDlgStruct->num_TextLines*sizeof(stTextLine)); -} - -int getDifficulty(stCloneKeenPlus *pCKP) -{ - CDialog *DifficultyMenu; - int bmnum; - int selection; - int x; - - fade.mode = FADE_GO; - fade.rate = FADE_NORM; - fade.dir = FADE_IN; - fade.curamt = 0; - fade.fadetimer = 0; - - showmapatpos(90, MAINMENU_X, MENUS_Y, 0, pCKP); - - // Load the Title Bitmap - bmnum = g_pGraphics->getBitmapNumberFromName("TITLE"); - - x = (320/2)-(bitmaps[bmnum].xsize/2); - - g_pGraphics->drawBitmap(x, 0, bmnum); - - // Prepare the Games Menu - DifficultyMenu = new CDialog(); - - DifficultyMenu->setDimensions(15,4,14,6); - - DifficultyMenu->addOptionText("Normal"); - DifficultyMenu->addOptionText("Hard"); - DifficultyMenu->addSeparator(); - DifficultyMenu->addOptionText("Cancel"); - - DifficultyMenu->animateDialogBox(true); - - do - { - // do fades - gamedo_fades(); - if(fade.mode == FADE_COMPLETE) - DifficultyMenu->setVisible(true); - - gamedo_AnimatedTiles(); - - // Check the Input - if(g_pInput->getPulsedCommand(IC_DOWN, 80)) - DifficultyMenu->setNextSelection(); - if(g_pInput->getPulsedCommand(IC_UP, 80)) - DifficultyMenu->setPrevSelection(); - - if(g_pInput->getPressedCommand(IC_STATUS)) - { - selection = DifficultyMenu->getSelection(); - break; - } - // Render the Games-Menu - DifficultyMenu->renderDialog(); - - // blit the scrollbuffer to the display - gamedo_frameskipping_blitonly(); - - g_pInput->pollEvents(); - g_pTimer->SpeedThrottle(); - - } while(1); - - delete DifficultyMenu; - - return selection; -} - -int AudioDlg(stCloneKeenPlus *pCKP) -{ - CDialog *AudioMenu; - int bmnum; - int selection; - int x; - int ok=0; - - int rate=0; - short mode=0; - - showmapatpos(90, MAINMENU_X, MENUS_Y, 0, pCKP); - - // Load the Title Bitmap - bmnum = g_pGraphics->getBitmapNumberFromName("TITLE"); - x = (320/2)-(bitmaps[bmnum].xsize/2); - g_pGraphics->drawBitmap(x, 0, bmnum); - - // Prepare the Games Menu - AudioMenu = new CDialog(); - AudioMenu->setDimensions(4,4,32,7); - - char buf[256]; - rate = g_pSound->getAudioSpec().freq; - sprintf(buf,"Rate: %d kHz",rate); - AudioMenu->addOptionText(buf); - mode = g_pSound->getAudioSpec().channels - 1; - if(mode == 1) - AudioMenu->addOptionText("Mode: Stereo"); - else - AudioMenu->addOptionText("Mode: Mono"); - AudioMenu->addSeparator(); - AudioMenu->addOptionText("Save and go back"); - AudioMenu->addOptionText("Cancel"); - - AudioMenu->animateDialogBox(true); - - do - { - // do fades - gamedo_fades(); - if(fade.mode == FADE_COMPLETE) - AudioMenu->setVisible(true); - gamedo_AnimatedTiles(); - - // Check the Input - if(g_pInput->getPulsedCommand(IC_DOWN, 80)) - AudioMenu->setNextSelection(); - if(g_pInput->getPulsedCommand(IC_UP, 80)) - AudioMenu->setPrevSelection(); - - if(g_pInput->getPressedCommand(IC_STATUS)) - { - selection = AudioMenu->getSelection(); - - if(selection == 0) - { - switch(rate) - { - case 44100: rate = 48000; break; - case 22050: rate = 44100; break; - case 11000: rate = 22050; break; - default: rate = 11000; break; - } - - sprintf(buf,"Rate: %d kHz",rate); - AudioMenu->setOptionText(0,buf); - } - - if(selection == 1) - { - mode = !mode; - if(!mode) - AudioMenu->setOptionText(1,"Mode: Mono"); - else - AudioMenu->setOptionText(1,"Mode: Stereo"); - } - - if(selection == 3) - { - g_pSound->destroy(); - g_pSound->setSoundmode(rate, mode ? true : false); - CSettings *Settings; - Settings = new CSettings(); - Settings->saveDrvCfg(); - delete Settings; Settings = NULL; - g_pSound->init(); - ok = g_pSound->loadSoundData(pCKP->Control.levelcontrol.episode, - pCKP->GameData[pCKP->Resources.GameSelected-1].DataDirectory); - - break; - } - if(selection == 4) - break; - - } - // Render the Games-Menu - AudioMenu->renderDialog(); - - // blit the scrollbuffer to the display - gamedo_frameskipping_blitonly(); - - g_pInput->pollEvents(); - g_pTimer->SpeedThrottle(); - - } while(1); - - delete AudioMenu; - return ok; -} - -void OptionsDlg(stCloneKeenPlus *pCKP) -{ - CDialog *OptionsMenu; - int bmnum; - int selection; - int x,i; - - char buf[256]; - - showmapatpos(90, MAINMENU_X, MENUS_Y, 0, pCKP); - - // Load the Title Bitmap - bmnum = g_pGraphics->getBitmapNumberFromName("TITLE"); - x = (320/2)-(bitmaps[bmnum].xsize/2); - g_pGraphics->drawBitmap(x, 0, bmnum); - - // Prepare the Games Menu - OptionsMenu = new CDialog(); - OptionsMenu->setDimensions(3,3,34,12); - - for( i = 0 ; i < NUM_OPTIONS ; i++ ) - { - sprintf(buf,"%s: ",options[i].name); - if(options[i].value) - strcat(buf,"Enabled"); - else - strcat(buf,"Disabled"); - - OptionsMenu->addOptionText(buf); - } - - OptionsMenu->addSeparator(); - OptionsMenu->addOptionText("Return"); - - OptionsMenu->animateDialogBox(true); - - do - { - // do fades - gamedo_fades(); - if(fade.mode == FADE_COMPLETE) - OptionsMenu->setVisible(true); - gamedo_AnimatedTiles(); - - // Check the Input - if(g_pInput->getPulsedCommand(IC_DOWN, 80)) - OptionsMenu->setNextSelection(); - if(g_pInput->getPulsedCommand(IC_UP, 80)) - OptionsMenu->setPrevSelection(); - - if(g_pInput->getPressedCommand(IC_STATUS)) - { - selection = OptionsMenu->getSelection(); - - if(selection < NUM_OPTIONS) - { - sprintf(buf,"%s: ",options[selection].name); - - if(options[selection].value) - { - options[selection].value = 0; - strcat(buf,"Disabled"); - } - else - { - options[selection].value = 1; - strcat(buf,"Enabled"); - } - - OptionsMenu->setOptionText(selection,buf); - } - else - { - CSettings Settings; - Settings.saveGameCfg(pCKP->Option); - break; - } - } - // Render the Games-Menu - OptionsMenu->renderDialog(); - - // blit the scrollbuffer to the display - gamedo_frameskipping_blitonly(); - - g_pInput->pollEvents(); - g_pTimer->SpeedThrottle(); - - } while(1); - - delete OptionsMenu; -} - -short GraphicsDlg(stCloneKeenPlus *pCKP) -{ - CDialog *DisplayMenu; - int bmnum; - int selection; - int x; - unsigned int width; - unsigned int height; - unsigned short depth; - unsigned short zoom = 1; - unsigned short filter = 0; - unsigned short frameskip = 0; - bool opengl = false; - unsigned char gl_filter = 0; - bool fsmode; - char buf[256]; - short retval = 0; - unsigned char autoframeskip = 0; - bool aspect; - - showmapatpos(90, MAINMENU_X, MENUS_Y, 0, pCKP); - - // Load the Title Bitmap - bmnum = g_pGraphics->getBitmapNumberFromName("TITLE"); - x = (320/2)-(bitmaps[bmnum].xsize/2); - g_pGraphics->drawBitmap(x, 0, bmnum); - - // Prepare the Games Menu - DisplayMenu = new CDialog(); - DisplayMenu->setDimensions(4,3,32,13); - - width = g_pVideoDriver->getWidth(); - height = g_pVideoDriver->getHeight(); - depth = g_pVideoDriver->getDepth(); - sprintf(buf,"Resolution: %dx%dx%d",width,height,depth); - - zoom = g_pVideoDriver->getZoomValue(); - filter = g_pVideoDriver->getFiltermode(); - frameskip = g_pVideoDriver->getFrameskip(); - - DisplayMenu->addOptionText(buf); - if(g_pVideoDriver->getFullscreen()) - { - DisplayMenu->addOptionText("Fullscreen mode"); - fsmode = true; - } - else - { - DisplayMenu->addOptionText("Windowed mode"); - fsmode = false; - } - - opengl = g_pVideoDriver->isOpenGL(); - if(!opengl) - { - zoom = g_pVideoDriver->getZoomValue(); - - if(zoom == 1) - sprintf(buf,"No scale"); - else - sprintf(buf,"Scale: %d", zoom); - DisplayMenu->addOptionText(buf); - } - else - { - gl_filter = g_pVideoDriver->getOGLFilter(); - - if(gl_filter == 1) - sprintf(buf,"OGL Filter: Linear"); - else - sprintf(buf,"OGL Filter: Nearest"); - DisplayMenu->addOptionText(buf); - } - - filter = g_pVideoDriver->getFiltermode(); - if(filter == 0) - DisplayMenu->addOptionText("No Filter"); - else if(filter == 1) - DisplayMenu->addOptionText("Scale2x Filter"); - else if(filter == 2) - DisplayMenu->addOptionText("Scale3x Filter"); - else if(filter == 3) - DisplayMenu->addOptionText("Scale4x Filter"); - else - DisplayMenu->addOptionText("Unknown Filter"); - - sprintf(buf,"Frameskip: %d", frameskip); - DisplayMenu->addOptionText(buf); - - if(opengl) - DisplayMenu->addOptionText("OpenGL Acceleration"); - else - DisplayMenu->addOptionText("Software Rendering"); - - autoframeskip = g_pVideoDriver->getTargetFPS(); - - if(autoframeskip) - sprintf(buf,"Auto-Frameskip : %d fps",autoframeskip); - else - sprintf(buf,"Auto-Frameskip disabled"); - - DisplayMenu->addOptionText(buf); - - aspect = g_pVideoDriver->getAspectCorrection(); - - if(aspect) - DisplayMenu->addOptionText("OGL Aspect Ratio Enabled"); - else - DisplayMenu->addOptionText("OGL Aspect Ratio Disabled"); - - DisplayMenu->addSeparator(); - DisplayMenu->addOptionText("Save and return"); - DisplayMenu->addOptionText("Cancel"); - DisplayMenu->animateDialogBox(true); - - do - { - // do fades - gamedo_fades(); - if(fade.mode == FADE_COMPLETE) - DisplayMenu->setVisible(true); - gamedo_AnimatedTiles(); - - // Check the Input - if(g_pInput->getPulsedCommand(IC_DOWN, 80)) - DisplayMenu->setNextSelection(); - if(g_pInput->getPulsedCommand(IC_UP, 80)) - DisplayMenu->setPrevSelection(); - - if(g_pInput->getPressedCommand(IC_STATUS)) - { - selection = DisplayMenu->getSelection(); - - if(selection == 0) - { - // Now the part of the resolution list - st_resolution Resolution; - Resolution = g_pVideoDriver->setNextResolution(); - - sprintf(buf,"Resolution: %dx%dx%d", Resolution.width, Resolution.height, Resolution.depth); - DisplayMenu->setOptionText(selection,buf); - } - else if(selection == 1) - { - if(!fsmode) - DisplayMenu->setOptionText(1,"Fullscreen mode"); - else - DisplayMenu->setOptionText(1,"Windowed mode"); - fsmode = !fsmode; - } - else if(selection == 2) - { - if(opengl) - { - gl_filter = (gl_filter==1) ? 0 : 1; - - if(gl_filter == 1) - sprintf(buf,"OGL Filter: Linear"); - else - sprintf(buf,"OGL Filter: Nearest"); - - DisplayMenu->setOptionText(2,buf); - } - else - { - if(zoom >= 4) - zoom = 1; - else - zoom++; - - if(zoom == 1) - sprintf(buf,"No scale"); - else - sprintf(buf,"Scale: %d", zoom); - } - - DisplayMenu->setOptionText(2,buf); - } - - else if(selection == 3) - { - if(filter >= 3) - filter = 0; - else - filter++; - - if(filter == 0) - DisplayMenu->setOptionText(3,"No Filter"); - else if(filter == 1) - DisplayMenu->setOptionText(3,"Scale2x Filter"); - else if(filter == 2) - DisplayMenu->setOptionText(3,"Scale3x Filter"); - else if(filter == 3) - DisplayMenu->setOptionText(3,"Scale4x Filter"); - } - else if(selection == 4) - { - frameskip++; - - if(frameskip > 20) - frameskip = 0; - - sprintf(buf,"Frameskip: %d",frameskip); - DisplayMenu->setOptionText(4,buf); - } - else if(selection == 5) - { - opengl = opengl ? false : true; // switch the mode!! - - if(opengl) - DisplayMenu->setOptionText(5,"OpenGL Acceleration"); - else - DisplayMenu->setOptionText(5,"Software Rendering"); - } - else if(selection == 6) - { - if(autoframeskip < 70) - { - autoframeskip += 10; - sprintf(buf,"Auto-Frameskip : %d fps", autoframeskip); - } - else - { - autoframeskip = 0; - sprintf(buf,"Auto-Frameskip disabled"); - } - - DisplayMenu->setOptionText(6, buf); - } - else if(selection == 7) - { - aspect = !aspect; - - if(aspect) - DisplayMenu->setOptionText(7,"OGL Aspect Ratio Enabled"); - else - DisplayMenu->setOptionText(7,"OGL Aspect Ratio Disabled"); - - } - else if(selection == 9) - { - g_pVideoDriver->stop(); - - if(fsmode) - g_pVideoDriver->isFullscreen(true); - else - g_pVideoDriver->isFullscreen(false); - - g_pVideoDriver->enableOpenGL(opengl); - g_pVideoDriver->setOGLFilter(gl_filter); - g_pVideoDriver->setZoom(zoom); - g_pVideoDriver->setFilter(filter); - g_pVideoDriver->setFrameskip(frameskip); - g_pVideoDriver->setTargetFPS(autoframeskip); - g_pVideoDriver->setAspectCorrection(aspect); - - // initialize/activate all drivers - g_pLogFile->ftextOut("Restarting graphics driver... (Menu)
"); - if (g_pVideoDriver->start()) - retval = 1; - - CSettings *Settings; - Settings = new CSettings(); - - Settings->saveDrvCfg(); - delete Settings; Settings = NULL; - - showmapatpos(90, MAINMENU_X, MENUS_Y, 0, pCKP); - - fade.mode = FADE_GO; - fade.dir = FADE_IN; - fade.curamt = 0; - fade.rate = FADE_NORM; - fade.fadetimer = 0; - gamedo_fades(); - break; - } - else - break; - } - // Render the Games-Menu - DisplayMenu->renderDialog(); - - // blit the scrollbuffer to the display - gamedo_frameskipping_blitonly(); - - g_pInput->pollEvents(); - g_pTimer->SpeedThrottle(); - - } while(1); - - delete DisplayMenu; - - return retval; -} - - -// This function shows the Story of Commander Keen! -void showPage(char *text, stCloneKeenPlus *pCKP, int textsize) -{ - unsigned int i, j, k; - int exit=0; - int textpos; - bool enter; - unsigned int dlgX,dlgY,dlgW,dlgH; - unsigned int scroll, maxscroll; - char buffer[200][40]; - - showmapatpos(90, STORYBOARD_X, STORYBOARD_Y, 0, pCKP); - - fade.mode = FADE_GO; - fade.rate = FADE_NORM; - fade.dir = FADE_IN; - fade.curamt = 0; - fade.fadetimer = 0; - - scroll=0; - maxscroll=0; - - j=0; - k=0; - - AllPlayersInvisible(); - - dlgX = 0; - dlgY = 0; - dlgW = 39; - dlgH = 15; - - textpos=0; - memset(buffer,0,200*40*sizeof(char)); - // Prepare the buffer - - char sbuf[256]; - unsigned int totnumline=0; - - for(i=0;i<200;i++) - { - for(j=0;j dlgW-2)) - { - if(text[textpos] == ' ') - { - textpos++; - break; - } - } - - if(text[textpos]=='\n' ) - { - textpos++; - break; - } - - if(text[textpos]==31 ) // I don't know, what they do, - //but original version seems to ignore them! - { - text[textpos]=' '; - } - - - buffer[i][j]=text[textpos]; - textpos++; - if(textpos >= textsize) - break; - } - if(textpos >= textsize) - { - totnumline+=3; - break; - } - - totnumline++; - } - buffer[i][j] = ' '; // Last character is empty! - - char coverline[39]; - memset(coverline,2,38*sizeof(char)); // for the upper and lower edges - coverline[38]=0; - - do - { - gamedo_fades(); - - gamedo_AnimatedTiles(); - - sb_dialogbox(dlgX, dlgY, dlgW, dlgH); - - k=0; - - // Draw the text - for(i=0;i>3)][0]=='~') // Special Background Colour - { - char temp[39]; - memset(temp,' ',38*sizeof(char)); - temp[38]=0; - g_pGraphics->sb_color_font_draw((unsigned char*) temp, (dlgX+1)<<3, (((dlgY+i+1)<<3) -(scroll%8)),COLOUR_DARKRED,COLOUR_GREY); - g_pGraphics->sb_color_font_draw((unsigned char*) buffer[i+(scroll>>3)]+1, (dlgX+1)<<3, (((dlgY+i+1)<<3) -(scroll%8)),COLOUR_DARKRED,COLOUR_GREY); - } - else - { - g_pGraphics->sb_font_draw((unsigned char*) buffer[i+(scroll>>3)], (dlgX+1)<<3, (((dlgY+i+1)<<3) -(scroll%8))); - } - } - g_pGraphics->sb_font_draw((unsigned char*) coverline, (dlgX+1)<<3, dlgY); // Upper and lower edge Update - g_pGraphics->sb_font_draw((unsigned char*) coverline, (dlgX+1)<<3, (dlgY+dlgH-1)<<3); - - // If user presses up or down - if (g_pInput->getHoldedCommand(0,IC_DOWN) || g_pInput->getHoldedCommand(1,IC_DOWN)) - { - if(scroll < (totnumline-dlgH)<<3) - scroll++; - SDL_Delay(2); - } - else if (g_pInput->getHoldedCommand(0,IC_UP) || g_pInput->getHoldedCommand(1,IC_UP)) - { - if(scroll > 0) - scroll--; - SDL_Delay(2); - } - - enter = (g_pInput->getPressedCommand(0,IC_STATUS) || g_pInput->getPressedCommand(1,IC_STATUS)); - if (enter) - { - exit=1; - fade.dir = FADE_OUT; - fade.curamt = PAL_FADE_SHADES; - fade.fadetimer = 0; - fade.rate = FADE_NORM; - fade.mode = FADE_GO; - } - - gamedo_frameskipping(pCKP); - - g_pInput->pollEvents(); - g_pTimer->SpeedThrottle(); - - - if(exit==1 && fade.mode==FADE_COMPLETE) - break; - - if (g_pInput->getPressedCommand(KQUIT)) break; - } while(!crashflag); - return; -} - -char configmenu(stCloneKeenPlus *pCKP) -{ - CDialog *OptionsMenu; - int bmnum; - int selection; - int x; - - showmapatpos(90, MAINMENU_X, MENUS_Y, 0, pCKP); - - // Load the Title Bitmap - bmnum = g_pGraphics->getBitmapNumberFromName("TITLE"); - - x = (320/2)-(bitmaps[bmnum].xsize/2); - - g_pGraphics->drawBitmap(x, 0, bmnum); - - // Prepare the Games Menu - OptionsMenu = new CDialog(); - - OptionsMenu->setDimensions(15,4,14,8); - - OptionsMenu->addOptionText("Graphics"); - OptionsMenu->addOptionText("Audio"); - OptionsMenu->addOptionText("Game"); - OptionsMenu->addOptionText("Controls"); - OptionsMenu->addSeparator(); - OptionsMenu->addOptionText("Back"); - - OptionsMenu->animateDialogBox(true); - - do - { - // do fades - gamedo_fades(); - if(fade.mode == FADE_COMPLETE) - OptionsMenu->setVisible(true); - - gamedo_AnimatedTiles(); - - // Check the Input - if(g_pInput->getPulsedCommand(IC_DOWN, 80)) - OptionsMenu->setNextSelection(); - if(g_pInput->getPulsedCommand(IC_UP, 80)) - OptionsMenu->setPrevSelection(); - - if(g_pInput->getPressedCommand(IC_STATUS)) - { - selection = OptionsMenu->getSelection(); - break; - } - // Render the Games-Menu - OptionsMenu->renderDialog(); - - // blit the scrollbuffer to the display - gamedo_frameskipping_blitonly(); - - g_pInput->pollEvents(); - g_pTimer->SpeedThrottle(); - - } while(1); - - switch(selection) - { - case 0: - GraphicsDlg(pCKP); - break; - - case 1: - AudioDlg(pCKP); - break; - - case 2: - OptionsDlg(pCKP); - break; - - case 3: - controlsmenu(pCKP); - break; - - default: - break; - } - - delete OptionsMenu; - - return 0; -} - -char controlsmenu(stCloneKeenPlus *pCKP) -{ - CDialog *ControlsMenu; - int bmnum; - int selection; - int x; - char buf[256]; - char buf2[256]; - - showmapatpos(90, MAINMENU_X, MENUS_Y, 0, pCKP); - - // Load the Title Bitmap - bmnum = g_pGraphics->getBitmapNumberFromName("TITLE"); - - x = (320/2)-(bitmaps[bmnum].xsize/2); - - g_pGraphics->drawBitmap(x, 0, bmnum); - - // Prepare the Games Menu - ControlsMenu = new CDialog(); - - ControlsMenu->setDimensions(1,3,38,20); - - g_pInput->getEventName(IC_LEFT, 0, buf2); - sprintf(buf,"P1 Left: %s",buf2); - ControlsMenu->addOptionText(buf); - g_pInput->getEventName(IC_UP, 0, buf2); - sprintf(buf,"P1 Up: %s",buf2); - ControlsMenu->addOptionText(buf); - g_pInput->getEventName(IC_RIGHT, 0, buf2); - sprintf(buf,"P1 Right: %s",buf2); - ControlsMenu->addOptionText(buf); - g_pInput->getEventName(IC_DOWN, 0, buf2); - sprintf(buf,"P1 Down: %s",buf2); - ControlsMenu->addOptionText(buf); - g_pInput->getEventName(IC_JUMP, 0, buf2); - sprintf(buf,"P1 Jump: %s",buf2); - ControlsMenu->addOptionText(buf); - g_pInput->getEventName(IC_POGO, 0, buf2); - sprintf(buf,"P1 Pogo: %s",buf2); - ControlsMenu->addOptionText(buf); - g_pInput->getEventName(IC_FIRE, 0, buf2); - sprintf(buf,"P1 Fire: %s",buf2); - ControlsMenu->addOptionText(buf); - g_pInput->getEventName(IC_STATUS, 0, buf2); - sprintf(buf,"P1 Status: %s",buf2); - ControlsMenu->addOptionText(buf); - - g_pInput->getEventName(IC_LEFT, 1, buf2); - sprintf(buf,"P2 Left: %s",buf2); - ControlsMenu->addOptionText(buf); - g_pInput->getEventName(IC_UP, 1, buf2); - sprintf(buf,"P2 Up: %s",buf2); - ControlsMenu->addOptionText(buf); - g_pInput->getEventName(IC_RIGHT, 1, buf2); - sprintf(buf,"P2 Right: %s",buf2); - ControlsMenu->addOptionText(buf); - g_pInput->getEventName(IC_DOWN, 1, buf2); - sprintf(buf,"P2 Down: %s",buf2); - ControlsMenu->addOptionText(buf); - g_pInput->getEventName(IC_JUMP, 1, buf2); - sprintf(buf,"P2 Jump: %s",buf2); - ControlsMenu->addOptionText(buf); - g_pInput->getEventName(IC_POGO, 1, buf2); - sprintf(buf,"P2 Pogo: %s",buf2); - ControlsMenu->addOptionText(buf); - g_pInput->getEventName(IC_FIRE, 1, buf2); - sprintf(buf,"P2 Fire: %s",buf2); - ControlsMenu->addOptionText(buf); - g_pInput->getEventName(IC_STATUS, 1, buf2); - sprintf(buf,"P2 Status: %s",buf2); - ControlsMenu->addOptionText(buf); - ControlsMenu->addSeparator(); - ControlsMenu->addOptionText("Return"); - - ControlsMenu->animateDialogBox(true); - - do - { - // do fades - gamedo_fades(); - if(fade.mode == FADE_COMPLETE) - ControlsMenu->setVisible(true); - gamedo_AnimatedTiles(); - - // Check the Input - if(g_pInput->getPulsedCommand(IC_DOWN, 80)) - ControlsMenu->setNextSelection(); - if(g_pInput->getPulsedCommand(IC_UP, 80)) - ControlsMenu->setPrevSelection(); - - if(g_pInput->getPressedCommand(IC_STATUS)) - { - selection = ControlsMenu->getSelection(); - - if(selection < MAX_COMMANDS) - { - int item=0; - if(selection < 4) - item = selection + 4; - else - item = selection - 4; - - switch(selection) - { - case 0: sprintf(buf,"P1 Left: "); break; - case 1: sprintf(buf,"P1 Up: "); break; - case 2: sprintf(buf,"P1 Right: "); break; - case 3: sprintf(buf,"P1 Down: "); break; - case 4: sprintf(buf,"P1 Jump: "); break; - case 5: sprintf(buf,"P1 Pogo: "); break; - case 6: sprintf(buf,"P1 Fire: "); break; - case 7: sprintf(buf,"P1 Status: "); break; - } - - strcpy(buf2,buf); - strcat(buf2,"*Waiting for Input*"); - ControlsMenu->setOptionText(selection,buf2); - - while(!g_pInput->readNewEvent(0,item)) - { - ControlsMenu->renderDialog(); - gamedo_frameskipping_blitonly(); - } - - g_pInput->getEventName(item, 0, buf2); - strcat(buf,buf2); - ControlsMenu->setOptionText(selection,buf); - } - else if(selection >= MAX_COMMANDS && selection < MAX_COMMANDS*2) - { - int item=0; - if(selection < (4 + MAX_COMMANDS)) - item = selection + 4 - MAX_COMMANDS; - else - item = selection - 4 - MAX_COMMANDS; - - switch(selection) - { - case 0+ MAX_COMMANDS: sprintf(buf,"P2 Left: "); break; - case 1+ MAX_COMMANDS: sprintf(buf,"P2 Up: "); break; - case 2+ MAX_COMMANDS: sprintf(buf,"P2 Right: "); break; - case 3+ MAX_COMMANDS: sprintf(buf,"P2 Down: "); break; - case 4+ MAX_COMMANDS: sprintf(buf,"P2 Jump: "); break; - case 5+ MAX_COMMANDS: sprintf(buf,"P2 Pogo: "); break; - case 6+ MAX_COMMANDS: sprintf(buf,"P2 Fire: "); break; - case 7+ MAX_COMMANDS: sprintf(buf,"P2 Status: "); break; - } - - strcpy(buf2,buf); - strcat(buf2,"*Waiting for Input*"); - ControlsMenu->setOptionText(selection,buf2); - - while(!g_pInput->readNewEvent(1,item)) - { - ControlsMenu->renderDialog(); - gamedo_frameskipping_blitonly(); - } - - g_pInput->getEventName(item, 1, buf2); - strcat(buf,buf2); - ControlsMenu->setOptionText(selection,buf); - } - else - { - g_pInput->saveControlconfig(); - break; - } - } - // Render the Menu - ControlsMenu->renderDialog(); - - // blit the scrollbuffer to the display - gamedo_frameskipping_blitonly(); - - g_pInput->pollEvents(); - g_pTimer->SpeedThrottle(); - - } while(1); - - delete ControlsMenu; - return 0; -} - -void keensleft(stCloneKeenPlus *pCKP) -{ -int enter, lastenterstate; -unsigned int p; -int x,y,i; -int boxY, boxH; -int boxtimer; -int ep3; - -stLevelControl *p_levelcontrol; - - p_levelcontrol = &(pCKP->Control.levelcontrol); - - // on episode 3 we have to subtract one from the map tiles - // because the tiles start at 31, not 32 like on the other eps - ep3 = 0; - if (p_levelcontrol->episode==3) ep3 = 1; - - #define KEENSLEFT_TIME 400 - - for(i=0;idrawFont( (unsigned char*) getstring("LIVES_LEFT_BACKGROUND"),(KEENSLEFT_X+1)*8,(boxY+1)*8,0); - g_pGraphics->drawFont( (unsigned char*) getstring("LIVES_LEFT"),((KEENSLEFT_X+7)*8)+4,(boxY+1)*8,0); - y = ((boxY+2)*8)+4; - if (numplayers>1) y--; - for(p=0;pdrawSprite_direct(x, y, PMAPDOWNFRAME+playerbaseframes[p]-ep3); - x+=16; - } - y+=18; - } - g_pVideoDriver->update_screen(); - - g_pSound->playSound(SOUND_KEENSLEFT, PLAY_NOW); - - boxtimer = 0; - do - { - - gamedo_fades(); - - if (boxtimer > KEENSLEFT_TIME) - { - break; - } else boxtimer++; - - enter = g_pInput->getPressedCommand(IC_STATUS)||g_pInput->getPressedCommand(IC_FIRE)|| - g_pInput->getPressedCommand(IC_JUMP)||g_pInput->getPressedCommand(IC_POGO); - if (enter) - { - break; - } - if (g_pInput->getPressedCommand(KQUIT)) - { - return; - } - - lastenterstate = enter; - g_pInput->pollEvents(); - g_pTimer->SpeedThrottle(); - } while(!crashflag); - -} + /* MENU.C + The main menu, intro, and other such stuff. +*/ + +#include "keen.h" +#include "pressf10.h" +#include "include/menu.h" +#include "include/misc.h" +#include "sdl/CVideoDriver.h" +#include "include/game.h" +#include "include/gamedo.h" +#include "sdl/CTimer.h" +#include "sdl/sound/CSound.h" +#include "include/eseq_ep2.h" +#include "include/fileio.h" +#include "include/gm_pdowm.h" +#include "include/gamedo.h" +#include "include/main.h" +#include "CGraphics.h" +#include "sdl/video/colourtable.h" +#include "include/gui/dialog.h" +#include "sdl/CInput.h" +#include "vorticon/CDialog.h" +#include "CLogFile.h" +#include "sdl/CSettings.h" +#include +#include +#include +#include "StringUtils.h" + + +using namespace std; + +#define SELMOVE_SPD 3 + +short openDlgStruct(stDlgStruct *pDlgStruct, stCloneKeenPlus *pCKP); + +void showmapatpos(int level, int xoff, int yoff, int wm, stCloneKeenPlus *pCKP) +{ +int i; + std::string levelname; +g_pLogFile->ftextOut("showmapatpos(%d, %d, %d, %d);
",level,xoff,yoff,wm); + pCKP->Control.levelcontrol.dark = 0; + g_pGraphics->initPalette(pCKP->Control.levelcontrol.dark); + + initgame(pCKP); // reset scroll + levelname = "level" + FixedWidthStr_LeftFill(itoa(level), 2, '0') + ".ck" + itoa(pCKP->Control.levelcontrol.episode); + + short numsel; + if(pCKP->Resources.GameSelected == 0 ) // First time startup. No game has been chosen + numsel = 0; + else + numsel = pCKP->Resources.GameSelected-1; + + loadmap(levelname, pCKP->GameData[numsel].DataDirectory, level, wm, pCKP); + + drawmap(); + for(i=0;isb_blit(); +} + +short loadResourcesforStartMenu(stCloneKeenPlus *pCKP, CGame *Game) +{ + string line; + + ifstream gamescfg("data/games.cfg"); + + if (gamescfg.is_open()) + { + while ( !gamescfg.eof() && pCKP->numGames < 20 ) + { + getline (gamescfg,line); + + if(strncmp(line.data(),"[",strlen("[")) == 0) + { + stGameData *NewGameData; + + pCKP->numGames++; + NewGameData = new stGameData[pCKP->numGames]; + for(int i = 0; i < pCKP->numGames-1; ++i) + NewGameData[i] = pCKP->GameData[i]; + + delete[] pCKP->GameData; + + pCKP->GameData = NewGameData; + } + if(strncmp(line.data(),"Name=",strlen("Name=")) == 0) + { + pCKP->GameData[pCKP->numGames-1].Name = line.substr(strlen("Name=")); + } + if(strncmp(line.data(),"Episode=",strlen("Episode=")) == 0) + { + sscanf(line.data(),"Episode=%hd", &(pCKP->GameData[pCKP->numGames-1].Episode)); + } + if(strncmp(line.data(),"Path=",strlen("Path=")) == 0) + { + unsigned short l = strlen("Path="); + pCKP->GameData[pCKP->numGames-1].DataDirectory = line.substr(l); + } + } + gamescfg.close(); + } + else + { + g_pLogFile->ftextOut(RED,"loadResourcesforStartMenu(): \"data/games.cfg\" could not be read! Assure, that the directory can be accessed."); + return -1; + } + + if( pCKP->numGames >= 20 ) + g_pLogFile->ftextOut(PURPLE,"parseTheGames(): Warning! Number of games limit in \"data/games.cfg\" reached."); + + if(pCKP->numGames == 0) + { + g_pLogFile->ftextOut(PURPLE,"parseTheGames(): In the file \"data/games.cfg\" no games were found."); + return -1; + } + + unsigned short c=0; + for(c=0 ; c < pCKP->numGames ; c++) + { + checkConsistencyofGameData(&(pCKP->GameData[c])); + } + + // /* Load the graphics of the first game for displaying the menu */ /* Graphics of the first Episode are taken*/ + if(!pCKP->Control.skipstarting) + pCKP->Control.levelcontrol.episode = 1; + else + 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); + Game->loadResources(pCKP->Control.levelcontrol.episode, pCKP->GameData[0].DataDirectory); + + player[0].x = player[0].y = 0; + if(initgamefirsttime(pCKP, 0) != 0) + { + return 1; + } + initgame(pCKP); + + return 0; +} + + +#define MAINMENU_GOTO_DEMO_TIME 4000 + +extern char fade_black; +short loadStartMenu(stCloneKeenPlus *pCKP) +{ + CDialog *GamesMenu; + int i; + + fade.mode = FADE_GO; + fade.rate = FADE_NORM; + fade.dir = FADE_IN; + fade.curamt = 0; + fade.fadetimer = 0; + showmapatpos(90, (104 << 2)+256+256+80, 32-4, 0, pCKP); + + // Prepare the Games Menu + GamesMenu = new CDialog(); + + GamesMenu->setDimensions(2,2,36,15); + + // Show me the games you detected! + for( i=0 ; i < pCKP->numGames ; i++ ) + { + GamesMenu->addOptionText(pCKP->GameData[i].Name); + } + + GamesMenu->animateDialogBox(true); + + do + { + g_pInput->pollEvents(); + g_pTimer->SpeedThrottle(); + + // do fades + gamedo_fades(); + if(fade.mode == FADE_COMPLETE) + GamesMenu->setVisible(true); + + gamedo_AnimatedTiles(); + + // Check the Input + if(g_pInput->getPulsedCommand(IC_DOWN, 80)) + GamesMenu->setNextSelection(); + if(g_pInput->getPulsedCommand(IC_UP, 80)) + GamesMenu->setPrevSelection(); + + if(g_pInput->getPressedCommand(0, IC_STATUS)) + { + fade.dir = FADE_OUT; + fade.curamt = PAL_FADE_SHADES; + fade.fadetimer = 0; + fade.rate = FADE_NORM; + fade.mode = FADE_GO; + pCKP->Resources.GameSelected = GamesMenu->getSelection()+1; + pCKP->Control.levelcontrol.episode = pCKP->GameData[pCKP->Resources.GameSelected-1].Episode; + break; + } + + // Render the Games-Menu + GamesMenu->renderDialog(); + + // blit the scrollbuffer to the display + gamedo_frameskipping_blitonly(); + } while(!g_pInput->getExitEvent()); + + delete GamesMenu; + + return 0; +} + +int mainmenu(stCloneKeenPlus *pCKP,int defaultopt) +{ + + CDialog *MainMenu; + int bmnum; + int x; + int selection; + + for(unsigned int cp=0 ; cpsetDimensions(11,8,18,12); + + // Load the Title Bitmap + bmnum = g_pGraphics->getBitmapNumberFromName("TITLE"); + + MainMenu->addOptionText("1-Player Game"); + MainMenu->addOptionText("2-Player Game"); + MainMenu->addOptionText("Load Game"); + MainMenu->addOptionText("Story"); + MainMenu->addOptionText("High Scores"); + MainMenu->addOptionText("Options"); + MainMenu->addOptionText("Demo"); + MainMenu->addOptionText("Change Game"); + MainMenu->addOptionText("About CG"); + MainMenu->addOptionText("Quit"); + + x = (320/2)-(bitmaps[bmnum].xsize/2); + + g_pGraphics->drawBitmap(x, 0, bmnum); + + MainMenu->animateDialogBox(true); + + do + { + + g_pInput->pollEvents(); + g_pTimer->SpeedThrottle(); + + // do fades + gamedo_fades(); + if(fade.mode == FADE_COMPLETE) + MainMenu->setVisible(true); + + gamedo_AnimatedTiles(); + + // Check the Input + if(g_pInput->getPulsedCommand(IC_DOWN, 80)) + MainMenu->setNextSelection(); + if(g_pInput->getPulsedCommand(IC_UP, 80)) + MainMenu->setPrevSelection(); + + if(g_pInput->getPressedCommand(IC_STATUS)) + { + selection = MainMenu->getSelection(); + break; + } + + + // Render the Games-Menu + MainMenu->renderDialog(); + + // blit the scrollbuffer to the display + gamedo_frameskipping_blitonly(); + + if(g_pInput->getExitEvent()) + { + delete MainMenu; + return MAINMNU_QUIT; + } + + } while(1); + + if (selection==MAINMNU_LOADGAME) + { + int diff; + diff = getDifficulty(pCKP); + if(diff>2) + { + return BACK2MAINMENU; + } + + pCKP->Control.levelcontrol.hardmode = (diff == 1) ? true : false; + + loadslot = save_slot_box(0, pCKP); + if (loadslot) + { + fade.dir = FADE_OUT; + fade.curamt = PAL_FADE_SHADES; + fade.fadetimer = 0; + fade.rate = FADE_NORM; + fade.mode = FADE_GO; + } + bmnum = g_pGraphics->getBitmapNumberFromName("TITLE"); + x = (320/2)-(bitmaps[bmnum].xsize/2); + g_pGraphics->drawBitmap(x, 0, bmnum); + } + else if (selection==MAINMNU_OPTIONS) + { + if (configmenu(pCKP)) + { // need to restart game + return RESTART_GAME; + } + } + else + { + if(selection==MAINMNU_1PLAYER || selection==MAINMNU_2PLAYER) + { + + int diff; + diff = getDifficulty(pCKP); + + if(diff>2) + { + delete MainMenu; + return BACK2MAINMENU; + } + pCKP->Control.levelcontrol.hardmode = (diff == 1) ? true : false; + } + + fade.dir = FADE_OUT; + fade.curamt = PAL_FADE_SHADES; + fade.fadetimer = 0; + fade.rate = FADE_NORM; + fade.mode = FADE_GO; + } + + delete MainMenu; + + return selection; +} + +void initialiazeDlgStruct(stDlgStruct *pDlgStruct) +{ + pDlgStruct->OptionSwitch = (stOptionSwitch*) malloc(pDlgStruct->num_OptionSwitches*sizeof(stOptionSwitch)); + pDlgStruct->Separator = (stSeparator*) malloc(pDlgStruct->num_Separators*sizeof(stSeparator)); + pDlgStruct->StarterSwitch = (stStarterSwitch*) malloc(pDlgStruct->num_StarterSwitch*sizeof(stStarterSwitch)); + pDlgStruct->TextLine = (stTextLine*) malloc(pDlgStruct->num_TextLines*sizeof(stTextLine)); +} + +int getDifficulty(stCloneKeenPlus *pCKP) +{ + CDialog *DifficultyMenu; + int bmnum; + int selection; + int x; + + fade.mode = FADE_GO; + fade.rate = FADE_NORM; + fade.dir = FADE_IN; + fade.curamt = 0; + fade.fadetimer = 0; + + showmapatpos(90, MAINMENU_X, MENUS_Y, 0, pCKP); + + // Load the Title Bitmap + bmnum = g_pGraphics->getBitmapNumberFromName("TITLE"); + + x = (320/2)-(bitmaps[bmnum].xsize/2); + + g_pGraphics->drawBitmap(x, 0, bmnum); + + // Prepare the Games Menu + DifficultyMenu = new CDialog(); + + DifficultyMenu->setDimensions(15,4,14,6); + + DifficultyMenu->addOptionText("Normal"); + DifficultyMenu->addOptionText("Hard"); + DifficultyMenu->addSeparator(); + DifficultyMenu->addOptionText("Cancel"); + + DifficultyMenu->animateDialogBox(true); + + do + { + // do fades + gamedo_fades(); + if(fade.mode == FADE_COMPLETE) + DifficultyMenu->setVisible(true); + + gamedo_AnimatedTiles(); + + // Check the Input + if(g_pInput->getPulsedCommand(IC_DOWN, 80)) + DifficultyMenu->setNextSelection(); + if(g_pInput->getPulsedCommand(IC_UP, 80)) + DifficultyMenu->setPrevSelection(); + + if(g_pInput->getPressedCommand(IC_STATUS)) + { + selection = DifficultyMenu->getSelection(); + break; + } + // Render the Games-Menu + DifficultyMenu->renderDialog(); + + // blit the scrollbuffer to the display + gamedo_frameskipping_blitonly(); + + g_pInput->pollEvents(); + g_pTimer->SpeedThrottle(); + + } while(1); + + delete DifficultyMenu; + + return selection; +} + +int AudioDlg(stCloneKeenPlus *pCKP) +{ + CDialog *AudioMenu; + int bmnum; + int selection; + int x; + int ok=0; + + int rate=0; + short mode=0; + + showmapatpos(90, MAINMENU_X, MENUS_Y, 0, pCKP); + + // Load the Title Bitmap + bmnum = g_pGraphics->getBitmapNumberFromName("TITLE"); + x = (320/2)-(bitmaps[bmnum].xsize/2); + g_pGraphics->drawBitmap(x, 0, bmnum); + + // Prepare the Games Menu + AudioMenu = new CDialog(); + AudioMenu->setDimensions(4,4,32,7); + + char buf[256]; + rate = g_pSound->getAudioSpec().freq; + sprintf(buf,"Rate: %d kHz",rate); + AudioMenu->addOptionText(buf); + mode = g_pSound->getAudioSpec().channels - 1; + if(mode == 1) + AudioMenu->addOptionText("Mode: Stereo"); + else + AudioMenu->addOptionText("Mode: Mono"); + AudioMenu->addSeparator(); + AudioMenu->addOptionText("Save and go back"); + AudioMenu->addOptionText("Cancel"); + + AudioMenu->animateDialogBox(true); + + do + { + // do fades + gamedo_fades(); + if(fade.mode == FADE_COMPLETE) + AudioMenu->setVisible(true); + gamedo_AnimatedTiles(); + + // Check the Input + if(g_pInput->getPulsedCommand(IC_DOWN, 80)) + AudioMenu->setNextSelection(); + if(g_pInput->getPulsedCommand(IC_UP, 80)) + AudioMenu->setPrevSelection(); + + if(g_pInput->getPressedCommand(IC_STATUS)) + { + selection = AudioMenu->getSelection(); + + if(selection == 0) + { + switch(rate) + { + case 44100: rate = 48000; break; + case 22050: rate = 44100; break; + case 11000: rate = 22050; break; + default: rate = 11000; break; + } + + sprintf(buf,"Rate: %d kHz",rate); + AudioMenu->setOptionText(0,buf); + } + + if(selection == 1) + { + mode = !mode; + if(!mode) + AudioMenu->setOptionText(1,"Mode: Mono"); + else + AudioMenu->setOptionText(1,"Mode: Stereo"); + } + + if(selection == 3) + { + g_pSound->destroy(); + g_pSound->setSoundmode(rate, mode ? true : false); + CSettings *Settings; + Settings = new CSettings(); + Settings->saveDrvCfg(); + delete Settings; Settings = NULL; + g_pSound->init(); + ok = g_pSound->loadSoundData(pCKP->Control.levelcontrol.episode, + pCKP->GameData[pCKP->Resources.GameSelected-1].DataDirectory); + + break; + } + if(selection == 4) + break; + + } + // Render the Games-Menu + AudioMenu->renderDialog(); + + // blit the scrollbuffer to the display + gamedo_frameskipping_blitonly(); + + g_pInput->pollEvents(); + g_pTimer->SpeedThrottle(); + + } while(1); + + delete AudioMenu; + return ok; +} + +void OptionsDlg(stCloneKeenPlus *pCKP) +{ + CDialog *OptionsMenu; + int bmnum; + int selection; + int x,i; + + char buf[256]; + + showmapatpos(90, MAINMENU_X, MENUS_Y, 0, pCKP); + + // Load the Title Bitmap + bmnum = g_pGraphics->getBitmapNumberFromName("TITLE"); + x = (320/2)-(bitmaps[bmnum].xsize/2); + g_pGraphics->drawBitmap(x, 0, bmnum); + + // Prepare the Games Menu + OptionsMenu = new CDialog(); + OptionsMenu->setDimensions(3,3,34,12); + + for( i = 0 ; i < NUM_OPTIONS ; i++ ) + { + sprintf(buf,"%s: ",options[i].name); + if(options[i].value) + strcat(buf,"Enabled"); + else + strcat(buf,"Disabled"); + + OptionsMenu->addOptionText(buf); + } + + OptionsMenu->addSeparator(); + OptionsMenu->addOptionText("Return"); + + OptionsMenu->animateDialogBox(true); + + do + { + // do fades + gamedo_fades(); + if(fade.mode == FADE_COMPLETE) + OptionsMenu->setVisible(true); + gamedo_AnimatedTiles(); + + // Check the Input + if(g_pInput->getPulsedCommand(IC_DOWN, 80)) + OptionsMenu->setNextSelection(); + if(g_pInput->getPulsedCommand(IC_UP, 80)) + OptionsMenu->setPrevSelection(); + + if(g_pInput->getPressedCommand(IC_STATUS)) + { + selection = OptionsMenu->getSelection(); + + if(selection < NUM_OPTIONS) + { + sprintf(buf,"%s: ",options[selection].name); + + if(options[selection].value) + { + options[selection].value = 0; + strcat(buf,"Disabled"); + } + else + { + options[selection].value = 1; + strcat(buf,"Enabled"); + } + + OptionsMenu->setOptionText(selection,buf); + } + else + { + CSettings Settings; + Settings.saveGameCfg(pCKP->Option); + break; + } + } + // Render the Games-Menu + OptionsMenu->renderDialog(); + + // blit the scrollbuffer to the display + gamedo_frameskipping_blitonly(); + + g_pInput->pollEvents(); + g_pTimer->SpeedThrottle(); + + } while(1); + + delete OptionsMenu; +} + +short GraphicsDlg(stCloneKeenPlus *pCKP) +{ + CDialog *DisplayMenu; + int bmnum; + int selection; + int x; + unsigned int width; + unsigned int height; + unsigned short depth; + unsigned short zoom = 1; + unsigned short filter = 0; + unsigned short frameskip = 0; + bool opengl = false; + unsigned char gl_filter = 0; + bool fsmode; + char buf[256]; + short retval = 0; + unsigned char autoframeskip = 0; + bool aspect; + + showmapatpos(90, MAINMENU_X, MENUS_Y, 0, pCKP); + + // Load the Title Bitmap + bmnum = g_pGraphics->getBitmapNumberFromName("TITLE"); + x = (320/2)-(bitmaps[bmnum].xsize/2); + g_pGraphics->drawBitmap(x, 0, bmnum); + + // Prepare the Games Menu + DisplayMenu = new CDialog(); + DisplayMenu->setDimensions(4,3,32,13); + + width = g_pVideoDriver->getWidth(); + height = g_pVideoDriver->getHeight(); + depth = g_pVideoDriver->getDepth(); + sprintf(buf,"Resolution: %dx%dx%d",width,height,depth); + + zoom = g_pVideoDriver->getZoomValue(); + filter = g_pVideoDriver->getFiltermode(); + frameskip = g_pVideoDriver->getFrameskip(); + + DisplayMenu->addOptionText(buf); + if(g_pVideoDriver->getFullscreen()) + { + DisplayMenu->addOptionText("Fullscreen mode"); + fsmode = true; + } + else + { + DisplayMenu->addOptionText("Windowed mode"); + fsmode = false; + } + + opengl = g_pVideoDriver->isOpenGL(); + if(!opengl) + { + zoom = g_pVideoDriver->getZoomValue(); + + if(zoom == 1) + sprintf(buf,"No scale"); + else + sprintf(buf,"Scale: %d", zoom); + DisplayMenu->addOptionText(buf); + } + else + { + gl_filter = g_pVideoDriver->getOGLFilter(); + + if(gl_filter == 1) + sprintf(buf,"OGL Filter: Linear"); + else + sprintf(buf,"OGL Filter: Nearest"); + DisplayMenu->addOptionText(buf); + } + + filter = g_pVideoDriver->getFiltermode(); + if(filter == 0) + DisplayMenu->addOptionText("No Filter"); + else if(filter == 1) + DisplayMenu->addOptionText("Scale2x Filter"); + else if(filter == 2) + DisplayMenu->addOptionText("Scale3x Filter"); + else if(filter == 3) + DisplayMenu->addOptionText("Scale4x Filter"); + else + DisplayMenu->addOptionText("Unknown Filter"); + + sprintf(buf,"Frameskip: %d", frameskip); + DisplayMenu->addOptionText(buf); + + if(opengl) + DisplayMenu->addOptionText("OpenGL Acceleration"); + else + DisplayMenu->addOptionText("Software Rendering"); + + autoframeskip = g_pVideoDriver->getTargetFPS(); + + if(autoframeskip) + sprintf(buf,"Auto-Frameskip : %d fps",autoframeskip); + else + sprintf(buf,"Auto-Frameskip disabled"); + + DisplayMenu->addOptionText(buf); + + aspect = g_pVideoDriver->getAspectCorrection(); + + if(aspect) + DisplayMenu->addOptionText("OGL Aspect Ratio Enabled"); + else + DisplayMenu->addOptionText("OGL Aspect Ratio Disabled"); + + DisplayMenu->addSeparator(); + DisplayMenu->addOptionText("Save and return"); + DisplayMenu->addOptionText("Cancel"); + DisplayMenu->animateDialogBox(true); + + do + { + // do fades + gamedo_fades(); + if(fade.mode == FADE_COMPLETE) + DisplayMenu->setVisible(true); + gamedo_AnimatedTiles(); + + // Check the Input + if(g_pInput->getPulsedCommand(IC_DOWN, 80)) + DisplayMenu->setNextSelection(); + if(g_pInput->getPulsedCommand(IC_UP, 80)) + DisplayMenu->setPrevSelection(); + + if(g_pInput->getPressedCommand(IC_STATUS)) + { + selection = DisplayMenu->getSelection(); + + if(selection == 0) + { + // Now the part of the resolution list + st_resolution Resolution; + Resolution = g_pVideoDriver->setNextResolution(); + + sprintf(buf,"Resolution: %dx%dx%d", Resolution.width, Resolution.height, Resolution.depth); + DisplayMenu->setOptionText(selection,buf); + } + else if(selection == 1) + { + if(!fsmode) + DisplayMenu->setOptionText(1,"Fullscreen mode"); + else + DisplayMenu->setOptionText(1,"Windowed mode"); + fsmode = !fsmode; + } + else if(selection == 2) + { + if(opengl) + { + gl_filter = (gl_filter==1) ? 0 : 1; + + if(gl_filter == 1) + sprintf(buf,"OGL Filter: Linear"); + else + sprintf(buf,"OGL Filter: Nearest"); + + DisplayMenu->setOptionText(2,buf); + } + else + { + if(zoom >= 4) + zoom = 1; + else + zoom++; + + if(zoom == 1) + sprintf(buf,"No scale"); + else + sprintf(buf,"Scale: %d", zoom); + } + + DisplayMenu->setOptionText(2,buf); + } + + else if(selection == 3) + { + if(filter >= 3) + filter = 0; + else + filter++; + + if(filter == 0) + DisplayMenu->setOptionText(3,"No Filter"); + else if(filter == 1) + DisplayMenu->setOptionText(3,"Scale2x Filter"); + else if(filter == 2) + DisplayMenu->setOptionText(3,"Scale3x Filter"); + else if(filter == 3) + DisplayMenu->setOptionText(3,"Scale4x Filter"); + } + else if(selection == 4) + { + frameskip++; + + if(frameskip > 20) + frameskip = 0; + + sprintf(buf,"Frameskip: %d",frameskip); + DisplayMenu->setOptionText(4,buf); + } + else if(selection == 5) + { + opengl = opengl ? false : true; // switch the mode!! + + if(opengl) + DisplayMenu->setOptionText(5,"OpenGL Acceleration"); + else + DisplayMenu->setOptionText(5,"Software Rendering"); + } + else if(selection == 6) + { + if(autoframeskip < 70) + { + autoframeskip += 10; + sprintf(buf,"Auto-Frameskip : %d fps", autoframeskip); + } + else + { + autoframeskip = 0; + sprintf(buf,"Auto-Frameskip disabled"); + } + + DisplayMenu->setOptionText(6, buf); + } + else if(selection == 7) + { + aspect = !aspect; + + if(aspect) + DisplayMenu->setOptionText(7,"OGL Aspect Ratio Enabled"); + else + DisplayMenu->setOptionText(7,"OGL Aspect Ratio Disabled"); + + } + else if(selection == 9) + { + g_pVideoDriver->stop(); + + if(fsmode) + g_pVideoDriver->isFullscreen(true); + else + g_pVideoDriver->isFullscreen(false); + + g_pVideoDriver->enableOpenGL(opengl); + g_pVideoDriver->setOGLFilter(gl_filter); + g_pVideoDriver->setZoom(zoom); + g_pVideoDriver->setFilter(filter); + g_pVideoDriver->setFrameskip(frameskip); + g_pVideoDriver->setTargetFPS(autoframeskip); + g_pVideoDriver->setAspectCorrection(aspect); + + // initialize/activate all drivers + g_pLogFile->ftextOut("Restarting graphics driver... (Menu)
"); + if (g_pVideoDriver->start()) + retval = 1; + + CSettings *Settings; + Settings = new CSettings(); + + Settings->saveDrvCfg(); + delete Settings; Settings = NULL; + + showmapatpos(90, MAINMENU_X, MENUS_Y, 0, pCKP); + + fade.mode = FADE_GO; + fade.dir = FADE_IN; + fade.curamt = 0; + fade.rate = FADE_NORM; + fade.fadetimer = 0; + gamedo_fades(); + break; + } + else + break; + } + // Render the Games-Menu + DisplayMenu->renderDialog(); + + // blit the scrollbuffer to the display + gamedo_frameskipping_blitonly(); + + g_pInput->pollEvents(); + g_pTimer->SpeedThrottle(); + + } while(1); + + delete DisplayMenu; + + return retval; +} + + +// This function shows the Story of Commander Keen! +void showPage(char *text, stCloneKeenPlus *pCKP, int textsize) +{ + unsigned int i, j, k; + int exit=0; + int textpos; + bool enter; + unsigned int dlgX,dlgY,dlgW,dlgH; + unsigned int scroll, maxscroll; + char buffer[200][40]; + + showmapatpos(90, STORYBOARD_X, STORYBOARD_Y, 0, pCKP); + + fade.mode = FADE_GO; + fade.rate = FADE_NORM; + fade.dir = FADE_IN; + fade.curamt = 0; + fade.fadetimer = 0; + + scroll=0; + maxscroll=0; + + j=0; + k=0; + + AllPlayersInvisible(); + + dlgX = 0; + dlgY = 0; + dlgW = 39; + dlgH = 15; + + textpos=0; + memset(buffer,0,200*40*sizeof(char)); + // Prepare the buffer + + char sbuf[256]; + unsigned int totnumline=0; + + for(i=0;i<200;i++) + { + for(j=0;j dlgW-2)) + { + if(text[textpos] == ' ') + { + textpos++; + break; + } + } + + if(text[textpos]=='\n' ) + { + textpos++; + break; + } + + if(text[textpos]==31 ) // I don't know, what they do, + //but original version seems to ignore them! + { + text[textpos]=' '; + } + + + buffer[i][j]=text[textpos]; + textpos++; + if(textpos >= textsize) + break; + } + if(textpos >= textsize) + { + totnumline+=3; + break; + } + + totnumline++; + } + buffer[i][j] = ' '; // Last character is empty! + + char coverline[39]; + memset(coverline,2,38*sizeof(char)); // for the upper and lower edges + coverline[38]=0; + + do + { + gamedo_fades(); + + gamedo_AnimatedTiles(); + + sb_dialogbox(dlgX, dlgY, dlgW, dlgH); + + k=0; + + // Draw the text + for(i=0;i>3)][0]=='~') // Special Background Colour + { + std::string temp(38, ' '); + g_pGraphics->sb_color_font_draw(temp, (dlgX+1)<<3, (((dlgY+i+1)<<3) -(scroll%8)),COLOUR_DARKRED,COLOUR_GREY); + g_pGraphics->sb_color_font_draw(buffer[i+(scroll>>3)]+1, (dlgX+1)<<3, (((dlgY+i+1)<<3) -(scroll%8)),COLOUR_DARKRED,COLOUR_GREY); + } + else + { + g_pGraphics->sb_font_draw(buffer[i+(scroll>>3)], (dlgX+1)<<3, (((dlgY+i+1)<<3) -(scroll%8))); + } + } + g_pGraphics->sb_font_draw(coverline, (dlgX+1)<<3, dlgY); // Upper and lower edge Update + g_pGraphics->sb_font_draw(coverline, (dlgX+1)<<3, (dlgY+dlgH-1)<<3); + + // If user presses up or down + if (g_pInput->getHoldedCommand(0,IC_DOWN) || g_pInput->getHoldedCommand(1,IC_DOWN)) + { + if(scroll < (totnumline-dlgH)<<3) + scroll++; + SDL_Delay(2); + } + else if (g_pInput->getHoldedCommand(0,IC_UP) || g_pInput->getHoldedCommand(1,IC_UP)) + { + if(scroll > 0) + scroll--; + SDL_Delay(2); + } + + enter = (g_pInput->getPressedCommand(0,IC_STATUS) || g_pInput->getPressedCommand(1,IC_STATUS)); + if (enter) + { + exit=1; + fade.dir = FADE_OUT; + fade.curamt = PAL_FADE_SHADES; + fade.fadetimer = 0; + fade.rate = FADE_NORM; + fade.mode = FADE_GO; + } + + gamedo_frameskipping(pCKP); + + g_pInput->pollEvents(); + g_pTimer->SpeedThrottle(); + + + if(exit==1 && fade.mode==FADE_COMPLETE) + break; + + if (g_pInput->getPressedCommand(KQUIT)) break; + } while(!crashflag); + return; +} + +char configmenu(stCloneKeenPlus *pCKP) +{ + CDialog *OptionsMenu; + int bmnum; + int selection; + int x; + + showmapatpos(90, MAINMENU_X, MENUS_Y, 0, pCKP); + + // Load the Title Bitmap + bmnum = g_pGraphics->getBitmapNumberFromName("TITLE"); + + x = (320/2)-(bitmaps[bmnum].xsize/2); + + g_pGraphics->drawBitmap(x, 0, bmnum); + + // Prepare the Games Menu + OptionsMenu = new CDialog(); + + OptionsMenu->setDimensions(15,4,14,8); + + OptionsMenu->addOptionText("Graphics"); + OptionsMenu->addOptionText("Audio"); + OptionsMenu->addOptionText("Game"); + OptionsMenu->addOptionText("Controls"); + OptionsMenu->addSeparator(); + OptionsMenu->addOptionText("Back"); + + OptionsMenu->animateDialogBox(true); + + do + { + // do fades + gamedo_fades(); + if(fade.mode == FADE_COMPLETE) + OptionsMenu->setVisible(true); + + gamedo_AnimatedTiles(); + + // Check the Input + if(g_pInput->getPulsedCommand(IC_DOWN, 80)) + OptionsMenu->setNextSelection(); + if(g_pInput->getPulsedCommand(IC_UP, 80)) + OptionsMenu->setPrevSelection(); + + if(g_pInput->getPressedCommand(IC_STATUS)) + { + selection = OptionsMenu->getSelection(); + break; + } + // Render the Games-Menu + OptionsMenu->renderDialog(); + + // blit the scrollbuffer to the display + gamedo_frameskipping_blitonly(); + + g_pInput->pollEvents(); + g_pTimer->SpeedThrottle(); + + } while(1); + + switch(selection) + { + case 0: + GraphicsDlg(pCKP); + break; + + case 1: + AudioDlg(pCKP); + break; + + case 2: + OptionsDlg(pCKP); + break; + + case 3: + controlsmenu(pCKP); + break; + + default: + break; + } + + delete OptionsMenu; + + return 0; +} + +char controlsmenu(stCloneKeenPlus *pCKP) +{ + CDialog *ControlsMenu; + int bmnum; + int selection; + int x; + char buf[256]; + char buf2[256]; + + showmapatpos(90, MAINMENU_X, MENUS_Y, 0, pCKP); + + // Load the Title Bitmap + bmnum = g_pGraphics->getBitmapNumberFromName("TITLE"); + + x = (320/2)-(bitmaps[bmnum].xsize/2); + + g_pGraphics->drawBitmap(x, 0, bmnum); + + // Prepare the Games Menu + ControlsMenu = new CDialog(); + + ControlsMenu->setDimensions(1,3,38,20); + + g_pInput->getEventName(IC_LEFT, 0, buf2); + sprintf(buf,"P1 Left: %s",buf2); + ControlsMenu->addOptionText(buf); + g_pInput->getEventName(IC_UP, 0, buf2); + sprintf(buf,"P1 Up: %s",buf2); + ControlsMenu->addOptionText(buf); + g_pInput->getEventName(IC_RIGHT, 0, buf2); + sprintf(buf,"P1 Right: %s",buf2); + ControlsMenu->addOptionText(buf); + g_pInput->getEventName(IC_DOWN, 0, buf2); + sprintf(buf,"P1 Down: %s",buf2); + ControlsMenu->addOptionText(buf); + g_pInput->getEventName(IC_JUMP, 0, buf2); + sprintf(buf,"P1 Jump: %s",buf2); + ControlsMenu->addOptionText(buf); + g_pInput->getEventName(IC_POGO, 0, buf2); + sprintf(buf,"P1 Pogo: %s",buf2); + ControlsMenu->addOptionText(buf); + g_pInput->getEventName(IC_FIRE, 0, buf2); + sprintf(buf,"P1 Fire: %s",buf2); + ControlsMenu->addOptionText(buf); + g_pInput->getEventName(IC_STATUS, 0, buf2); + sprintf(buf,"P1 Status: %s",buf2); + ControlsMenu->addOptionText(buf); + + g_pInput->getEventName(IC_LEFT, 1, buf2); + sprintf(buf,"P2 Left: %s",buf2); + ControlsMenu->addOptionText(buf); + g_pInput->getEventName(IC_UP, 1, buf2); + sprintf(buf,"P2 Up: %s",buf2); + ControlsMenu->addOptionText(buf); + g_pInput->getEventName(IC_RIGHT, 1, buf2); + sprintf(buf,"P2 Right: %s",buf2); + ControlsMenu->addOptionText(buf); + g_pInput->getEventName(IC_DOWN, 1, buf2); + sprintf(buf,"P2 Down: %s",buf2); + ControlsMenu->addOptionText(buf); + g_pInput->getEventName(IC_JUMP, 1, buf2); + sprintf(buf,"P2 Jump: %s",buf2); + ControlsMenu->addOptionText(buf); + g_pInput->getEventName(IC_POGO, 1, buf2); + sprintf(buf,"P2 Pogo: %s",buf2); + ControlsMenu->addOptionText(buf); + g_pInput->getEventName(IC_FIRE, 1, buf2); + sprintf(buf,"P2 Fire: %s",buf2); + ControlsMenu->addOptionText(buf); + g_pInput->getEventName(IC_STATUS, 1, buf2); + sprintf(buf,"P2 Status: %s",buf2); + ControlsMenu->addOptionText(buf); + ControlsMenu->addSeparator(); + ControlsMenu->addOptionText("Return"); + + ControlsMenu->animateDialogBox(true); + + do + { + // do fades + gamedo_fades(); + if(fade.mode == FADE_COMPLETE) + ControlsMenu->setVisible(true); + gamedo_AnimatedTiles(); + + // Check the Input + if(g_pInput->getPulsedCommand(IC_DOWN, 80)) + ControlsMenu->setNextSelection(); + if(g_pInput->getPulsedCommand(IC_UP, 80)) + ControlsMenu->setPrevSelection(); + + if(g_pInput->getPressedCommand(IC_STATUS)) + { + selection = ControlsMenu->getSelection(); + + if(selection < MAX_COMMANDS) + { + int item=0; + if(selection < 4) + item = selection + 4; + else + item = selection - 4; + + switch(selection) + { + case 0: sprintf(buf,"P1 Left: "); break; + case 1: sprintf(buf,"P1 Up: "); break; + case 2: sprintf(buf,"P1 Right: "); break; + case 3: sprintf(buf,"P1 Down: "); break; + case 4: sprintf(buf,"P1 Jump: "); break; + case 5: sprintf(buf,"P1 Pogo: "); break; + case 6: sprintf(buf,"P1 Fire: "); break; + case 7: sprintf(buf,"P1 Status: "); break; + } + + strcpy(buf2,buf); + strcat(buf2,"*Waiting for Input*"); + ControlsMenu->setOptionText(selection,buf2); + + while(!g_pInput->readNewEvent(0,item)) + { + ControlsMenu->renderDialog(); + gamedo_frameskipping_blitonly(); + } + + g_pInput->getEventName(item, 0, buf2); + strcat(buf,buf2); + ControlsMenu->setOptionText(selection,buf); + } + else if(selection >= MAX_COMMANDS && selection < MAX_COMMANDS*2) + { + int item=0; + if(selection < (4 + MAX_COMMANDS)) + item = selection + 4 - MAX_COMMANDS; + else + item = selection - 4 - MAX_COMMANDS; + + switch(selection) + { + case 0+ MAX_COMMANDS: sprintf(buf,"P2 Left: "); break; + case 1+ MAX_COMMANDS: sprintf(buf,"P2 Up: "); break; + case 2+ MAX_COMMANDS: sprintf(buf,"P2 Right: "); break; + case 3+ MAX_COMMANDS: sprintf(buf,"P2 Down: "); break; + case 4+ MAX_COMMANDS: sprintf(buf,"P2 Jump: "); break; + case 5+ MAX_COMMANDS: sprintf(buf,"P2 Pogo: "); break; + case 6+ MAX_COMMANDS: sprintf(buf,"P2 Fire: "); break; + case 7+ MAX_COMMANDS: sprintf(buf,"P2 Status: "); break; + } + + strcpy(buf2,buf); + strcat(buf2,"*Waiting for Input*"); + ControlsMenu->setOptionText(selection,buf2); + + while(!g_pInput->readNewEvent(1,item)) + { + ControlsMenu->renderDialog(); + gamedo_frameskipping_blitonly(); + } + + g_pInput->getEventName(item, 1, buf2); + strcat(buf,buf2); + ControlsMenu->setOptionText(selection,buf); + } + else + { + g_pInput->saveControlconfig(); + break; + } + } + // Render the Menu + ControlsMenu->renderDialog(); + + // blit the scrollbuffer to the display + gamedo_frameskipping_blitonly(); + + g_pInput->pollEvents(); + g_pTimer->SpeedThrottle(); + + } while(1); + + delete ControlsMenu; + return 0; +} + +void keensleft(stCloneKeenPlus *pCKP) +{ +int enter, lastenterstate; +unsigned int p; +int x,y,i; +int boxY, boxH; +int boxtimer; +int ep3; + +stLevelControl *p_levelcontrol; + + p_levelcontrol = &(pCKP->Control.levelcontrol); + + // on episode 3 we have to subtract one from the map tiles + // because the tiles start at 31, not 32 like on the other eps + ep3 = 0; + if (p_levelcontrol->episode==3) ep3 = 1; + + #define KEENSLEFT_TIME 400 + + for(i=0;idrawFont( getstring("LIVES_LEFT_BACKGROUND"),(KEENSLEFT_X+1)*8,(boxY+1)*8,0); + g_pGraphics->drawFont( getstring("LIVES_LEFT"),((KEENSLEFT_X+7)*8)+4,(boxY+1)*8,0); + y = ((boxY+2)*8)+4; + if (numplayers>1) y--; + for(p=0;pdrawSprite_direct(x, y, PMAPDOWNFRAME+playerbaseframes[p]-ep3); + x+=16; + } + y+=18; + } + g_pVideoDriver->update_screen(); + + g_pSound->playSound(SOUND_KEENSLEFT, PLAY_NOW); + + boxtimer = 0; + do + { + + gamedo_fades(); + + if (boxtimer > KEENSLEFT_TIME) + { + break; + } else boxtimer++; + + enter = g_pInput->getPressedCommand(IC_STATUS)||g_pInput->getPressedCommand(IC_FIRE)|| + g_pInput->getPressedCommand(IC_JUMP)||g_pInput->getPressedCommand(IC_POGO); + if (enter) + { + break; + } + if (g_pInput->getPressedCommand(KQUIT)) + { + return; + } + + lastenterstate = enter; + g_pInput->pollEvents(); + g_pTimer->SpeedThrottle(); + } while(!crashflag); + +} diff --git a/src/misc.cpp b/src/misc.cpp index 7106f8872..60bbde906 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -1,1373 +1,1366 @@ -/* MISC.C - All KINDS of assorted crap :) Has most of the in-game dialog boxes - such as the status box etc. - - Also like I said there's all kinds of assorted crap in here. - That's why it's called "misc.c" (get it? :)) -*/ - -#include "keen.h" -#ifdef BUILD_SDL -#include -#include "sdl/joydrv.h" -#include "sdl/CInput.h" -#include "sdl/CTimer.h" -#include "sdl/CVideoDriver.h" -#include "sdl/sound/CSound.h" -#endif - -#include "include/misc.h" -#include "include/game.h" -#include "include/eseq_ep1.h" -#include "include/eseq_ep2.h" -#include "include/eseq_ep3.h" -#include "include/gamedo.h" -#include "CLogFile.h" -#include "CGraphics.h" - -void banner(void) -{ -char buf[80]; - - sprintf(buf, "%s *Unknown* build check banner()", REVISION); - #ifdef TARGET_WIN32 - sprintf(buf, "%s Windows build", REVISION); - #endif - #ifdef TARGET_LNX - sprintf(buf, "%s Linux build", REVISION); - #endif - printf("%s", buf); - printf(" (%d bit)", static_cast (sizeof(int*)*8)); - - 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"); - printf("\n"); -} - -void cleanup(stCloneKeenPlus *CKP) -{ - if(CKP->GameData){ delete[] CKP->GameData; CKP->GameData = NULL; } - - g_pLogFile->ftextOut(BLACK,true," Freed %d strings.
", freestrings()); - - JoyDrv_Stop(&(CKP->Joystick)); - g_pLogFile->textOut(BLACK,true," Joystick driver shut down.
"); - g_pSound->stopAllSounds(); - g_pSound->destroy(); - g_pLogFile->textOut(BLACK,true," Sound driver shut down.
"); - - #ifdef NETWORK_PLAY - if (is_server) - { - NetDrv_Server_Stop(); - g_pLogFile->ftextOut(" * Network (server) shut down.
"); - } - if (is_client) - { - NetDrv_Client_Stop(); - g_pLogFile->ftextOut(" * Network (client) shut down.
"); - } - #endif - - if (demofile) - { - fclose(demofile); - g_pLogFile->ftextOut(BLACK,true," Demo file closed.
"); - } - - g_pGraphics->stopGraphics(); - g_pLogFile->ftextOut(BLACK,true," Graphics driver shut down.
"); - - g_pGraphics->freemem(); - - g_pLogFile->ftextOut("
"); -} - -// draw an empty dialog box, for youseeinyourmind(), etc. -void dialogbox(int x1, int y1, int w, int h) -{ -int x,y,i,j; - - g_pGraphics->drawCharacter(x1*8, y1*8, 1); - g_pGraphics->drawCharacter((x1+w)*8, y1*8, 3); - for(x=(x1*8)+8,i=0;idrawCharacter(x, y1*8, 2); - x+=8; - } - y=(y1+1)*8; - for(j=0;jdrawCharacter(x, y, 4); - else if (i==w) g_pGraphics->drawCharacter(x, y, 5); - else g_pGraphics->drawCharacter(x, y, ' '); - x+=8; - } - y+=8; - } - for(x=(x1*8),i=0;i<=w;i++) - { - if (i==0) g_pGraphics->drawCharacter(x, y, 6); - else if (i==w) g_pGraphics->drawCharacter(x, y, 8); - else g_pGraphics->drawCharacter(x, y, 7); - x+=8; - } -} -// draw an empty dialog box, for youseeinyourmind(), etc. -void sb_dialogbox(int x1, int y1, int w, int h) -{ - int x,y,i,j; - - g_pGraphics->sb_drawCharacter(x1*8, y1*8, 1); - g_pGraphics->sb_drawCharacter((x1+w)*8, y1*8, 3); - for(x=(x1*8)+8,i=0;isb_drawCharacter(x, y1*8, 2); - x+=8; - } - y=(y1+1)*8; - for(j=0;jsb_drawCharacter(x, y, 4); - else if (i==w) g_pGraphics->sb_drawCharacter(x, y, 5); - else g_pGraphics->sb_drawCharacter(x, y, ' '); - x+=8; - } - y+=8; - } - for(x=(x1*8),i=0;i<=w;i++) - { - if (i==0) g_pGraphics->sb_drawCharacter(x, y, 6); - else if (i==w) g_pGraphics->sb_drawCharacter(x, y, 8); - else g_pGraphics->sb_drawCharacter(x, y, 7); - x+=8; - } -} - -#define YORPSTATUEHEADUSED 485 -void youseeinyourmind(int mpx, int mpy, stCloneKeenPlus *pCKP) -{ -int twirlframe, twirltimer; -char strname[80]; -int dlgX,dlgY,dlgW,dlgH,twirlX,twirlY; - -bool isgarg; - -int i; - - isgarg = false; - if(map.mapdata[mpx][mpy] >= 435 && map.mapdata[mpx][mpy] <= 438) - isgarg = true; - - if (!isgarg) - { - if(!map_isanimated(mpx, mpy)) - return; - } - else - { // it's a garg statue - if(!map_isanimated(mpx, mpy)) - return; - } - - for(i=0; i < 4 ; i++) - { - player[0].playcontrol[PA_JUMP+i] = 0; - } - - 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); - - dlgX = GetStringAttribute(strname, "LEFT"); - dlgY = GetStringAttribute(strname, "TOP"); - dlgW = GetStringAttribute(strname, "WIDTH"); - dlgH = GetStringAttribute(strname, "HEIGHT"); - twirlX = GetStringAttribute(strname, "TWIRLX"); - twirlY = GetStringAttribute(strname, "TWIRLY"); - - dialogbox(dlgX,dlgY,dlgW,dlgH); - g_pGraphics->drawFont((unsigned char*) getstring(strname), (dlgX+1)<<3, (dlgY+1)<<3,0); - - twirlframe = 0; - twirltimer = twirl_speed+1; - // wait for enter - do - { - if (twirltimer>twirl_speed) - { - g_pGraphics->drawCharacter((dlgX+twirlX)<<3, (dlgY+twirlY)<<3, 9+twirlframe); - g_pVideoDriver->update_screen(); - twirlframe++; - if (twirlframe>5) twirlframe=0; - twirltimer=0; - } else twirltimer++; - g_pInput->pollEvents(); - g_pTimer->SpeedThrottle(); - g_pVideoDriver->update_screen(); - } while(!g_pInput->getPressedKey(KENTER) /*&& !immediate_keytable[KQUIT] && !getanyevent(pCKP)*/); - - // make the statue head stop glowing - if (!isgarg) - { - map_chgtile(mpx, mpy, YORPSTATUEHEADUSED); - map_deanimate(mpx, mpy); - } - else - { // it's a garg statue - - map_chgtile(mpx, mpy, 434); - map_deanimate(mpx, mpy); - } -} - -void VorticonElder(int mpx, int mpy, stCloneKeenPlus *pCKP) -{ - int twirlframe, twirltimer; - int dlgX,dlgY,dlgW,dlgH,twirlX,twirlY; - const char *strName; - const int twirl_speed = 100; - - for(int i=0; i < 4 ; i++) - { - player[0].playcontrol[PA_JUMP+i] = 0; - } - - g_pSound->pauseSound(); - - switch(pCKP->Control.levelcontrol.curlevel) - { - case 8: - strName = "EP2_VE_NOJUMPINDARK"; - break; - case 10: - strName = "EP2_VE_EVILBELTS"; - break; - - default: - crashflag = 1; - why_term_ptr = "VE box: Illegal level #."; - break; - } - - dlgX = GetStringAttribute(strName, "LEFT"); - dlgY = GetStringAttribute(strName, "TOP"); - dlgW = GetStringAttribute(strName, "WIDTH"); - dlgH = GetStringAttribute(strName, "HEIGHT"); - twirlX = GetStringAttribute(strName, "TWIRLX"); - twirlY = GetStringAttribute(strName, "TWIRLY"); - - dialogbox(dlgX, dlgY, dlgW, dlgH); - g_pGraphics->drawFont( (unsigned char*) getstring(strName), (dlgX+1)<<3, (dlgY+1)<<3,0); - - twirlframe = 0; - twirltimer = twirl_speed+1; - // wait for enter - do - { - if (twirltimer>twirl_speed) - { - g_pGraphics->drawCharacter((dlgX+twirlX)<<3, (dlgY+twirlY)<<3, 9+twirlframe); - g_pVideoDriver->update_screen(); - twirlframe++; - if (twirlframe>5) twirlframe=0; - twirltimer=0; - } else twirltimer++; - g_pInput->pollEvents(); - g_pTimer->SpeedThrottle(); - g_pVideoDriver->update_screen(); - } while(!g_pInput->getPressedKey(KENTER) ); - - // make the switch stop glowing - map_chgtile(mpx, mpy+1, 432); - - map_deanimate(mpx, mpy+1); - - g_pSound->resumeSounds(); -} - - -void inventory_draw_ep1(int p) -{ -int x,t,i,j; -char tempbuf[40]; -int dlgX,dlgY,dlgW,dlgH; - - dlgX = GetStringAttribute("EP1_StatusBox", "LEFT"); - dlgY = GetStringAttribute("EP1_StatusBox", "TOP"); - dlgW = GetStringAttribute("EP1_StatusBox", "WIDTH"); - dlgH = GetStringAttribute("EP1_StatusBox", "HEIGHT"); - - dialogbox(dlgX,dlgY,dlgW,dlgH); - g_pGraphics->drawFont( (unsigned char*) getstring("EP1_StatusBox"), (dlgX+1)<<3, (dlgY+1)<<3, 0); - -// fill in what we have - // 321: joystick/battery/vacuum/fuel not gotten - // 414: raygun, 415, pogo - // 424: yellow/red/green/blue cards - // 448: ship parts, gotten - // raygun icon - g_pGraphics->drawTile_direct((dlgX+4)<<3, ((dlgY+8)<<3)+3, 414); - // 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.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); - if (player[p].inventory.HasBattery) t=449; else t=322; - g_pGraphics->drawTile_direct((dlgX+21)<<3, ((dlgY+4)<<3)+3, t); - if (player[p].inventory.HasVacuum) t=450; else t=323; - g_pGraphics->drawTile_direct((dlgX+24)<<3, ((dlgY+4)<<3)+3, t); - if (player[p].inventory.HasFuel) t=451; else t=324; - g_pGraphics->drawTile_direct((dlgX+27)<<3, ((dlgY+4)<<3)+3, t); - // ray gun charges - i = player[p].inventory.charges; - if (i>999) i=999; - sprintf(tempbuf, "%d", i); - g_pGraphics->drawFont( (unsigned char*) tempbuf, (dlgX+4)<<3, (dlgY+12)<<3, 0); - - // score - i = player[p].inventory.score; - sprintf(tempbuf, "%d", i); - g_pGraphics->drawFont( (unsigned char*) tempbuf, (dlgX+12-strlen(tempbuf))<<3, (dlgY+2)<<3, 0); - // extra life at - i = player[p].inventory.extralifeat; - sprintf(tempbuf, "%d", i); - g_pGraphics->drawFont( (unsigned char*) tempbuf, (dlgX+28-strlen(tempbuf))<<3, (dlgY+2)<<3, 0); - // lives - i = player[p].inventory.lives; - x = ((dlgX+1)<<3)+4; - if (i>7) i=7; - for(j=0;jdrawSprite_direct(x, (dlgY+4)<<3, playerbaseframes[p]); - x += sprites[0].xsize; - } -} - -void inventory_draw_ep2(int p, stCloneKeenPlus *pCKP) -{ -int x,/*y,t,*/i,j; -char tempbuf[40]; -int dlgX,dlgY,dlgW,dlgH; - - stLevelControl *p_levelcontrol; - - p_levelcontrol = &(pCKP->Control.levelcontrol); - - dlgX = GetStringAttribute("EP2_StatusBox", "LEFT"); - dlgY = GetStringAttribute("EP2_StatusBox", "TOP"); - dlgW = GetStringAttribute("EP2_StatusBox", "WIDTH"); - dlgH = GetStringAttribute("EP2_StatusBox", "HEIGHT"); - - dialogbox(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.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); - if (p_levelcontrol->levels_completed[7]) g_pGraphics->drawFont( (unsigned char*) getstring("EP2_LVL7_TargetName"), (dlgX+1)<<3, (dlgY+9)<<3, 0); - if (p_levelcontrol->levels_completed[13]) g_pGraphics->drawFont( (unsigned char*) getstring("EP2_LVL13_TargetName"), (dlgX+8)<<3, (dlgY+9)<<3, 0); - if (p_levelcontrol->levels_completed[11]) g_pGraphics->drawFont( (unsigned char*) getstring("EP2_LVL11_TargetName"), (dlgX+1)<<3, (dlgY+10)<<3, 0); - if (p_levelcontrol->levels_completed[9]) g_pGraphics->drawFont( (unsigned char*) getstring("EP2_LVL9_TargetName"), (dlgX+8)<<3, (dlgY+10)<<3, 0); - if (p_levelcontrol->levels_completed[15]) g_pGraphics->drawFont( (unsigned char*) getstring("EP2_LVL15_TargetName"), (dlgX+1)<<3, (dlgY+11)<<3, 0); - if (p_levelcontrol->levels_completed[16]) g_pGraphics->drawFont( (unsigned char*) getstring("EP2_LVL16_TargetName"), (dlgX+8)<<3, (dlgY+11)<<3, 0); - - // raygun icon - g_pGraphics->drawTile_direct((dlgX+20)<<3, ((dlgY+5)<<3)-5, 414); - - // ray gun charges text - i = player[p].inventory.charges; - if (i>999) i=999; - sprintf(tempbuf, "%d", i); - g_pGraphics->drawFont( (unsigned char*) tempbuf, (dlgX+27-strlen( (char*) tempbuf))<<3, ((dlgY+5)<<3)-1, 0); - - // score - i = player[p].inventory.score; - sprintf(tempbuf, "%d", i); - g_pGraphics->drawFont( (unsigned char*) tempbuf, (dlgX+12-strlen( (char*) tempbuf))<<3, (dlgY+2)<<3, 0); - // extra life at - i = player[p].inventory.extralifeat; - sprintf(tempbuf, "%d", i); - g_pGraphics->drawFont( (unsigned char*) tempbuf, (dlgX+28-strlen( (char*) tempbuf))<<3, (dlgY+2)<<3, 0); - // lives - i = player[p].inventory.lives; - x = ((dlgX + 1)<<3)+4; - if (i>7) i=7; - for(j=0;jdrawSprite_direct(x, (dlgY+4)<<3, playerbaseframes[p]); - x += sprites[0].xsize; - } - -} - -void inventory_draw_ep3(int p) -{ -//int x,y,t,i,j; -int i,j,x; -int ankhtimepercent; -char tempbuf[40]; -int dlgX,dlgY,dlgW,dlgH; - - dlgX = GetStringAttribute("EP3_StatusBox", "LEFT"); - dlgY = GetStringAttribute("EP3_StatusBox", "TOP"); - dlgW = GetStringAttribute("EP3_StatusBox", "WIDTH"); - dlgH = GetStringAttribute("EP3_StatusBox", "HEIGHT"); - - dialogbox(dlgX,dlgY,dlgW,dlgH); - g_pGraphics->drawFont( (unsigned char*) getstring("EP3_StatusBox"), (dlgX+1)<<3, (dlgY+1)<<3, 0); - - // calculate % ankh time left - ankhtimepercent = (int)((float)player[p].ankhtime / (PLAY_ANKH_TIME/100)); - // ankh time - g_pGraphics->drawTile_direct((dlgX+4)<<3, ((dlgY+8)<<3)+3, 214); - sprintf(tempbuf, "%d", ankhtimepercent); - g_pGraphics->drawFont( (unsigned char*) tempbuf, (dlgX+8)<<3, ((dlgY+8)<<3)+7, 0); - - // raygun icon - g_pGraphics->drawTile_direct((dlgX+23)<<3, ((dlgY+5)<<3)-5, 216); - - // ray gun charges text - i = player[p].inventory.charges; - if (i>999) i=999; - sprintf(tempbuf, "%d", i); - 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.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; - sprintf(tempbuf, "%d", i); - g_pGraphics->drawFont( (unsigned char*) tempbuf, (dlgX+12-strlen(tempbuf))<<3, (dlgY+2)<<3, 0); - // extra life at - i = player[p].inventory.extralifeat; - sprintf(tempbuf, "%d", i); - g_pGraphics->drawFont( (unsigned char*) tempbuf, (dlgX+28-strlen(tempbuf))<<3, (dlgY+2)<<3, 0); - // lives - i = player[p].inventory.lives; - x = ((dlgX+1)<<3)+4; - if (i>9) i=9; - for(j=0;jdrawSprite_direct(x, (dlgY+4)<<3, playerbaseframes[p]); - x += sprites[0].xsize; - } -} - -void showinventory(int p, stCloneKeenPlus *pCKP) -{ -//int x,y,t,i,j; -//char tempbuf[40]; - unsigned short i; - - stLevelControl *p_levelcontrol; - p_levelcontrol = &(pCKP->Control.levelcontrol); - - // draw the episode-specific stuff - if (p_levelcontrol->episode==1) - { - inventory_draw_ep1(p); - } - else if (p_levelcontrol->episode==2) - { - inventory_draw_ep2(p, pCKP); - } - else if (p_levelcontrol->episode==3) - { - inventory_draw_ep3(p); - } - - - g_pVideoDriver->update_screen(); - - // wait for any button pressed or any action triggered - bool close=false; - - while(!close) - { - g_pInput->pollEvents(); - - for(i=0 ; igetPressedCommand(i)) - close=true; - } - - for(i=0 ; igetPressedKey(i)) - close=true; - } - } -} - -/*void sshot(char *visiblefile, char *scrollfile) -{ -FILE *fp; -int x,y; - - fp = fopen(visiblefile, "wb"); - if (!fp) return;< - - for(y=0;y<200;y++) - for(x=0;x<320;x++) - fputc(getpixel(x,y), fp); - - fclose(fp); - - fp = fopen(scrollfile, "wb"); - if (!fp) return; - - for(y=0;y<512;y++) - for(x=0;x<512;x++) - fputc(sb_getpixel(x,y), fp); - - fclose(fp); -}*/ - -void YourShipNeedsTheseParts(stCloneKeenPlus *pCKP) -{ -int cp = 0; -int dlgX,dlgY,dlgW,dlgH; - - dlgX = GetStringAttribute("EP1_SHIP", "LEFT"); - dlgY = GetStringAttribute("EP1_SHIP", "TOP"); - dlgW = GetStringAttribute("EP1_SHIP", "WIDTH"); - dlgH = GetStringAttribute("EP1_SHIP", "HEIGHT"); - - dialogbox(dlgX,dlgY,dlgW,dlgH); - - g_pGraphics->drawFont( (unsigned char*) getstring("EP1_SHIP"), (dlgX+1)<<3, (dlgY+1)<<3,0); - - // draw needed parts - if (!player[cp].inventory.HasJoystick) - g_pGraphics->drawTile_direct((dlgX+9)<<3, (dlgY+3)<<3, 448); - - if (!player[cp].inventory.HasBattery) - g_pGraphics->drawTile_direct((dlgX+12)<<3, (dlgY+3)<<3, 449); - - if (!player[cp].inventory.HasVacuum) - g_pGraphics->drawTile_direct((dlgX+15)<<3, (dlgY+3)<<3, 450); - - if (!player[cp].inventory.HasFuel) - g_pGraphics->drawTile_direct((dlgX+18)<<3, (dlgY+3)<<3, 451); - - g_pVideoDriver->update_screen(); - - // wait for any key! - g_pInput->flushKeys(); - while(!g_pInput->getPressedAnyKey()) - { - g_pInput->pollEvents(); - - if(g_pInput->getPressedAnyCommand()) - break; - } -} - -void ShipEp3(stCloneKeenPlus *pCKP) -{ -char strname[80]; -int twirlframe, twirltimer; -int dlgX,dlgY,dlgW,dlgH,twirlX,twirlY; -const int twirlspeed = 100; - - // display one of four random strings - sprintf(strname, "EP3_SHIP%d", (rand()%4)+1); - - dlgX = GetStringAttribute(strname, "LEFT"); - dlgY = GetStringAttribute(strname, "TOP"); - dlgW = GetStringAttribute(strname, "WIDTH"); - dlgH = GetStringAttribute(strname, "HEIGHT"); - twirlX = GetStringAttribute(strname, "TWIRLX"); - twirlY = GetStringAttribute(strname, "TWIRLY"); - - dialogbox(dlgX,dlgY,dlgW,dlgH); - g_pGraphics->drawFont( (unsigned char*) getstring(strname), (dlgX+1)<<3, (dlgY+1)<<3,0); - - g_pVideoDriver->update_screen(); - - g_pInput->flushAll(); - - twirlframe = 0; - twirltimer = twirlspeed+1; - g_pInput->flushKeys(); - // wait for any command or key - do - { - if (twirltimer>twirlspeed) - { - g_pGraphics->drawCharacter((dlgX+twirlX)<<3, (dlgY+twirlY)<<3, twirlframe+9); - g_pVideoDriver->update_screen(); - twirlframe++; - if (twirlframe>5) twirlframe=0; - twirltimer=0; - } else twirltimer++; - if(g_pInput->getPressedAnyCommand()) break; - g_pInput->pollEvents(); - g_pTimer->SpeedThrottle(); - } while(!g_pInput->getPressedAnyKey()); -} - -void game_save(char *fname, stCloneKeenPlus *pCKP) -{ - unsigned int i; - FILE *fp; - - fp = fopen(fname, "wb"); - - // save the header/version check - fputc('S', fp); - fputc(SAVEGAMEVERSION, fp); - - // save all necessary structures to the file - if (map.isworldmap) fputc('W', fp); else fputc('L', fp); - - sgrle_compress(fp, (unsigned char *)&numplayers, sizeof(numplayers)); - sgrle_compress(fp, (unsigned char *)&(pCKP->Control.levelcontrol), sizeof(pCKP->Control.levelcontrol)); - sgrle_compress(fp, (unsigned char *)&scroll_x, sizeof(scroll_x)); - sgrle_compress(fp, (unsigned char *)&scroll_y, sizeof(scroll_y)); - sgrle_compress(fp, (unsigned char *)&max_scroll_x, sizeof(max_scroll_x)); - sgrle_compress(fp, (unsigned char *)&max_scroll_y, sizeof(max_scroll_y)); - sgrle_compress(fp, (unsigned char *)&map, sizeof(map)); - for(i=0;iControl.levelcontrol); - - fp = fopen(fname, "rb"); - if (!fp) return 1; - - // do the header and version check - if (fgetc(fp) != 'S') { fclose(fp); return 1; } - if (fgetc(fp) != SAVEGAMEVERSION) { fclose(fp); return 1; } - fgetc(fp); // iswm flag--not needed here - - // load all structures from the file - sgrle_reset(); - sgrle_decompress(fp, (unsigned char *)&numplayers, sizeof(numplayers)); - sgrle_decompress(fp, (unsigned char *) p_levelcontrol , sizeof(*p_levelcontrol)); - sgrle_decompress(fp, (unsigned char *)&scrx, sizeof(scrx)); - sgrle_decompress(fp, (unsigned char *)&scry, sizeof(scry)); - sgrle_decompress(fp, (unsigned char *)&max_scroll_x, sizeof(max_scroll_x)); - sgrle_decompress(fp, (unsigned char *)&max_scroll_y, sizeof(max_scroll_y)); - sgrle_decompress(fp, (unsigned char *)&map, sizeof(map)); - - initgame(pCKP); // reset scroll - drawmap(); - for(i=0;iControl.levelcontrol); - -top: ; - if (issave) - { - dlgX = GetStringAttribute("WhichSlotSave", "LEFT"); - dlgY = GetStringAttribute("WhichSlotSave", "TOP"); - dlgW = GetStringAttribute("WhichSlotSave", "WIDTH"); - dlgH = GetStringAttribute("WhichSlotSave", "HEIGHT"); - } - else - { - dlgX = GetStringAttribute("WhichSlotLoad", "LEFT"); - dlgY = GetStringAttribute("WhichSlotLoad", "TOP"); - dlgW = GetStringAttribute("WhichSlotLoad", "WIDTH"); - dlgH = GetStringAttribute("WhichSlotLoad", "HEIGHT"); - map_redraw(); - bmnum = g_pGraphics->getBitmapNumberFromName("TITLE"); - x = (320/2)-(bitmaps[bmnum].xsize/2); - g_pGraphics->drawBitmap(x, 0, bmnum); - } - - saveslot = 0; - do - { - - gamedo_render_drawobjects(pCKP); - - sb_dialogbox(dlgX,dlgY,dlgW,dlgH); - if (issave) - { - g_pGraphics->sb_font_draw( (unsigned char*) getstring("WhichSlotSave"),(dlgX+1)<<3,(dlgY+1)<<3); - } - else - { - g_pGraphics->sb_font_draw( (unsigned char*) getstring("WhichSlotLoad"),(dlgX+1)<<3,(dlgY+1)<<3); - gamedo_AnimatedTiles(); - } - - for (int i=0 ; i<9 ; i++) - { - if (g_pInput->getPressedKey(KNUM1+i)) saveslot = 1+i; - } - - g_pVideoDriver->sb_blit(); - gamedo_render_eraseobjects(); - - - g_pInput->pollEvents(); - g_pTimer->SpeedThrottle(); - } while(!g_pInput->getPressedKey(KQUIT) && !saveslot); - - /* check if the selected save file exists */ - sprintf(fname, "ep%csave%c.dat", p_levelcontrol->episode+'0', saveslot+'0'); - slotexists = 0; - fp = fopen(fname, "rb"); - if (fp) - { - fclose(fp); - slotexists = 1; - } - - if ((issave && !slotexists) || (!issave && slotexists)) - { - map_redraw(); - return saveslot; - } - - if (issave) - { - dlgX = GetStringAttribute("SaveSlotOverwrite", "LEFT"); - dlgY = GetStringAttribute("SaveSlotOverwrite", "TOP"); - dlgW = GetStringAttribute("SaveSlotOverwrite", "WIDTH"); - dlgH = GetStringAttribute("SaveSlotOverwrite", "HEIGHT"); - } - else - { - dlgX = GetStringAttribute("LoadNoSuchSlot", "LEFT"); - dlgY = GetStringAttribute("LoadNoSuchSlot", "TOP"); - dlgW = GetStringAttribute("LoadNoSuchSlot", "WIDTH"); - dlgH = GetStringAttribute("LoadNoSuchSlot", "HEIGHT"); - } - - // either we're trying to save over an existing game, or we're - // loading a game that doesn't exist. - do - { - - gamedo_render_drawobjects(pCKP); - - sb_dialogbox(dlgX,dlgY,dlgW,dlgH); - if (issave) - { - g_pGraphics->sb_font_draw( (unsigned char*) getstring("SaveSlotOverwrite"),(dlgX+1)<<3,(dlgY+1)<<3); - if (g_pInput->getPressedKey(KN)) - { - map_redraw(); - goto top; - } - else if (g_pInput->getPressedKey(KY)) - { - map_redraw(); - return saveslot; - } - } - else - { - g_pGraphics->sb_font_draw( (unsigned char*) getstring("LoadNoSuchSlot"),(dlgX+1)<<3,(dlgY+1)<<3); - - if (g_pInput->getPressedAnyKey()) - { - map_redraw(); - goto top; - } - - gamedo_AnimatedTiles(); - } - - g_pVideoDriver->sb_blit(); - gamedo_render_eraseobjects(); - - g_pInput->pollEvents(); - g_pTimer->SpeedThrottle(); - } while(!g_pInput->getPressedKey(KQUIT)); - - map_redraw(); - return 0; -} - -void game_save_interface(stCloneKeenPlus *pCKP) -{ -int waittimer; -char fname[40]; -char saveslot; -int dlgX,dlgY,dlgW,dlgH; - - dlgX = GetStringAttribute("GameSaveSuccess", "LEFT"); - dlgY = GetStringAttribute("GameSaveSuccess", "TOP"); - dlgW = GetStringAttribute("GameSaveSuccess", "WIDTH"); - dlgH = GetStringAttribute("GameSaveSuccess", "HEIGHT"); - - saveslot = save_slot_box(1, pCKP); - if (!saveslot) return; // canceled - - /* save the game */ - sprintf(fname, "ep%csave%c.dat", pCKP->Control.levelcontrol.episode+'0', saveslot+'0'); - game_save(fname,pCKP); - - /* display the "your game has been saved" box */ - waittimer = 0; - do - { - waittimer++; - if (waittimer > 5000) break; - - gamedo_render_drawobjects(pCKP); - - sb_dialogbox(dlgX,dlgY,dlgW,dlgH); - g_pGraphics->sb_font_draw( (unsigned char*) getstring("GameSaveSuccess"),(dlgX+1)<<3,(dlgY+1)<<3); - - g_pVideoDriver->sb_blit(); - gamedo_render_eraseobjects(); - - g_pInput->pollEvents(); - g_pTimer->SpeedThrottle(); - } while(!g_pInput->getPressedAnyKey()); - - map_redraw(); -} - -int VerifyQuit(stCloneKeenPlus *pCKP) -{ -int dlgX,dlgY,dlgW,dlgH; -char *text; - - if (fade.mode==FADE_GO) return NO_QUIT; - - text = getstring("VerifyQuit"); - dlgX = GetStringAttribute("VerifyQuit", "LEFT"); - dlgY = GetStringAttribute("VerifyQuit", "TOP"); - dlgW = GetStringAttribute("VerifyQuit", "WIDTH"); - dlgH = GetStringAttribute("VerifyQuit", "HEIGHT"); - - // either we're trying to save over an existing game, or we're - // loading a game that doesn't exist. - do - { - gamedo_render_drawobjects(pCKP); - gamedo_AnimatedTiles(); - - sb_dialogbox(dlgX, dlgY, dlgW, dlgH); - g_pGraphics->sb_font_draw( (unsigned char*) text, (dlgX+1)<<3, (dlgY+1)<<3); - if (g_pInput->getPressedKey(KQ)) - { - map_redraw(); - QuitState = QUIT_PROGRAM; - return 0; - } - else if (g_pInput->getPressedKey(KT)) - { - map_redraw(); - QuitState = QUIT_TO_TITLE; - return QuitState; - } - else if (g_pInput->getPressedKey(KQUIT)) - { - map_redraw(); - QuitState = NO_QUIT; - return QuitState; - } - - g_pVideoDriver->sb_blit(); - gamedo_render_eraseobjects(); - - g_pInput->pollEvents(); - g_pTimer->SpeedThrottle(); - } while(1); -} - -int endsequence(stCloneKeenPlus *pCKP) -{ - - if (pCKP->Control.levelcontrol.episode==1) - { - if (eseq1_ReturnsToShip(pCKP)) return 0; - if (eseq1_ShipFlys(pCKP)) return 0; - eseq1_BackAtHome(pCKP); - } - else if (pCKP->Control.levelcontrol.episode==2) - { - if (eseq2_HeadsForEarth(pCKP)) return 0; - if (eseq2_LimpsHome(pCKP)) return 0; - if (eseq2_SnowedOutside(pCKP)) return 0; - } - else if (pCKP->Control.levelcontrol.episode==3) - { - if (eseq3_AwardBigV(pCKP)) return 0; - } - - return 0; -} - -void AllPlayersInvisible(void) -{ -int i; - - for(i=0;iControl.levelcontrol); - - if (p_levelcontrol->episode==1) - { - /* episode 1: game is won when all parts are collected */ - - // count the number of parts the players have acquired - partcount = 0; - for(i=0;i= 4) - { - return 1; - } - else return 0; - } - else if (p_levelcontrol->episode==2) - { - /* episode 2: game is won when all cities are saved */ - if (!p_levelcontrol->levels_completed[4]) return 0; - if (!p_levelcontrol->levels_completed[6]) return 0; - if (!p_levelcontrol->levels_completed[7]) return 0; - if (!p_levelcontrol->levels_completed[13]) return 0; - if (!p_levelcontrol->levels_completed[11]) return 0; - if (!p_levelcontrol->levels_completed[9]) return 0; - if (!p_levelcontrol->levels_completed[15]) return 0; - if (!p_levelcontrol->levels_completed[16]) return 0; - return 1; - } - else if (p_levelcontrol->episode==3) - { - /* episode 3: game is won when mortimer is defeated */ - if (p_levelcontrol->levels_completed[16]) - { - return 1; - } - else - { - return 0; - } - } - -return 0; -} - -void usage(void) -{ - printf("Usage: keen [lvlnum] [-*player] [-nopk] [-ep*] [-dtm] [-nocheat] [-rec] -[eseq]
\n"); - printf("lvlnum specify a level number (such as 2) to go directly to that level
"); - printf("-*player select number of players (1-4); defaults to 1
"); - printf("-nopk do not allow players to kill each other in multiplayer games
"); - printf("-game* select game of data base; if not given, start menu is opened
"); - printf("-dtm go directly to the world map, bypassing intro and title screen
"); - printf("-mean increase game difficulty
"); - printf("-cheat enable function key cheat/debug codes
"); - printf("-rec record player actions to demo.dat for making a demo
"); - printf("-eseq for the impatient--cut directly to the ending sequence
"); -#ifdef BUILD_SDL - printf("-fs use fullscreen mode
"); - printf("-dbl zoom image 2x
"); - printf("-ogl hardware acceleration
"); - printf("-showfps show FPS in upper-right of screen
"); -#endif -#ifdef TARGET_WIN32 - printf("
-host & -join for the experimental network play mode. These DON'T work yet.\n"); -#endif - - printf("
"); - printf("Examples:
"); - printf(" keen 3 -ep2 play ep 2, level 3 in 1-player mode
"); - printf(" keen -ep3 -dtm -2player play ep3, skip title&intro, 2-player mode
"); - printf(" keen -ep3 play a normal game of ep3
"); -} - -void radar(void) -{ -unsigned int x,y,o; -unsigned int x1,y1,x2,y2; -unsigned int yoff; - // draw the map - for(y=0;ygetScrollbuffer()[yoff+((4+x+scrollx_buf)&511)] = map.mapdata[x][y]&15; - } - } - - // draw objects - for(o=0;o> CSF >> 4; - y = objects[o].y >> CSF >> 4; - - yoff = ((y+4+scrolly_buf)&511)<<9; - g_pGraphics->getScrollbuffer()[yoff+((4+x+scrollx_buf)&511)] = objects[o].type&15; - } - } - - // draw the area that is visible in the scrollbuffer - x1 = mapx; y1 = mapy; - x2 = x1+32; y2 = y1+32; - for(y=y1;ygetScrollbuffer()[yoff+((4+x1+scrollx_buf)&511)] = 10; - if (x2getScrollbuffer()[yoff+((4+x2+scrollx_buf)&511)] = 10; - } - } - for(x=x1;x<=x2;x++) - { - if (y1 < map.ysize && x < map.xsize) - { - yoff = ((y1+4+scrolly_buf)&511)<<9; - g_pGraphics->getScrollbuffer()[yoff+((4+x+scrollx_buf)&511)] = 10; - } - if (y2 < map.ysize && x < map.xsize) - { - yoff = ((y2+4+scrolly_buf)&511)<<9; - g_pGraphics->getScrollbuffer()[yoff+((4+x+scrollx_buf)&511)] = 10; - } - } - - // draw the area that is visible on the screen - // 320x200 = 20x12.5 tiles - x1 = scroll_x>>4; y1 = scroll_y>>4; - x2 = x1+20; y2 = y1+12; - for(y=y1;ygetScrollbuffer()[yoff+((4+x1+scrollx_buf)&511)] = 12; - if (x2getScrollbuffer()[yoff+((4+x2+scrollx_buf)&511)] = 12; - } - } - for(x=x1;x<=x2;x++) - { - if (x < map.xsize) - { - if (y1 < map.ysize) - { - yoff = ((y1+4+scrolly_buf)&511)<<9; - g_pGraphics->getScrollbuffer()[yoff+((4+x+scrollx_buf)&511)] = 12; - } - if (y2 < map.ysize) - { - yoff = ((y2+4+scrolly_buf)&511)<<9; - g_pGraphics->getScrollbuffer()[yoff+((4+x+scrollx_buf)&511)] = 12; - } - } - } -} - -void SetAllCanSupportPlayer(int o, int state) -{ - unsigned int i; - for(i=0;idrawFont((unsigned char*) text[i], (dlgX+1)<<3, (dlgY+1+i)<<3,0); - } - - twirlframe = 0; - twirltimer = TWIRL_SPEED+1; - - g_pInput->flushAll(); - - // wait for enter - do - { - if (twirltimer>TWIRL_SPEED) - { - g_pGraphics->drawCharacter((dlgX+twirlX)<<3, (dlgY+twirlY)<<3, 9+twirlframe); - g_pVideoDriver->update_screen(); - twirlframe++; - if (twirlframe>5) twirlframe=0; - twirltimer=0; - } else twirltimer++; - g_pInput->pollEvents(); - g_pTimer->SpeedThrottle(); - g_pVideoDriver->update_screen(); - } while(!g_pInput->getPressedKey(KENTER)); -} +/* MISC.C + All KINDS of assorted crap :) Has most of the in-game dialog boxes + such as the status box etc. + + Also like I said there's all kinds of assorted crap in here. + That's why it's called "misc.c" (get it? :)) +*/ + +#include "keen.h" +#ifdef BUILD_SDL +#include +#include "sdl/joydrv.h" +#include "sdl/CInput.h" +#include "sdl/CTimer.h" +#include "sdl/CVideoDriver.h" +#include "sdl/sound/CSound.h" +#endif + +#include "include/misc.h" +#include "include/game.h" +#include "include/eseq_ep1.h" +#include "include/eseq_ep2.h" +#include "include/eseq_ep3.h" +#include "include/gamedo.h" +#include "CLogFile.h" +#include "CGraphics.h" +#include "StringUtils.h" + +void banner(void) +{ +char buf[80]; + + sprintf(buf, "%s *Unknown* build check banner()", REVISION); + #ifdef TARGET_WIN32 + sprintf(buf, "%s Windows build", REVISION); + #endif + #ifdef TARGET_LNX + sprintf(buf, "%s Linux build", REVISION); + #endif + printf("%s", buf); + printf(" (%d bit)", static_cast (sizeof(int*)*8)); + + 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"); + printf("\n"); +} + +void cleanup(stCloneKeenPlus *CKP) +{ + if(CKP->GameData){ delete[] CKP->GameData; CKP->GameData = NULL; } + + g_pLogFile->ftextOut(BLACK,true," Freed %d strings.
", freestrings()); + + JoyDrv_Stop(&(CKP->Joystick)); + g_pLogFile->textOut(BLACK,true," Joystick driver shut down.
"); + g_pSound->stopAllSounds(); + g_pSound->destroy(); + g_pLogFile->textOut(BLACK,true," Sound driver shut down.
"); + + #ifdef NETWORK_PLAY + if (is_server) + { + NetDrv_Server_Stop(); + g_pLogFile->ftextOut(" * Network (server) shut down.
"); + } + if (is_client) + { + NetDrv_Client_Stop(); + g_pLogFile->ftextOut(" * Network (client) shut down.
"); + } + #endif + + if (demofile) + { + fclose(demofile); + g_pLogFile->ftextOut(BLACK,true," Demo file closed.
"); + } + + g_pGraphics->stopGraphics(); + g_pLogFile->ftextOut(BLACK,true," Graphics driver shut down.
"); + + g_pGraphics->freemem(); + + g_pLogFile->ftextOut("
"); +} + +// draw an empty dialog box, for youseeinyourmind(), etc. +void dialogbox(int x1, int y1, int w, int h) +{ +int x,y,i,j; + + g_pGraphics->drawCharacter(x1*8, y1*8, 1); + g_pGraphics->drawCharacter((x1+w)*8, y1*8, 3); + for(x=(x1*8)+8,i=0;idrawCharacter(x, y1*8, 2); + x+=8; + } + y=(y1+1)*8; + for(j=0;jdrawCharacter(x, y, 4); + else if (i==w) g_pGraphics->drawCharacter(x, y, 5); + else g_pGraphics->drawCharacter(x, y, ' '); + x+=8; + } + y+=8; + } + for(x=(x1*8),i=0;i<=w;i++) + { + if (i==0) g_pGraphics->drawCharacter(x, y, 6); + else if (i==w) g_pGraphics->drawCharacter(x, y, 8); + else g_pGraphics->drawCharacter(x, y, 7); + x+=8; + } +} +// draw an empty dialog box, for youseeinyourmind(), etc. +void sb_dialogbox(int x1, int y1, int w, int h) +{ + int x,y,i,j; + + g_pGraphics->sb_drawCharacter(x1*8, y1*8, 1); + g_pGraphics->sb_drawCharacter((x1+w)*8, y1*8, 3); + for(x=(x1*8)+8,i=0;isb_drawCharacter(x, y1*8, 2); + x+=8; + } + y=(y1+1)*8; + for(j=0;jsb_drawCharacter(x, y, 4); + else if (i==w) g_pGraphics->sb_drawCharacter(x, y, 5); + else g_pGraphics->sb_drawCharacter(x, y, ' '); + x+=8; + } + y+=8; + } + for(x=(x1*8),i=0;i<=w;i++) + { + if (i==0) g_pGraphics->sb_drawCharacter(x, y, 6); + else if (i==w) g_pGraphics->sb_drawCharacter(x, y, 8); + else g_pGraphics->sb_drawCharacter(x, y, 7); + x+=8; + } +} + +#define YORPSTATUEHEADUSED 485 +void youseeinyourmind(int mpx, int mpy, stCloneKeenPlus *pCKP) +{ +int twirlframe, twirltimer; +char strname[80]; +int dlgX,dlgY,dlgW,dlgH,twirlX,twirlY; + +bool isgarg; + +int i; + + isgarg = false; + if(map.mapdata[mpx][mpy] >= 435 && map.mapdata[mpx][mpy] <= 438) + isgarg = true; + + if (!isgarg) + { + if(!map_isanimated(mpx, mpy)) + return; + } + else + { // it's a garg statue + if(!map_isanimated(mpx, mpy)) + return; + } + + for(i=0; i < 4 ; i++) + { + player[0].playcontrol[PA_JUMP+i] = 0; + } + + 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); + + dlgX = GetStringAttribute(strname, "LEFT"); + dlgY = GetStringAttribute(strname, "TOP"); + dlgW = GetStringAttribute(strname, "WIDTH"); + dlgH = GetStringAttribute(strname, "HEIGHT"); + twirlX = GetStringAttribute(strname, "TWIRLX"); + twirlY = GetStringAttribute(strname, "TWIRLY"); + + dialogbox(dlgX,dlgY,dlgW,dlgH); + g_pGraphics->drawFont(getstring(strname), (dlgX+1)<<3, (dlgY+1)<<3,0); + + twirlframe = 0; + twirltimer = twirl_speed+1; + // wait for enter + do + { + if (twirltimer>twirl_speed) + { + g_pGraphics->drawCharacter((dlgX+twirlX)<<3, (dlgY+twirlY)<<3, 9+twirlframe); + g_pVideoDriver->update_screen(); + twirlframe++; + if (twirlframe>5) twirlframe=0; + twirltimer=0; + } else twirltimer++; + g_pInput->pollEvents(); + g_pTimer->SpeedThrottle(); + g_pVideoDriver->update_screen(); + } while(!g_pInput->getPressedKey(KENTER) /*&& !immediate_keytable[KQUIT] && !getanyevent(pCKP)*/); + + // make the statue head stop glowing + if (!isgarg) + { + map_chgtile(mpx, mpy, YORPSTATUEHEADUSED); + map_deanimate(mpx, mpy); + } + else + { // it's a garg statue + + map_chgtile(mpx, mpy, 434); + map_deanimate(mpx, mpy); + } +} + +void VorticonElder(int mpx, int mpy, stCloneKeenPlus *pCKP) +{ + int twirlframe, twirltimer; + int dlgX,dlgY,dlgW,dlgH,twirlX,twirlY; + const char *strName; + const int twirl_speed = 100; + + for(int i=0; i < 4 ; i++) + { + player[0].playcontrol[PA_JUMP+i] = 0; + } + + g_pSound->pauseSound(); + + switch(pCKP->Control.levelcontrol.curlevel) + { + case 8: + strName = "EP2_VE_NOJUMPINDARK"; + break; + case 10: + strName = "EP2_VE_EVILBELTS"; + break; + + default: + crashflag = 1; + why_term_ptr = "VE box: Illegal level #."; + break; + } + + dlgX = GetStringAttribute(strName, "LEFT"); + dlgY = GetStringAttribute(strName, "TOP"); + dlgW = GetStringAttribute(strName, "WIDTH"); + dlgH = GetStringAttribute(strName, "HEIGHT"); + twirlX = GetStringAttribute(strName, "TWIRLX"); + twirlY = GetStringAttribute(strName, "TWIRLY"); + + dialogbox(dlgX, dlgY, dlgW, dlgH); + g_pGraphics->drawFont( getstring(strName), (dlgX+1)<<3, (dlgY+1)<<3,0); + + twirlframe = 0; + twirltimer = twirl_speed+1; + // wait for enter + do + { + if (twirltimer>twirl_speed) + { + g_pGraphics->drawCharacter((dlgX+twirlX)<<3, (dlgY+twirlY)<<3, 9+twirlframe); + g_pVideoDriver->update_screen(); + twirlframe++; + if (twirlframe>5) twirlframe=0; + twirltimer=0; + } else twirltimer++; + g_pInput->pollEvents(); + g_pTimer->SpeedThrottle(); + g_pVideoDriver->update_screen(); + } while(!g_pInput->getPressedKey(KENTER) ); + + // make the switch stop glowing + map_chgtile(mpx, mpy+1, 432); + + map_deanimate(mpx, mpy+1); + + g_pSound->resumeSounds(); +} + + +void inventory_draw_ep1(int p) +{ +int x,t,i,j; + std::string tempbuf; +int dlgX,dlgY,dlgW,dlgH; + + dlgX = GetStringAttribute("EP1_StatusBox", "LEFT"); + dlgY = GetStringAttribute("EP1_StatusBox", "TOP"); + dlgW = GetStringAttribute("EP1_StatusBox", "WIDTH"); + dlgH = GetStringAttribute("EP1_StatusBox", "HEIGHT"); + + dialogbox(dlgX,dlgY,dlgW,dlgH); + g_pGraphics->drawFont( getstring("EP1_StatusBox"), (dlgX+1)<<3, (dlgY+1)<<3, 0); + +// fill in what we have + // 321: joystick/battery/vacuum/fuel not gotten + // 414: raygun, 415, pogo + // 424: yellow/red/green/blue cards + // 448: ship parts, gotten + // raygun icon + g_pGraphics->drawTile_direct((dlgX+4)<<3, ((dlgY+8)<<3)+3, 414); + // 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.HasCardYellow > 1) + { + std::string buf = itoa(player[p].inventory.HasCardYellow); + g_pGraphics->drawFont(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) + { + std::string buf = itoa(player[p].inventory.HasCardRed); + g_pGraphics->drawFont(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) + { + std::string buf = itoa(player[p].inventory.HasCardGreen); + g_pGraphics->drawFont(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) + { + std::string buf = itoa(player[p].inventory.HasCardBlue); + g_pGraphics->drawFont(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); + if (player[p].inventory.HasBattery) t=449; else t=322; + g_pGraphics->drawTile_direct((dlgX+21)<<3, ((dlgY+4)<<3)+3, t); + if (player[p].inventory.HasVacuum) t=450; else t=323; + g_pGraphics->drawTile_direct((dlgX+24)<<3, ((dlgY+4)<<3)+3, t); + if (player[p].inventory.HasFuel) t=451; else t=324; + g_pGraphics->drawTile_direct((dlgX+27)<<3, ((dlgY+4)<<3)+3, t); + // ray gun charges + i = player[p].inventory.charges; + if (i>999) i=999; + tempbuf = itoa(i); + g_pGraphics->drawFont( tempbuf, (dlgX+4)<<3, (dlgY+12)<<3, 0); + + // score + i = player[p].inventory.score; + tempbuf = itoa(i); + g_pGraphics->drawFont( tempbuf, (dlgX+12-tempbuf.size())<<3, (dlgY+2)<<3, 0); + // extra life at + i = player[p].inventory.extralifeat; + tempbuf = itoa(i); + g_pGraphics->drawFont( tempbuf, (dlgX+28-tempbuf.size())<<3, (dlgY+2)<<3, 0); + // lives + i = player[p].inventory.lives; + x = ((dlgX+1)<<3)+4; + if (i>7) i=7; + for(j=0;jdrawSprite_direct(x, (dlgY+4)<<3, playerbaseframes[p]); + x += sprites[0].xsize; + } +} + +void inventory_draw_ep2(int p, stCloneKeenPlus *pCKP) +{ +int x,/*y,t,*/i,j; + std::string tempbuf; +int dlgX,dlgY,dlgW,dlgH; + + stLevelControl *p_levelcontrol; + + p_levelcontrol = &(pCKP->Control.levelcontrol); + + dlgX = GetStringAttribute("EP2_StatusBox", "LEFT"); + dlgY = GetStringAttribute("EP2_StatusBox", "TOP"); + dlgW = GetStringAttribute("EP2_StatusBox", "WIDTH"); + dlgH = GetStringAttribute("EP2_StatusBox", "HEIGHT"); + + dialogbox(dlgX,dlgY,dlgW,dlgH); + g_pGraphics->drawFont( 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.HasCardYellow > 1) + { + std::string buf = itoa(player[p].inventory.HasCardYellow); + g_pGraphics->drawFont(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) + { + std::string buf = itoa(player[p].inventory.HasCardRed); + g_pGraphics->drawFont(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) + { + std::string buf = itoa(player[p].inventory.HasCardGreen); + g_pGraphics->drawFont(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) + { + std::string buf = itoa(player[p].inventory.HasCardBlue); + g_pGraphics->drawFont(buf,(dlgX+24)<<3,((dlgY+10)<<3)+3,0); + } + } + // cities saved + if (p_levelcontrol->levels_completed[4]) g_pGraphics->drawFont( getstring("EP2_LVL4_TargetName"), (dlgX+1)<<3, (dlgY+8)<<3, 0); + if (p_levelcontrol->levels_completed[6]) g_pGraphics->drawFont( getstring("EP2_LVL6_TargetName"), (dlgX+8)<<3, (dlgY+8)<<3, 0); + if (p_levelcontrol->levels_completed[7]) g_pGraphics->drawFont( getstring("EP2_LVL7_TargetName"), (dlgX+1)<<3, (dlgY+9)<<3, 0); + if (p_levelcontrol->levels_completed[13]) g_pGraphics->drawFont( getstring("EP2_LVL13_TargetName"), (dlgX+8)<<3, (dlgY+9)<<3, 0); + if (p_levelcontrol->levels_completed[11]) g_pGraphics->drawFont( getstring("EP2_LVL11_TargetName"), (dlgX+1)<<3, (dlgY+10)<<3, 0); + if (p_levelcontrol->levels_completed[9]) g_pGraphics->drawFont( getstring("EP2_LVL9_TargetName"), (dlgX+8)<<3, (dlgY+10)<<3, 0); + if (p_levelcontrol->levels_completed[15]) g_pGraphics->drawFont( getstring("EP2_LVL15_TargetName"), (dlgX+1)<<3, (dlgY+11)<<3, 0); + if (p_levelcontrol->levels_completed[16]) g_pGraphics->drawFont( getstring("EP2_LVL16_TargetName"), (dlgX+8)<<3, (dlgY+11)<<3, 0); + + // raygun icon + g_pGraphics->drawTile_direct((dlgX+20)<<3, ((dlgY+5)<<3)-5, 414); + + // ray gun charges text + i = player[p].inventory.charges; + if (i>999) i=999; + tempbuf = itoa(i); + g_pGraphics->drawFont( tempbuf, (dlgX+27-tempbuf.size())<<3, ((dlgY+5)<<3)-1, 0); + + // score + i = player[p].inventory.score; + tempbuf = itoa(i); + g_pGraphics->drawFont( tempbuf, (dlgX+12-tempbuf.size())<<3, (dlgY+2)<<3, 0); + // extra life at + i = player[p].inventory.extralifeat; + tempbuf = itoa(i); + g_pGraphics->drawFont( tempbuf, (dlgX+28-tempbuf.size())<<3, (dlgY+2)<<3, 0); + // lives + i = player[p].inventory.lives; + x = ((dlgX + 1)<<3)+4; + if (i>7) i=7; + for(j=0;jdrawSprite_direct(x, (dlgY+4)<<3, playerbaseframes[p]); + x += sprites[0].xsize; + } + +} + +void inventory_draw_ep3(int p) +{ +//int x,y,t,i,j; +int i,j,x; +int ankhtimepercent; + std::string tempbuf; +int dlgX,dlgY,dlgW,dlgH; + + dlgX = GetStringAttribute("EP3_StatusBox", "LEFT"); + dlgY = GetStringAttribute("EP3_StatusBox", "TOP"); + dlgW = GetStringAttribute("EP3_StatusBox", "WIDTH"); + dlgH = GetStringAttribute("EP3_StatusBox", "HEIGHT"); + + dialogbox(dlgX,dlgY,dlgW,dlgH); + g_pGraphics->drawFont( getstring("EP3_StatusBox"), (dlgX+1)<<3, (dlgY+1)<<3, 0); + + // calculate % ankh time left + ankhtimepercent = (int)((float)player[p].ankhtime / (PLAY_ANKH_TIME/100)); + // ankh time + g_pGraphics->drawTile_direct((dlgX+4)<<3, ((dlgY+8)<<3)+3, 214); + tempbuf = itoa(ankhtimepercent); + g_pGraphics->drawFont( tempbuf, (dlgX+8)<<3, ((dlgY+8)<<3)+7, 0); + + // raygun icon + g_pGraphics->drawTile_direct((dlgX+23)<<3, ((dlgY+5)<<3)-5, 216); + + // ray gun charges text + i = player[p].inventory.charges; + if (i>999) i=999; + tempbuf = itoa(i); + g_pGraphics->drawFont( 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.HasCardYellow > 1) + { + std::string buf = itoa(player[p].inventory.HasCardYellow); + g_pGraphics->drawFont(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) + { + std::string buf = itoa(player[p].inventory.HasCardRed); + g_pGraphics->drawFont(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) + { + std::string buf = itoa(player[p].inventory.HasCardGreen); + g_pGraphics->drawFont(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) + { + std::string buf = itoa(player[p].inventory.HasCardBlue); + g_pGraphics->drawFont(buf,(dlgX+25)<<3,((dlgY+8)<<3)+3,0); + } + } + + // score + i = player[p].inventory.score; + tempbuf = itoa(i); + g_pGraphics->drawFont( tempbuf, (dlgX+12-tempbuf.size())<<3, (dlgY+2)<<3, 0); + // extra life at + i = player[p].inventory.extralifeat; + tempbuf = itoa(i); + g_pGraphics->drawFont( tempbuf, (dlgX+28-tempbuf.size())<<3, (dlgY+2)<<3, 0); + // lives + i = player[p].inventory.lives; + x = ((dlgX+1)<<3)+4; + if (i>9) i=9; + for(j=0;jdrawSprite_direct(x, (dlgY+4)<<3, playerbaseframes[p]); + x += sprites[0].xsize; + } +} + +void showinventory(int p, stCloneKeenPlus *pCKP) +{ +//int x,y,t,i,j; +//char tempbuf[40]; + unsigned short i; + + stLevelControl *p_levelcontrol; + p_levelcontrol = &(pCKP->Control.levelcontrol); + + // draw the episode-specific stuff + if (p_levelcontrol->episode==1) + { + inventory_draw_ep1(p); + } + else if (p_levelcontrol->episode==2) + { + inventory_draw_ep2(p, pCKP); + } + else if (p_levelcontrol->episode==3) + { + inventory_draw_ep3(p); + } + + + g_pVideoDriver->update_screen(); + + // wait for any button pressed or any action triggered + bool close=false; + + while(!close) + { + g_pInput->pollEvents(); + + for(i=0 ; igetPressedCommand(i)) + close=true; + } + + for(i=0 ; igetPressedKey(i)) + close=true; + } + } +} + +/*void sshot(char *visiblefile, char *scrollfile) +{ +FILE *fp; +int x,y; + + fp = fopen(visiblefile, "wb"); + if (!fp) return;< + + for(y=0;y<200;y++) + for(x=0;x<320;x++) + fputc(getpixel(x,y), fp); + + fclose(fp); + + fp = fopen(scrollfile, "wb"); + if (!fp) return; + + for(y=0;y<512;y++) + for(x=0;x<512;x++) + fputc(sb_getpixel(x,y), fp); + + fclose(fp); +}*/ + +void YourShipNeedsTheseParts(stCloneKeenPlus *pCKP) +{ +int cp = 0; +int dlgX,dlgY,dlgW,dlgH; + + dlgX = GetStringAttribute("EP1_SHIP", "LEFT"); + dlgY = GetStringAttribute("EP1_SHIP", "TOP"); + dlgW = GetStringAttribute("EP1_SHIP", "WIDTH"); + dlgH = GetStringAttribute("EP1_SHIP", "HEIGHT"); + + dialogbox(dlgX,dlgY,dlgW,dlgH); + + g_pGraphics->drawFont( getstring("EP1_SHIP"), (dlgX+1)<<3, (dlgY+1)<<3,0); + + // draw needed parts + if (!player[cp].inventory.HasJoystick) + g_pGraphics->drawTile_direct((dlgX+9)<<3, (dlgY+3)<<3, 448); + + if (!player[cp].inventory.HasBattery) + g_pGraphics->drawTile_direct((dlgX+12)<<3, (dlgY+3)<<3, 449); + + if (!player[cp].inventory.HasVacuum) + g_pGraphics->drawTile_direct((dlgX+15)<<3, (dlgY+3)<<3, 450); + + if (!player[cp].inventory.HasFuel) + g_pGraphics->drawTile_direct((dlgX+18)<<3, (dlgY+3)<<3, 451); + + g_pVideoDriver->update_screen(); + + // wait for any key! + g_pInput->flushKeys(); + while(!g_pInput->getPressedAnyKey()) + { + g_pInput->pollEvents(); + + if(g_pInput->getPressedAnyCommand()) + break; + } +} + +void ShipEp3(stCloneKeenPlus *pCKP) +{ +char strname[80]; +int twirlframe, twirltimer; +int dlgX,dlgY,dlgW,dlgH,twirlX,twirlY; +const int twirlspeed = 100; + + // display one of four random strings + sprintf(strname, "EP3_SHIP%d", (rand()%4)+1); + + dlgX = GetStringAttribute(strname, "LEFT"); + dlgY = GetStringAttribute(strname, "TOP"); + dlgW = GetStringAttribute(strname, "WIDTH"); + dlgH = GetStringAttribute(strname, "HEIGHT"); + twirlX = GetStringAttribute(strname, "TWIRLX"); + twirlY = GetStringAttribute(strname, "TWIRLY"); + + dialogbox(dlgX,dlgY,dlgW,dlgH); + g_pGraphics->drawFont( getstring(strname), (dlgX+1)<<3, (dlgY+1)<<3,0); + + g_pVideoDriver->update_screen(); + + g_pInput->flushAll(); + + twirlframe = 0; + twirltimer = twirlspeed+1; + g_pInput->flushKeys(); + // wait for any command or key + do + { + if (twirltimer>twirlspeed) + { + g_pGraphics->drawCharacter((dlgX+twirlX)<<3, (dlgY+twirlY)<<3, twirlframe+9); + g_pVideoDriver->update_screen(); + twirlframe++; + if (twirlframe>5) twirlframe=0; + twirltimer=0; + } else twirltimer++; + if(g_pInput->getPressedAnyCommand()) break; + g_pInput->pollEvents(); + g_pTimer->SpeedThrottle(); + } while(!g_pInput->getPressedAnyKey()); +} + +void game_save(char *fname, stCloneKeenPlus *pCKP) +{ + unsigned int i; + FILE *fp; + + fp = fopen(fname, "wb"); + + // save the header/version check + fputc('S', fp); + fputc(SAVEGAMEVERSION, fp); + + // save all necessary structures to the file + if (map.isworldmap) fputc('W', fp); else fputc('L', fp); + + sgrle_compress(fp, (unsigned char *)&numplayers, sizeof(numplayers)); + sgrle_compress(fp, (unsigned char *)&(pCKP->Control.levelcontrol), sizeof(pCKP->Control.levelcontrol)); + sgrle_compress(fp, (unsigned char *)&scroll_x, sizeof(scroll_x)); + sgrle_compress(fp, (unsigned char *)&scroll_y, sizeof(scroll_y)); + sgrle_compress(fp, (unsigned char *)&max_scroll_x, sizeof(max_scroll_x)); + sgrle_compress(fp, (unsigned char *)&max_scroll_y, sizeof(max_scroll_y)); + sgrle_compress(fp, (unsigned char *)&map, sizeof(map)); + for(i=0;iControl.levelcontrol); + + fp = fopen(fname, "rb"); + if (!fp) return 1; + + // do the header and version check + if (fgetc(fp) != 'S') { fclose(fp); return 1; } + if (fgetc(fp) != SAVEGAMEVERSION) { fclose(fp); return 1; } + fgetc(fp); // iswm flag--not needed here + + // load all structures from the file + sgrle_reset(); + sgrle_decompress(fp, (unsigned char *)&numplayers, sizeof(numplayers)); + sgrle_decompress(fp, (unsigned char *) p_levelcontrol , sizeof(*p_levelcontrol)); + sgrle_decompress(fp, (unsigned char *)&scrx, sizeof(scrx)); + sgrle_decompress(fp, (unsigned char *)&scry, sizeof(scry)); + sgrle_decompress(fp, (unsigned char *)&max_scroll_x, sizeof(max_scroll_x)); + sgrle_decompress(fp, (unsigned char *)&max_scroll_y, sizeof(max_scroll_y)); + sgrle_decompress(fp, (unsigned char *)&map, sizeof(map)); + + initgame(pCKP); // reset scroll + drawmap(); + for(i=0;iControl.levelcontrol); + +top: ; + if (issave) + { + dlgX = GetStringAttribute("WhichSlotSave", "LEFT"); + dlgY = GetStringAttribute("WhichSlotSave", "TOP"); + dlgW = GetStringAttribute("WhichSlotSave", "WIDTH"); + dlgH = GetStringAttribute("WhichSlotSave", "HEIGHT"); + } + else + { + dlgX = GetStringAttribute("WhichSlotLoad", "LEFT"); + dlgY = GetStringAttribute("WhichSlotLoad", "TOP"); + dlgW = GetStringAttribute("WhichSlotLoad", "WIDTH"); + dlgH = GetStringAttribute("WhichSlotLoad", "HEIGHT"); + map_redraw(); + bmnum = g_pGraphics->getBitmapNumberFromName("TITLE"); + x = (320/2)-(bitmaps[bmnum].xsize/2); + g_pGraphics->drawBitmap(x, 0, bmnum); + } + + saveslot = 0; + do + { + + gamedo_render_drawobjects(pCKP); + + sb_dialogbox(dlgX,dlgY,dlgW,dlgH); + if (issave) + { + g_pGraphics->sb_font_draw( getstring("WhichSlotSave"),(dlgX+1)<<3,(dlgY+1)<<3); + } + else + { + g_pGraphics->sb_font_draw( getstring("WhichSlotLoad"),(dlgX+1)<<3,(dlgY+1)<<3); + gamedo_AnimatedTiles(); + } + + for (int i=0 ; i<9 ; i++) + { + if (g_pInput->getPressedKey(KNUM1+i)) saveslot = 1+i; + } + + g_pVideoDriver->sb_blit(); + gamedo_render_eraseobjects(); + + + g_pInput->pollEvents(); + g_pTimer->SpeedThrottle(); + } while(!g_pInput->getPressedKey(KQUIT) && !saveslot); + + /* check if the selected save file exists */ + fname = "ep"; + fname += p_levelcontrol->episode+'0'; + fname += "save"; + fname += saveslot+'0'; + fname += ".dat"; + slotexists = 0; + fp = fopen(fname.c_str(), "rb"); + if (fp) + { + fclose(fp); + slotexists = 1; + } + + if ((issave && !slotexists) || (!issave && slotexists)) + { + map_redraw(); + return saveslot; + } + + if (issave) + { + dlgX = GetStringAttribute("SaveSlotOverwrite", "LEFT"); + dlgY = GetStringAttribute("SaveSlotOverwrite", "TOP"); + dlgW = GetStringAttribute("SaveSlotOverwrite", "WIDTH"); + dlgH = GetStringAttribute("SaveSlotOverwrite", "HEIGHT"); + } + else + { + dlgX = GetStringAttribute("LoadNoSuchSlot", "LEFT"); + dlgY = GetStringAttribute("LoadNoSuchSlot", "TOP"); + dlgW = GetStringAttribute("LoadNoSuchSlot", "WIDTH"); + dlgH = GetStringAttribute("LoadNoSuchSlot", "HEIGHT"); + } + + // either we're trying to save over an existing game, or we're + // loading a game that doesn't exist. + do + { + + gamedo_render_drawobjects(pCKP); + + sb_dialogbox(dlgX,dlgY,dlgW,dlgH); + if (issave) + { + g_pGraphics->sb_font_draw( getstring("SaveSlotOverwrite"),(dlgX+1)<<3,(dlgY+1)<<3); + if (g_pInput->getPressedKey(KN)) + { + map_redraw(); + goto top; + } + else if (g_pInput->getPressedKey(KY)) + { + map_redraw(); + return saveslot; + } + } + else + { + g_pGraphics->sb_font_draw( getstring("LoadNoSuchSlot"),(dlgX+1)<<3,(dlgY+1)<<3); + + if (g_pInput->getPressedAnyKey()) + { + map_redraw(); + goto top; + } + + gamedo_AnimatedTiles(); + } + + g_pVideoDriver->sb_blit(); + gamedo_render_eraseobjects(); + + g_pInput->pollEvents(); + g_pTimer->SpeedThrottle(); + } while(!g_pInput->getPressedKey(KQUIT)); + + map_redraw(); + return 0; +} + +void game_save_interface(stCloneKeenPlus *pCKP) +{ +int waittimer; +char fname[40]; +char saveslot; +int dlgX,dlgY,dlgW,dlgH; + + dlgX = GetStringAttribute("GameSaveSuccess", "LEFT"); + dlgY = GetStringAttribute("GameSaveSuccess", "TOP"); + dlgW = GetStringAttribute("GameSaveSuccess", "WIDTH"); + dlgH = GetStringAttribute("GameSaveSuccess", "HEIGHT"); + + saveslot = save_slot_box(1, pCKP); + if (!saveslot) return; // canceled + + /* save the game */ + sprintf(fname, "ep%csave%c.dat", pCKP->Control.levelcontrol.episode+'0', saveslot+'0'); + game_save(fname,pCKP); + + /* display the "your game has been saved" box */ + waittimer = 0; + do + { + waittimer++; + if (waittimer > 5000) break; + + gamedo_render_drawobjects(pCKP); + + sb_dialogbox(dlgX,dlgY,dlgW,dlgH); + g_pGraphics->sb_font_draw( getstring("GameSaveSuccess"),(dlgX+1)<<3,(dlgY+1)<<3); + + g_pVideoDriver->sb_blit(); + gamedo_render_eraseobjects(); + + g_pInput->pollEvents(); + g_pTimer->SpeedThrottle(); + } while(!g_pInput->getPressedAnyKey()); + + map_redraw(); +} + +int VerifyQuit(stCloneKeenPlus *pCKP) +{ +int dlgX,dlgY,dlgW,dlgH; + std::string text; + + if (fade.mode==FADE_GO) return NO_QUIT; + + text = getstring("VerifyQuit"); + dlgX = GetStringAttribute("VerifyQuit", "LEFT"); + dlgY = GetStringAttribute("VerifyQuit", "TOP"); + dlgW = GetStringAttribute("VerifyQuit", "WIDTH"); + dlgH = GetStringAttribute("VerifyQuit", "HEIGHT"); + + // either we're trying to save over an existing game, or we're + // loading a game that doesn't exist. + do + { + gamedo_render_drawobjects(pCKP); + gamedo_AnimatedTiles(); + + sb_dialogbox(dlgX, dlgY, dlgW, dlgH); + g_pGraphics->sb_font_draw( text, (dlgX+1)<<3, (dlgY+1)<<3); + if (g_pInput->getPressedKey(KQ)) + { + map_redraw(); + QuitState = QUIT_PROGRAM; + return 0; + } + else if (g_pInput->getPressedKey(KT)) + { + map_redraw(); + QuitState = QUIT_TO_TITLE; + return QuitState; + } + else if (g_pInput->getPressedKey(KQUIT)) + { + map_redraw(); + QuitState = NO_QUIT; + return QuitState; + } + + g_pVideoDriver->sb_blit(); + gamedo_render_eraseobjects(); + + g_pInput->pollEvents(); + g_pTimer->SpeedThrottle(); + } while(1); +} + +int endsequence(stCloneKeenPlus *pCKP) +{ + + if (pCKP->Control.levelcontrol.episode==1) + { + if (eseq1_ReturnsToShip(pCKP)) return 0; + if (eseq1_ShipFlys(pCKP)) return 0; + eseq1_BackAtHome(pCKP); + } + else if (pCKP->Control.levelcontrol.episode==2) + { + if (eseq2_HeadsForEarth(pCKP)) return 0; + if (eseq2_LimpsHome(pCKP)) return 0; + if (eseq2_SnowedOutside(pCKP)) return 0; + } + else if (pCKP->Control.levelcontrol.episode==3) + { + if (eseq3_AwardBigV(pCKP)) return 0; + } + + return 0; +} + +void AllPlayersInvisible(void) +{ +int i; + + for(i=0;iControl.levelcontrol); + + if (p_levelcontrol->episode==1) + { + /* episode 1: game is won when all parts are collected */ + + // count the number of parts the players have acquired + partcount = 0; + for(i=0;i= 4) + { + return 1; + } + else return 0; + } + else if (p_levelcontrol->episode==2) + { + /* episode 2: game is won when all cities are saved */ + if (!p_levelcontrol->levels_completed[4]) return 0; + if (!p_levelcontrol->levels_completed[6]) return 0; + if (!p_levelcontrol->levels_completed[7]) return 0; + if (!p_levelcontrol->levels_completed[13]) return 0; + if (!p_levelcontrol->levels_completed[11]) return 0; + if (!p_levelcontrol->levels_completed[9]) return 0; + if (!p_levelcontrol->levels_completed[15]) return 0; + if (!p_levelcontrol->levels_completed[16]) return 0; + return 1; + } + else if (p_levelcontrol->episode==3) + { + /* episode 3: game is won when mortimer is defeated */ + if (p_levelcontrol->levels_completed[16]) + { + return 1; + } + else + { + return 0; + } + } + +return 0; +} + +void usage(void) +{ + printf("Usage: keen [lvlnum] [-*player] [-nopk] [-ep*] [-dtm] [-nocheat] [-rec] -[eseq]
\n"); + printf("lvlnum specify a level number (such as 2) to go directly to that level
"); + printf("-*player select number of players (1-4); defaults to 1
"); + printf("-nopk do not allow players to kill each other in multiplayer games
"); + printf("-game* select game of data base; if not given, start menu is opened
"); + printf("-dtm go directly to the world map, bypassing intro and title screen
"); + printf("-mean increase game difficulty
"); + printf("-cheat enable function key cheat/debug codes
"); + printf("-rec record player actions to demo.dat for making a demo
"); + printf("-eseq for the impatient--cut directly to the ending sequence
"); +#ifdef BUILD_SDL + printf("-fs use fullscreen mode
"); + printf("-dbl zoom image 2x
"); + printf("-ogl hardware acceleration
"); + printf("-showfps show FPS in upper-right of screen
"); +#endif +#ifdef TARGET_WIN32 + printf("
-host & -join for the experimental network play mode. These DON'T work yet.\n"); +#endif + + printf("
"); + printf("Examples:
"); + printf(" keen 3 -ep2 play ep 2, level 3 in 1-player mode
"); + printf(" keen -ep3 -dtm -2player play ep3, skip title&intro, 2-player mode
"); + printf(" keen -ep3 play a normal game of ep3
"); +} + +void radar(void) +{ +unsigned int x,y,o; +unsigned int x1,y1,x2,y2; +unsigned int yoff; + // draw the map + for(y=0;ygetScrollbuffer()[yoff+((4+x+scrollx_buf)&511)] = map.mapdata[x][y]&15; + } + } + + // draw objects + for(o=0;o> CSF >> 4; + y = objects[o].y >> CSF >> 4; + + yoff = ((y+4+scrolly_buf)&511)<<9; + g_pGraphics->getScrollbuffer()[yoff+((4+x+scrollx_buf)&511)] = objects[o].type&15; + } + } + + // draw the area that is visible in the scrollbuffer + x1 = mapx; y1 = mapy; + x2 = x1+32; y2 = y1+32; + for(y=y1;ygetScrollbuffer()[yoff+((4+x1+scrollx_buf)&511)] = 10; + if (x2getScrollbuffer()[yoff+((4+x2+scrollx_buf)&511)] = 10; + } + } + for(x=x1;x<=x2;x++) + { + if (y1 < map.ysize && x < map.xsize) + { + yoff = ((y1+4+scrolly_buf)&511)<<9; + g_pGraphics->getScrollbuffer()[yoff+((4+x+scrollx_buf)&511)] = 10; + } + if (y2 < map.ysize && x < map.xsize) + { + yoff = ((y2+4+scrolly_buf)&511)<<9; + g_pGraphics->getScrollbuffer()[yoff+((4+x+scrollx_buf)&511)] = 10; + } + } + + // draw the area that is visible on the screen + // 320x200 = 20x12.5 tiles + x1 = scroll_x>>4; y1 = scroll_y>>4; + x2 = x1+20; y2 = y1+12; + for(y=y1;ygetScrollbuffer()[yoff+((4+x1+scrollx_buf)&511)] = 12; + if (x2getScrollbuffer()[yoff+((4+x2+scrollx_buf)&511)] = 12; + } + } + for(x=x1;x<=x2;x++) + { + if (x < map.xsize) + { + if (y1 < map.ysize) + { + yoff = ((y1+4+scrolly_buf)&511)<<9; + g_pGraphics->getScrollbuffer()[yoff+((4+x+scrollx_buf)&511)] = 12; + } + if (y2 < map.ysize) + { + yoff = ((y2+4+scrolly_buf)&511)<<9; + g_pGraphics->getScrollbuffer()[yoff+((4+x+scrollx_buf)&511)] = 12; + } + } + } +} + +void SetAllCanSupportPlayer(int o, int state) +{ + unsigned int i; + for(i=0;idrawFont(text[i], (dlgX+1)<<3, (dlgY+1+i)<<3,0); + } + + twirlframe = 0; + twirltimer = TWIRL_SPEED+1; + + g_pInput->flushAll(); + + // wait for enter + do + { + if (twirltimer>TWIRL_SPEED) + { + g_pGraphics->drawCharacter((dlgX+twirlX)<<3, (dlgY+twirlY)<<3, 9+twirlframe); + g_pVideoDriver->update_screen(); + twirlframe++; + if (twirlframe>5) twirlframe=0; + twirltimer=0; + } else twirltimer++; + g_pInput->pollEvents(); + g_pTimer->SpeedThrottle(); + g_pVideoDriver->update_screen(); + } while(!g_pInput->getPressedKey(KENTER)); +} diff --git a/src/sdl/CVideoDriver.cpp b/src/sdl/CVideoDriver.cpp index 58f0f1244..e6e3dde96 100644 --- a/src/sdl/CVideoDriver.cpp +++ b/src/sdl/CVideoDriver.cpp @@ -480,7 +480,7 @@ char tempbuf[80]; #else sprintf(tempbuf, "FPS: %03d", fps); #endif - g_pGraphics->drawFont( (unsigned char *) tempbuf, 320-3-(strlen( (char *) tempbuf)<<3), 3, 1); + g_pGraphics->drawFont( tempbuf, 320-3-(strlen( (char *) tempbuf)<<3), 3, 1); } update_screen(); @@ -765,7 +765,7 @@ int y; y = CONSOLE_MESSAGE_Y; for(i=0;idrawFont( (unsigned char *) cmsg[i].msg, CONSOLE_MESSAGE_X, y, 1); + g_pGraphics->drawFont( cmsg[i].msg, CONSOLE_MESSAGE_X, y, 1); y += CONSOLE_MESSAGE_SPACING; } } diff --git a/src/sdl/CVideoDriver.h b/src/sdl/CVideoDriver.h index 39f07aec1..0dace2d9b 100644 --- a/src/sdl/CVideoDriver.h +++ b/src/sdl/CVideoDriver.h @@ -21,7 +21,6 @@ struct st_resolution #include #include #include -using namespace std; inline bool LockSurface(SDL_Surface * bmp) { if (SDL_MUSTLOCK(bmp)) @@ -110,8 +109,8 @@ private: st_resolution m_Resolution; - list m_Resolutionlist; - list :: iterator m_Resolution_pos; + std::list m_Resolutionlist; + std::list :: iterator m_Resolution_pos; unsigned int Mode; bool Fullscreen; diff --git a/src/sdl/sound/CSound.cpp b/src/sdl/sound/CSound.cpp index 4a37a1c53..bde61eabd 100644 --- a/src/sdl/sound/CSound.cpp +++ b/src/sdl/sound/CSound.cpp @@ -12,6 +12,7 @@ #include "../../hqp/CMusic.h" #include "../../vorticon/sounds.h" #include "../../fileio/CExeFile.h" +#include "../../StringUtils.h" #define SAFE_DELETE_ARRAY(x) if(x) delete[] x; x=NULL @@ -44,7 +45,7 @@ CSound::~CSound() { bool CSound::init(void) { - char name[MAX_STRING_LENGTH]; + char name[256]; SDL_AudioSpec *desired, *obtained; desired = &AudioSpec; @@ -297,14 +298,14 @@ playsound: ; m_soundchannel[chnl].setupSound((unsigned short)snd, 0, true, WAVE_IN, 0, (mode==PLAY_FORCE) ? true : false ); } -char CSound::loadSoundData(unsigned short Episode, char *DataDirectory) +char CSound::loadSoundData(unsigned short Episode, const std::string& DataDirectory) { if(!m_active) return false; - char *path; + std::string path; int ok; - char soundfile[80]; - char buf[256]; + std::string soundfile; + std::string buf; if(m_soundslot) delete[] m_soundslot; m_soundslot = new CSoundSlot[MAX_SOUNDS]; @@ -318,21 +319,16 @@ char CSound::loadSoundData(unsigned short Episode, char *DataDirectory) g_pLogFile->ftextOut("sound_load_all(): loading all sounds...
"); - char buffer[256]; - - formatPathString(buffer,path); - - sprintf(soundfile, "%ssounds.ck%d", buffer,Episode); + soundfile = formatPathString(path) + "sounds.ck" + itoa(Episode); FILE *p_file; - if( ( p_file = fopen(soundfile,"rb") ) == NULL ) + if( ( p_file = fopen(soundfile.c_str(),"rb") ) == NULL ) { - formatPathString(buffer,path); - - sprintf(buf,"keen%d.exe",Episode); - g_pLogFile->ftextOut("sound_load_all(): \"%s\" was not found in the data directory. Looking for \"%s\" in \"%s\" and trying to extract this file
", soundfile, buf, buffer); - extractOfExeFile(buffer, Episode); + + buf = "keen" + itoa(Episode) + ".exe"; + g_pLogFile->ftextOut("sound_load_all(): \"%s\" was not found in the data directory. Looking for \"%s\" in \"%s\" and trying to extract this file
", soundfile.c_str(), buf.c_str(), formatPathString(path).c_str()); + extractOfExeFile(formatPathString(path), Episode); } else fclose(p_file); @@ -409,18 +405,16 @@ char CSound::loadSoundData(unsigned short Episode, char *DataDirectory) the sound data. */ -char CSound::extractOfExeFile(char *inputpath, int episode) +char CSound::extractOfExeFile(const std::string& inputpath, int episode) { - const char *outputfname; + std::string outputfname; int bit_count; int pos, sounds_start, sounds_end, ret = 0; - char buffer[MAX_STRING_LENGTH]; - char inputfname[MAX_STRING_LENGTH]; + std::string buffer; + std::string inputfname; pos = 0; bit_count = 0; - 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) @@ -437,7 +431,7 @@ char CSound::extractOfExeFile(char *inputpath, int episode) } else { - g_pLogFile->ftextOut("Error: Unknown keen executable name: %s
", inputfname); + g_pLogFile->ftextOut("Error: Unknown keen executable name: %s
", inputfname.c_str()); return 1; } @@ -446,7 +440,7 @@ char CSound::extractOfExeFile(char *inputpath, int episode) else { FILE *fout; - if(!(fout = fopen(outputfname,"wb"))) ret = 1; + if(!(fout = fopen(outputfname.c_str(),"wb"))) ret = 1; else { fwrite( ExeFile->getData()+sounds_start, 1, (sounds_end-sounds_start), fout); diff --git a/src/sdl/sound/CSound.h b/src/sdl/sound/CSound.h index 8ab64171d..456d474bb 100644 --- a/src/sdl/sound/CSound.h +++ b/src/sdl/sound/CSound.h @@ -11,10 +11,12 @@ #include "../../CSingleton.h" #define g_pSound CSound::Get() +#include #include #include "CSoundChannel.h" #include "CSoundSlot.h" + class CSound : public CSingleton { public: @@ -23,11 +25,11 @@ public: bool init(void); void stop(void); - char loadSoundData(unsigned short Episode, char *DataDirectory); + char loadSoundData(unsigned short Episode, const std::string& DataDirectory); void stopAllSounds(void); bool forcedisPlaying(void); - char sound_load_all(const char *path); + char sound_load_all(const std::string& path); void transform_into_logaritmic_sound(int *pcmstream, int len); void callback(void *unused, Uint8 *stream, int len); void pauseSound(void); @@ -44,7 +46,7 @@ public: void setSoundmode(int freq, bool stereo); - char extractOfExeFile(char *inputpath, int episode); // This is a special funktion. It doesn't belong here! + char extractOfExeFile(const std::string& inputpath, int episode); // This is a special funktion. It doesn't belong here! private: CSoundChannel *m_soundchannel; diff --git a/src/sdl/sound/CSoundSlot.cpp b/src/sdl/sound/CSoundSlot.cpp index 243a44516..097347b89 100644 --- a/src/sdl/sound/CSoundSlot.cpp +++ b/src/sdl/sound/CSoundSlot.cpp @@ -34,7 +34,7 @@ CSoundSlot::~CSoundSlot() { // loads sound searchname from file fname, into sounds[] entry loadnum // return value is nonzero on failure -bool CSoundSlot::loadSound(const char *fname, const char *searchname, unsigned int loadnum) +bool CSoundSlot::loadSound(const std::string& fname, const std::string& searchname, unsigned int loadnum) { // Unload the sound if any was previously loaded if(m_sounddata){ delete[] m_sounddata; m_sounddata = NULL; } @@ -57,10 +57,10 @@ bool CSoundSlot::loadSound(const char *fname, const char *searchname, unsigned i for(i=0;i<12;i++) name[i] = 0; - fp = fopen(fname, "rb"); + fp = fopen(fname.c_str(), "rb"); if (!fp) { - g_pLogFile->ftextOut("loadSound : Sounds file '%s' unopenable attempting load of '%s'
", fname, searchname); + g_pLogFile->ftextOut("loadSound : Sounds file '%s' unopenable attempting load of '%s'
", fname.c_str(), searchname.c_str()); return false; } @@ -75,12 +75,12 @@ bool CSoundSlot::loadSound(const char *fname, const char *searchname, unsigned i priority = fgetc(fp); garbage = fgetc(fp); for(i=0;i<12;i++) name[i] = fgetc(fp); - if (!strcmp(name, searchname)) goto sound_found; + if (name == searchname) goto sound_found; curheader += 0x10; } // sound could not be found - g_pLogFile->ftextOut("loadSound : sound %s could not be found in %s.
", searchname, fname); + g_pLogFile->ftextOut("loadSound : sound %s could not be found in %s.
", searchname.c_str(), fname.c_str()); fclose(fp); return false; @@ -115,7 +115,7 @@ bool CSoundSlot::loadSound(const char *fname, const char *searchname, unsigned i memcpy(m_sounddata, tempstack, m_soundlength*sizeof(unsigned int)); - g_pLogFile->ftextOut("loadSound : loaded sound %s of %d bytes.
", searchname, m_soundlength); + g_pLogFile->ftextOut("loadSound : loaded sound %s of %d bytes.
", searchname.c_str(), m_soundlength); m_hqsound.enabled = false; fclose(fp); diff --git a/src/sdl/sound/CSoundSlot.h b/src/sdl/sound/CSoundSlot.h index f0c131f20..408c61310 100644 --- a/src/sdl/sound/CSoundSlot.h +++ b/src/sdl/sound/CSoundSlot.h @@ -15,7 +15,7 @@ public: CSoundSlot(); virtual ~CSoundSlot(); - bool loadSound(const char *fname, const char *searchname, unsigned int loadnum); + bool loadSound(const std::string& fname, const std::string& searchname, unsigned int loadnum); void setpAudioSpec(SDL_AudioSpec *pAudioSpec){ m_pAudioSpec = pAudioSpec; } diff --git a/src/vorticon/CCredits.cpp b/src/vorticon/CCredits.cpp index 76ea1be58..037694dd6 100644 --- a/src/vorticon/CCredits.cpp +++ b/src/vorticon/CCredits.cpp @@ -128,7 +128,7 @@ void CCredits::Render(stCloneKeenPlus *pCKP) for(int j=0 ; j<51 ; j++) if(scrolly+(j<<3) > -8 && scrolly+(j<<3) < 200) - g_pGraphics->sb_font_draw_inverse( (unsigned char*) scrolltext[j], mid[j], scrolly+(j<<3)); + g_pGraphics->sb_font_draw_inverse( scrolltext[j], mid[j], scrolly+(j<<3)); if( g_pInput->getPressedAnyCommand() ) { diff --git a/src/vorticon/CDialog.cpp b/src/vorticon/CDialog.cpp index e99685a88..27c67685a 100644 --- a/src/vorticon/CDialog.cpp +++ b/src/vorticon/CDialog.cpp @@ -77,10 +77,9 @@ void CDialog::addSeparator(void) addOptionText(""); } -void CDialog::addOptionText(const char *text) +void CDialog::addOptionText(const std::string& text) { - char buf[TEXT_LENGTH]; - memset(buf,0,TEXT_LENGTH); + std::string buf; // This algorithm is similar to one pointer session and // list implementation. TextList is the head. if(OptionTextList == NULL) @@ -88,22 +87,21 @@ void CDialog::addOptionText(const char *text) OptionTextList = new stTextList; OptionTextList->nextElement = NULL; - memset(OptionTextList->text,0,TEXT_LENGTH); + OptionTextList->text = ""; - strcpy(buf,text); + buf = text; - unsigned int length; - length = strlen(buf); + size_t length = buf.length(); // before the text is copied, check if that string is too long. if(length > w-4) { - copy(text,text+w-7,OptionTextList->text); - strcat(OptionTextList->text,"..."); + OptionTextList->text = text.substr(0, w-7); + OptionTextList->text += "..."; } else { - strcpy(OptionTextList->text,text); + OptionTextList->text = text; } number_of_options = 1; @@ -124,41 +122,41 @@ void CDialog::addOptionText(const char *text) curTextList = (stTextList*) curTextList->nextElement; - memset(curTextList->text,0, TEXT_LENGTH); + curTextList->text = ""; number_of_options++; - strcpy(buf,text); + buf = text; - unsigned int length; - length = strlen(buf); + size_t length = buf.length(); // before the text is copied, check if that string is too long. if(length > w-4) { - copy(text,text+w-7,curTextList->text); - strcat(curTextList->text,"..."); + curTextList->text = text.substr(0, w-7); + curTextList->text += "..."; } else { - strcpy(curTextList->text,text); + curTextList->text = text; } curTextList->nextElement = NULL; } } -void CDialog::setOptionText(unsigned int pos, const char *text) +void CDialog::setOptionText(unsigned int pos, const std::string& text) { unsigned int i; - stTextList *curTextList; + stTextList *curTextList = OptionTextList; - curTextList = OptionTextList; - - for(i=0 ; inextElement; - - memset(curTextList->text,0,TEXT_LENGTH); - strcpy(curTextList->text,text); + for(i=0 ; inextElement; + } + + curTextList->text = text; } void CDialog::setDimensions(int rectx, int recty, int rectw, int recth) @@ -197,7 +195,7 @@ void CDialog::renderDialog() while(curTextList != NULL) { - g_pGraphics->sb_font_draw((unsigned char*)(curTextList->text), (x+3)<<3, (y+i+1)<<3); + g_pGraphics->sb_font_draw(curTextList->text, (x+3)<<3, (y+i+1)<<3); curTextList = (stTextList*) curTextList->nextElement; i++; if(i >= h-2) @@ -287,7 +285,7 @@ void CDialog::renderOpenDialogAnimation(int x,int y, int w, int h) isanimated = false; } -char *CDialog::getOptionString(unsigned int pos) +std::string CDialog::getOptionString(unsigned int pos) { unsigned int i; stTextList *curTextList; @@ -327,7 +325,7 @@ bool CDialog::setNextSelection() int i=0; if(selection+1 < number_of_options) { - while(strcmp(getOptionString(selection+i+1),"") == 0) + while(getOptionString(selection+i+1) == "") i++; selection += i; @@ -343,7 +341,7 @@ bool CDialog::setPrevSelection() int i=0; if(selection-1 > 0) { - while(strcmp(getOptionString(selection-i-1),"") == 0) + while(getOptionString(selection-i-1) == "") i++; selection -= i; diff --git a/src/vorticon/CDialog.h b/src/vorticon/CDialog.h index f81cd2299..632f81b24 100644 --- a/src/vorticon/CDialog.h +++ b/src/vorticon/CDialog.h @@ -8,13 +8,13 @@ #ifndef CDIALOG_H_ #define CDIALOG_H_ -#define TEXT_LENGTH 256 +#include -typedef struct stTextList +struct stTextList { - char text[TEXT_LENGTH]; - void *nextElement; -}stTextList; + std::string text; + stTextList *nextElement; +}; class CDialog { public: @@ -25,8 +25,8 @@ public: void drawDialogbox(int x1, int y1, int w, int h); void setDimensions(int rectx, int recty, int rectw, int recth); - void addOptionText(const char *text); - void setOptionText(unsigned int pos, const char *text); + void addOptionText(const std::string& text); + void setOptionText(unsigned int pos, const std::string& text); void addSeparator(void); bool setSelection(int value); @@ -34,7 +34,7 @@ public: bool setPrevSelection(); int getSelection(void); - char *getOptionString(unsigned int pos); + std::string getOptionString(unsigned int pos); void renderOpenDialogAnimation(int x,int y, int w, int h); void animateDialogBox(bool value); diff --git a/src/vorticon/CEGAGraphics.cpp b/src/vorticon/CEGAGraphics.cpp index 69e66be3f..51df16a25 100644 --- a/src/vorticon/CEGAGraphics.cpp +++ b/src/vorticon/CEGAGraphics.cpp @@ -12,11 +12,14 @@ #endif #include #include +#include "../StringUtils.h" + + using namespace std; -CEGAGraphics::CEGAGraphics(short episode, const char *path) { +CEGAGraphics::CEGAGraphics(short episode, const std::string& path) { m_episode = episode; - strcpy(m_path, path); + m_path = path; // EGAHEAD Structure LatchPlaneSize = 0; @@ -51,15 +54,15 @@ CEGAGraphics::~CEGAGraphics() { bool CEGAGraphics::loadData() { - char buf[256]; + std::string buf; vector databuf; chdir("data"); // TODO: You must be able to use another directory - if(m_path[0] == 0) - sprintf(buf,"egahead.ck%hd",m_episode); + if(m_path == "") + buf = "egahead.ck" + itoa(m_episode); else - sprintf(buf,"%s/egahead.ck%hd",m_path,m_episode); - ifstream HeadFile(buf,ios::binary); + buf = m_path + "/egahead.ck" + itoa(m_episode); + std::ifstream HeadFile(buf.c_str(),ios::binary); if(!HeadFile) return false; @@ -106,10 +109,10 @@ bool CEGAGraphics::loadData() m_Latch->loadHead(data); - if(m_path[0] == 0) - sprintf(buf,"egalatch.ck%hd",m_episode); + if(m_path == "") + buf = "egalatch.ck" + itoa(m_episode); else - sprintf(buf,"%s/egalatch.ck%hd",m_path,m_episode); + buf = m_path + "/egalatch.ck" + itoa(m_episode); m_Latch->loadData(buf,(compressed>>1)); // The second bit tells, if latch is compressed. @@ -119,10 +122,10 @@ bool CEGAGraphics::loadData() SpriteLocation); m_Sprit->loadHead(data); - if(m_path[0] == 0) - sprintf(buf,"egasprit.ck%hd",m_episode); + if(m_path == "") + buf = "egasprit.ck" + itoa(m_episode); else - sprintf(buf,"%s/egasprit.ck%hd",m_path,m_episode); + buf = m_path + "/egasprit.ck" + itoa(m_episode); m_Sprit->loadData(buf,(compressed>>1)); chdir("../"); diff --git a/src/vorticon/CEGAGraphics.h b/src/vorticon/CEGAGraphics.h index 7c8287c4e..99605342d 100644 --- a/src/vorticon/CEGAGraphics.h +++ b/src/vorticon/CEGAGraphics.h @@ -14,12 +14,13 @@ #ifndef CEGAGRAPHICS_H_ #define CEGAGRAPHICS_H_ +#include #include "CEGALatch.h" #include "CEGASprit.h" class CEGAGraphics { public: - CEGAGraphics(short episode, const char *path); + CEGAGraphics(short episode, const std::string& path); virtual ~CEGAGraphics(); bool loadData(); @@ -28,7 +29,7 @@ public: private: short m_episode; - char m_path[256]; + std::string m_path; // Part of the EGAHEAD Data Structure // Section 1: diff --git a/src/vorticon/CEGALatch.cpp b/src/vorticon/CEGALatch.cpp index 930a15179..1ea63f2d5 100644 --- a/src/vorticon/CEGALatch.cpp +++ b/src/vorticon/CEGALatch.cpp @@ -65,12 +65,11 @@ bool CEGALatch::loadHead( char *data ) return true; } -bool CEGALatch::loadData(const char *filename, bool compresseddata) +bool CEGALatch::loadData(const std::string& filename, bool compresseddata) { - FILE* latchfile; char *RawData; - latchfile = fopen(filename,"rb"); + FILE* latchfile = fopen(filename.c_str(),"rb"); if(!latchfile) return false; diff --git a/src/vorticon/CEGALatch.h b/src/vorticon/CEGALatch.h index 6dac2b5be..d72589fd3 100644 --- a/src/vorticon/CEGALatch.h +++ b/src/vorticon/CEGALatch.h @@ -8,7 +8,8 @@ #ifndef CEGALATCH_H_ #define CEGALATCH_H_ -#include +#include +#include class CEGALatch { public: @@ -25,7 +26,7 @@ public: virtual ~CEGALatch(); bool loadHead(char *data ); - bool loadData(const char *filename, bool compresseddata); + bool loadData(const std::string& filename, bool compresseddata); char *RawData; diff --git a/src/vorticon/CEGASprit.cpp b/src/vorticon/CEGASprit.cpp index f5d29a8e9..cb4b96dde 100644 --- a/src/vorticon/CEGASprit.cpp +++ b/src/vorticon/CEGASprit.cpp @@ -71,12 +71,11 @@ bool CEGASprit::loadHead(char *data) return true; } -bool CEGASprit::loadData(const char *filename, bool compresseddata) +bool CEGASprit::loadData(const std::string& filename, bool compresseddata) { - FILE* latchfile; char *RawData; - latchfile = fopen(filename,"rb"); + FILE* latchfile = fopen(filename.c_str(),"rb"); if(!latchfile) return false; diff --git a/src/vorticon/CEGASprit.h b/src/vorticon/CEGASprit.h index 2cabe9ad9..1f46dda2a 100644 --- a/src/vorticon/CEGASprit.h +++ b/src/vorticon/CEGASprit.h @@ -8,6 +8,8 @@ #ifndef CEGASPRIT_H_ #define CEGASPRIT_H_ +#include + class CEGASprit { public: CEGASprit(int planesize, @@ -17,7 +19,7 @@ public: virtual ~CEGASprit(); bool loadHead(char *data); - bool loadData(const char *filename, bool compresseddata); + bool loadData(const std::string& filename, bool compresseddata); private: int m_numsprites; diff --git a/src/vorticon/CHighScores.cpp b/src/vorticon/CHighScores.cpp index d166e01fa..c398b7a8f 100644 --- a/src/vorticon/CHighScores.cpp +++ b/src/vorticon/CHighScores.cpp @@ -9,9 +9,7 @@ #include #include -using namespace std; - -#include +#include #include "../keen.h" #include "../include/menu.h" @@ -20,10 +18,14 @@ using namespace std; #include "../sdl/CInput.h" #include "../sdl/CTimer.h" #include "../CGraphics.h" +#include "../StringUtils.h" #define HIGHSCORETABLE_X 1344 #define HIGHSCORETABLE_Y 32 +using namespace std; + + CHighScores::CHighScores(stCloneKeenPlus *poutsideCKP) { // Set default Scores strcpy(Name[0],"Gerstrong"); @@ -124,8 +126,8 @@ char CHighScores::showHighScore(void) for( i=0 ; i<7 ; i++ ) { - g_pGraphics->sb_color_font_draw((unsigned char*) Name[i],40,64+(i<<4),4,7); - g_pGraphics->sb_color_font_draw((unsigned char*) Score[i],200-(strlen(Score[i])<<3),64+(i<<4),4,7); + g_pGraphics->sb_color_font_draw(Name[i],40,64+(i<<4),4,7); + g_pGraphics->sb_color_font_draw(Score[i],200-(strlen(Score[i])<<3),64+(i<<4),4,7); if(Extra[i][0] == true) g_pGraphics->drawTile(32,90+(i<<4),ItemTiles[0]); if(Extra[i][1] == true) @@ -140,19 +142,19 @@ char CHighScores::showHighScore(void) { for( i=0 ; i<7 ; i++ ) { - char buf[2]; - g_pGraphics->sb_color_font_draw((unsigned char*) Name[i],40,64+(i<<4),4,7); - g_pGraphics->sb_color_font_draw((unsigned char*) Score[i],200-(strlen(Score[i])<<3),64+(i<<4),4,7); - sprintf(buf,"%d",Cities[i]); - g_pGraphics->sb_color_font_draw((unsigned char*) buf,250,64+(i<<4),4,7); + std::string buf; + g_pGraphics->sb_color_font_draw(Name[i],40,64+(i<<4),4,7); + g_pGraphics->sb_color_font_draw(Score[i],200-(strlen(Score[i])<<3),64+(i<<4),4,7); + buf = itoa(Cities[i]); + g_pGraphics->sb_color_font_draw(buf,250,64+(i<<4),4,7); } } else { for( i=0 ; i<7 ; i++ ) { - g_pGraphics->sb_color_font_draw((unsigned char*) Name[i],40,64+(i<<4),4,7); - g_pGraphics->sb_color_font_draw((unsigned char*) Score[i],200-(strlen(Score[i])<<3),64+(i<<4),4,7); + g_pGraphics->sb_color_font_draw(Name[i],40,64+(i<<4),4,7); + g_pGraphics->sb_color_font_draw(Score[i],200-(strlen(Score[i])<<3),64+(i<<4),4,7); } } @@ -245,19 +247,19 @@ char CHighScores::writeHighScore(int points, bool *extras, int cities) { for( i=0 ; i<7 ; i++ ) { - char buf[2]; - g_pGraphics->sb_color_font_draw((unsigned char*) Name[i],40,64+(i<<4),4,7); - g_pGraphics->sb_color_font_draw((unsigned char*) Score[i],200-(strlen(Score[i])<<3),64+(i<<4),4,7); - sprintf(buf,"%d",Cities[i]); - g_pGraphics->sb_color_font_draw((unsigned char*) buf,250,64+(i<<4),4,7); + std::string buf; + g_pGraphics->sb_color_font_draw(Name[i],40,64+(i<<4),4,7); + g_pGraphics->sb_color_font_draw(Score[i],200-(strlen(Score[i])<<3),64+(i<<4),4,7); + buf = itoa(Cities[i]); + g_pGraphics->sb_color_font_draw(buf,250,64+(i<<4),4,7); } } else { for( i=0 ; i<7 ; i++ ) { - g_pGraphics->sb_color_font_draw((unsigned char*) Name[i],40,64+(i<<4),4,7); - g_pGraphics->sb_color_font_draw((unsigned char*) Score[i],200-(strlen(Score[i])<<3),64+(i<<4),4,7); + g_pGraphics->sb_color_font_draw(Name[i],40,64+(i<<4),4,7); + g_pGraphics->sb_color_font_draw(Score[i],200-(strlen(Score[i])<<3),64+(i<<4),4,7); } } @@ -311,7 +313,7 @@ char CHighScores::writeHighScore(int points, bool *extras, int cities) if(g_pInput->getPressedKey(KBCKSPCE) && (WrittenName.length() > 0)) { memset(buf,0,256); - g_pGraphics->sb_color_font_draw((unsigned char*) " ",40,64+(place<<4),4,7); + g_pGraphics->sb_color_font_draw(" ",40,64+(place<<4),4,7); WrittenName.erase(WrittenName.length()-1); WrittenName.copy(buf,WrittenName.length(),0); memset(Name[place],0,16); @@ -329,10 +331,10 @@ char CHighScores::writeHighScore(int points, bool *extras, int cities) for( i=0 ; i<7 ; i++ ) { if(i != place) - g_pGraphics->sb_color_font_draw((unsigned char*) Name[i],40,64+(i<<4),4,7); + g_pGraphics->sb_color_font_draw(Name[i],40,64+(i<<4),4,7); else - g_pGraphics->sb_color_font_draw((unsigned char*) buf,40,64+(i<<4),4,7); - g_pGraphics->sb_color_font_draw((unsigned char*) Score[i],200-(strlen(Score[i])<<3),64+(i<<4),4,7); + g_pGraphics->sb_color_font_draw(buf,40,64+(i<<4),4,7); + g_pGraphics->sb_color_font_draw(Score[i],200-(strlen(Score[i])<<3),64+(i<<4),4,7); if(pCKP->Control.levelcontrol.episode == 1) { @@ -364,9 +366,7 @@ char CHighScores::writeHighScore(int points, bool *extras, int cities) char CHighScores::loadHighScoreTable(void) { string sBuf; - char chBuf[256]; - - sprintf(chBuf,"%d",Episode); + std::string chBuf = itoa(Episode); sBuf.append("data/"); sBuf.append(DataDirectory); diff --git a/src/vorticon/CHighScores.h b/src/vorticon/CHighScores.h index 7b822a657..4797a19d5 100644 --- a/src/vorticon/CHighScores.h +++ b/src/vorticon/CHighScores.h @@ -8,6 +8,8 @@ #ifndef CHIGHSCORES_H_ #define CHIGHSCORES_H_ +#include + class CHighScores { public: CHighScores(stCloneKeenPlus *poutsideCKP); @@ -25,7 +27,7 @@ private: int ItemTiles[4]; char Episode; - char *DataDirectory; + std::string DataDirectory; stCloneKeenPlus *pCKP; diff --git a/src/vorticon/CMessages.cpp b/src/vorticon/CMessages.cpp index e479b9d31..ef5dd5c9a 100644 --- a/src/vorticon/CMessages.cpp +++ b/src/vorticon/CMessages.cpp @@ -55,7 +55,7 @@ bool CMessages::readData(char *buf, int episode, int version) // Now read the stuff and store it to a list for(int pos=offset_start ; pos :: iterator i; + std::list :: iterator i; #include for(i=StringList.begin() ; i!=StringList.end() ; i++) diff --git a/src/vorticon/CMessages.h b/src/vorticon/CMessages.h index a76f35568..00d6be2fb 100644 --- a/src/vorticon/CMessages.h +++ b/src/vorticon/CMessages.h @@ -12,8 +12,6 @@ #include #include -using namespace std; - // TODO: Make the strings a class, but it must read from the exe-files basing on uncompressed buffer class CMessages { @@ -25,8 +23,8 @@ public: char *getString(const char *IDtext); private: - list StringList; - list StringIDList; + std::list StringList; + std::list StringIDList; }; #endif /* CMESSAGES_H_ */