Files
commandergenius/project/jni/application/enigma/src/enigma.cpp
2010-10-13 17:30:44 +03:00

520 lines
12 KiB
C++
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Copyright (C) 2002,2003,2004 Daniel Heck
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "errors.hh"
#include "enigma.hh"
#include "ecl.hh"
#include "main.hh"
#include <iostream>
#include <ctime>
#include <set>
using namespace std;
using namespace ecl;
using namespace enigma;
/* -------------------- Game Type -------------------- */
static const char *versionName[GAMET_COUNT+1] = {
"enigma", // same indices as enum GameType
"oxyd1",
"per.oxyd",
"oxyd.extra",
"oxyd.magnum",
0
};
GameType enigma::GetGameType(std::string name) {
GameType type = GAMET_UNKNOWN;
for (int v = 0; v<GAMET_COUNT; ++v) {
if (0 == strcmp(name.c_str(), versionName[v])) {
type = GameType(v);
break;
}
}
return type;
}
std::string enigma::GetGameTypeName(GameType type) {
if (type >= GAMET_FIRST && type <= GAMET_LAST)
return versionName[type];
else
return "unknown";
}
/* -------------------- Direction -------------------- */
Direction enigma::reverse(Direction d) {
static Direction rdir[] = { NODIR, EAST, NORTH, WEST, SOUTH };
return rdir[d+1];
}
Direction enigma::rotate_cw (Direction d)
{
static Direction rdir[] = { NODIR, NORTH, WEST, SOUTH, EAST };
return rdir[d+1];
}
Direction enigma::rotate_ccw (Direction d)
{
static Direction rdir[] = { NODIR, SOUTH, EAST, NORTH, WEST };
return rdir[d+1];
}
Direction
direction_fromto(GridPos source, GridPos target)
{
// source and target have to be adjacent
int dx = target.x-source.x;
int dy = target.y-source.y;
Direction d = NODIR;
if (dx == 0) {
if (dy == -1) d = NORTH;
else if (dy == 1) d = SOUTH;
}
else if (dy == 0) {
if (dx == -1) d = WEST;
else if (dx == 1) d = EAST;
}
ASSERT(d != NODIR, XLevelRuntime,
"direction_fromto: source and target not adjacent");
return d;
}
string enigma::to_suffix(Direction d) {
static const char *sfx[] = { "", "-w", "-s", "-e", "-n" };
return sfx[d+1];
}
/* -------------------- DirectionBits -------------------- */
DirectionBits
enigma::rotate(DirectionBits d, bool clockwise)
{
if (clockwise) {
d = DirectionBits(((d>>1) | (d<<3)) & ALL_DIRECTIONS);
} else {
d = DirectionBits(((d>>3) | (d<<1)) & ALL_DIRECTIONS);
}
return d;
}
/* -------------------- Value implementation -------------------- */
Value::Value(const char* str)
: type(STRING)
{
val.str = new char[strlen(str)+1];
strcpy(val.str, str);
}
Value::~Value()
{
clear();
}
Value::Value(const string& str)
: type(STRING)
{
val.str = new char[str.length()+1];
strcpy(val.str, str.c_str());
}
Value::Value (const Value& other) : type(NIL) {
this->operator=(other);
}
Value& Value::operator= (const Value& other) {
if (this != &other) {
if (other.type == STRING) {
assign(other.val.str);
} else {
clear();
type = other.type;
val = other.val;
}
}
return *this;
}
void Value::assign(const char* s) {
clear();
type = STRING;
val.str = new char[strlen(s)+1];
strcpy(val.str, s);
}
void Value::assign(double d)
{
clear(); type=DOUBLE; val.dval=d;
}
void Value::clear() {
if (type == STRING)
delete[] val.str;
type = NIL;
}
double Value::get_double() const throw()
{
ASSERT(type == DOUBLE, XLevelRuntime, "get_double: type not double");
return val.dval;
}
const char* Value::get_string() const throw()
{
ASSERT(type == STRING, XLevelRuntime, "get_string: type not string");
return val.str;
}
Buffer& enigma::operator<<(Buffer& buf, const Value& val)
{
buf << Uint8(val.get_type());
switch (val.get_type()) {
case Value::NIL:
break;
case Value::DOUBLE:
buf << val.get_double();
break;
case Value::STRING:
{
const char* str = val.get_string();
buf << (Uint16)strlen(str);
buf.write(str, strlen(str));
} break;
}
return buf;
}
// Buffer& enigma::operator>>(Buffer& buf, Value& val)
// {
// Uint8 type = Value::NIL;
// buf >> type;
// switch (type) {
// case Value::NIL:
// // ## fixme
// break;
// case Value::DOUBLE:
// {
// double tmp;
// if (buf >> tmp)
// val = Value(tmp);
// } break;
// case Value::STRING:
// {
// Uint16 len;
// if (buf >> len) {
// char* tmp = new char[len+1];
// tmp[len] = 0;
// if (buf.read(tmp, len))
// val.assign(tmp);
// delete[] tmp;
// }
// } break;
// }
// return buf;
// }
int enigma::to_int(const Value &v) {
switch (v.get_type()) {
case Value::DOUBLE: return round_nearest<int>(v.get_double());
case Value::STRING: return atoi(v.get_string());
default: return 0;
}
}
bool enigma::to_bool(const Value &v) {
return (v.get_type() != Value::NIL);
}
double enigma::to_double(const Value &v) {
switch (v.get_type()) {
case Value::DOUBLE: return v.get_double();
case Value::STRING: return atof(v.get_string());
default: return 0;
}
}
#ifdef _MSC_VER
#define snprintf _snprintf
#endif
const char * enigma::to_string(const Value &v) {
static char buf[30];
switch (v.get_type()) {
case Value::NIL: return "";
case Value::DOUBLE:
snprintf(buf, sizeof(buf), "%f", v.get_double());
return buf;
case Value::STRING: return v.get_string();
default: return 0;
}
}
Direction enigma::to_direction (const Value &v) {
int val = Clamp(to_int(v), 0, 3);
return static_cast<Direction>(val);
}
ostream& enigma::operator<<(ostream& os, const Value& val)
{
switch (val.get_type()) {
case Value::NIL: os << "nil"; break;
case Value::DOUBLE: os << val.get_double(); break;
case Value::STRING: os << val.get_string(); break;
}
return os;
}
/* -------------------- GridPos -------------------- */
GridPos::GridPos(const ecl::V2& p)
: x (round_down<int>(p[0])),
y (round_down<int>(p[1]))
{}
std::ostream& enigma::operator<<(std::ostream& os, const GridPos& val)
{
return os << '(' << val.x << ',' << val.y << ')';
}
/*
516
203
748
*/
GridPos enigma::get_neighbour (GridPos p, int i)
{
ASSERT (i >= 0 && i <= 9, XLevelRuntime, "get_neighbour: index out of bounds");
static int xoff[9] = { 0,0,-1,1,0,-1,1,-1,1 };
static int yoff[9] = { 0,-1,0,0,1,-1,-1,1,1 };
return GridPos(p.x + xoff[i], p.y + yoff[i]);
}
/* -------------------- GridLoc -------------------- */
bool enigma::to_gridloc (const char *str, GridLoc &l) {
GridLoc loc;
const char *numstr = str + 3;
if (strncmp (str, "fl(", 3) == 0)
loc.layer = GRID_FLOOR;
else if (strncmp (str, "it(", 3) == 0)
loc.layer = GRID_ITEMS;
else if (strncmp (str, "st(", 3) == 0)
loc.layer = GRID_STONES;
else
numstr = str;
if (2 != sscanf (numstr, "%d %d", &loc.pos.x, &loc.pos.y))
return false;
l = loc;
return true;
}
/* -------------------- Random numbers -------------------- */
void enigma::Randomize ()
{
srand (time(NULL));
}
void enigma::Randomize (unsigned seed)
{
srand (seed);
}
int enigma::IntegerRand (int min, int max)
{
int r = round_down<int>((max-min+1) * (rand()/(RAND_MAX+1.0)));
return r+min;
}
double enigma::DoubleRand (double min, double max)
{
return min + double(rand())/RAND_MAX * (max-min);
}
/* -------------------- Time & Date -------------------- */
#define MAX_DATE_LENGTH 256
const char *enigma::date(const char *format) { // format see 'man strftime'
static char *result = 0;
char buffer[MAX_DATE_LENGTH];
time_t t;
time(&t);
struct tm *tm = localtime(&t);
strftime(buffer, MAX_DATE_LENGTH, format, tm);
if (result) free(result);
result = strdup(buffer);
return result;
}
/* -------------------- Resource management -------------------- */
namespace
{
struct FontDescr {
// Variables
string name;
string ttf_name;
int ttf_size;
string bitmap_name;
int r, g, b;
// Constructor
FontDescr (const string &name_,
const string &ttf_name_,
int ttf_size_,
const string &bitmap_name_,
int r_, int g_, int b_)
: name (name_),
ttf_name (ttf_name_),
ttf_size (ttf_size_),
bitmap_name (bitmap_name_),
r (r_), g(g_), b(b_)
{}
};
class FontCache : public PtrCache<Font> {
public:
Font *acquire (const std::string &name) {
Font *f = 0;
if (m_fonts.has_key (name)) {
const FontDescr &fd = m_fonts[name];
f = load_ttf (fd.ttf_name, fd.ttf_size, fd.r, fd.g, fd.b);
if (f == 0) {
std::cerr << "Could not load .ttf file " << fd.ttf_name << "\n";
f = load_bmf (fd.bitmap_name);
}
}
else {
f = load_bmf (name);
}
return f;
}
void define_font (const FontDescr &descr) {
remove (descr.name); // remove entry in cache (if any)
if (m_fonts.has_key (descr.name))
m_fonts[descr.name]= descr;
else
m_fonts.insert (descr.name, descr);
}
private:
Font *load_bmf (const string &name) {
string png, bmf;
if (app.resourceFS->findFile(string("fonts/")+name+".png", png) &&
app.resourceFS->findFile(string("fonts/")+name+".bmf", bmf))
{
return ecl::LoadBitmapFont(png.c_str(), bmf.c_str());
}
return 0;
}
Font *load_ttf (const string &name, int ptsize, int r, int g, int b) {
string ttf;
if (app.resourceFS->findFile(string("fonts/") + name, ttf))
return ecl::LoadTTF (ttf.c_str(), ptsize, r, g, b);
return 0;
}
// Variables
ecl::Dict <FontDescr> m_fonts;
};
// ---------- Variables ----------
FontCache font_cache;
ImageCache image_cache;
}
ecl::Surface *ImageCache::acquire (const std::string &name)
{
return ecl::LoadImage(name.c_str());
}
void enigma::DefineFont (const char *name,
const char *ttf_name,
int ttf_size,
const char *bmf_name,
int r, int g, int b)
{
font_cache.define_font (FontDescr (name, ttf_name, ttf_size, bmf_name, r, g, b));
}
ecl::Font *enigma::GetFont (const char *name)
{
return font_cache.get(name);
}
void enigma::ClearFontCache() {
font_cache.clear();
}
ecl::Surface *enigma::LoadImage(const char *name)
{
string filename;
if (app.resourceFS->findImageFile (string(name) + ".png", filename))
return ecl::LoadImage(filename.c_str());
return 0;
}
ecl::Surface *enigma::GetImage(const char *name, const char *ext)
{
string filename;
if (app.resourceFS->findImageFile (string(name) + ext, filename))
return image_cache.get(filename);
return 0;
}
ecl::Surface *enigma::RegisterImage (const char *name, ecl::Surface *s)
{
image_cache.store(name, s);
return s;
}
void enigma::ClearImageCache() {
image_cache.clear();
}