From ce46866403fdcc479cf9d67e4d430409b15dadc3 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 21 Aug 2002 16:07:07 +0000 Subject: Initial revision svn-id: r4785 --- common/config-file.cpp | 386 +++++++++++++++++++++++++++++ common/config-file.h | 57 +++++ common/gameDetector.cpp | 632 ++++++++++++++++++++++++++++++++++++++++++++++++ common/gameDetector.h | 79 ++++++ common/main.cpp | 150 ++++++++++++ common/scummsys.h | 366 ++++++++++++++++++++++++++++ common/stdafx.cpp | 1 + common/stdafx.h | 169 +++++++++++++ common/system.h | 199 +++++++++++++++ common/timer.cpp | 157 ++++++++++++ common/timer.h | 66 +++++ common/util.cpp | 312 ++++++++++++++++++++++++ common/util.h | 183 ++++++++++++++ 13 files changed, 2757 insertions(+) create mode 100644 common/config-file.cpp create mode 100644 common/config-file.h create mode 100644 common/gameDetector.cpp create mode 100644 common/gameDetector.h create mode 100644 common/main.cpp create mode 100644 common/scummsys.h create mode 100644 common/stdafx.cpp create mode 100644 common/stdafx.h create mode 100644 common/system.h create mode 100644 common/timer.cpp create mode 100644 common/timer.h create mode 100644 common/util.cpp create mode 100644 common/util.h (limited to 'common') diff --git a/common/config-file.cpp b/common/config-file.cpp new file mode 100644 index 0000000000..b56630f5c5 --- /dev/null +++ b/common/config-file.cpp @@ -0,0 +1,386 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001/2002 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#include +#include +#include "stdafx.h" +#include "config-file.h" +#include "scumm.h" + +#define MAXLINELEN 256 + +#define xfree(p) {if (p) free(p);} + + +static char *ltrim(char *t) +{ + for (; *t && (*t == ' '); t++); + return t; +} + +static char *rtrim(char *t) +{ + int l; + + for (l = strlen(t) - 1; l; l--) { + if (t[l] == ' ') { + *t = 0; + } else { + return t; + } + } + return t; +} + +class hashconfig { +public: + hashconfig (const char *); + ~hashconfig (); + bool is_domain(const char *) const; + const char *get(const char *) const; + const char *set(const char *, const char *); + const char *getdomain() const; + void flush(FILE *) const; + void rename(const char *); + void merge(const hashconfig *); +private: + char *domain; + char **keys, **values; + int nkeys; +}; + +hashconfig::hashconfig (const char *dom):domain(dom ? strdup(dom) : 0), +keys(0), values(0), nkeys(0) +{ +} + +hashconfig::~hashconfig () { + xfree(domain); +} + +bool hashconfig::is_domain(const char *d) const +{ + return d && domain && !strcmp(d, domain); +} + +const char *hashconfig::get(const char *key) const +{ + int i; + + for (i = 0; i < nkeys; i++) { + if (!strcmp(key, keys[i])) { + return values[i]; + } + } + + return 0; +} + +const char *hashconfig::set(const char *key, const char *value) +{ + int i; + + for (i = 0; i < nkeys; i++) { + if (!strcmp(key, keys[i])) { + xfree(values[i]); + return values[i] = value ? strdup(value) : 0; + } + } + + nkeys++; + keys = (char **)realloc(keys, nkeys * sizeof(char *)); + values = (char **)realloc(values, nkeys * sizeof(char *)); + keys[nkeys - 1] = strdup(key); + return values[nkeys - 1] = value ? strdup(value) : 0; +} + +const char *hashconfig::getdomain() const +{ + return domain; +} + +void hashconfig::flush(FILE *cfg_file) const +{ + int i; + + if (!domain) + return; + + fprintf(cfg_file, "[%s]\n", domain); + + for (i = 0; i < nkeys; i++) { + if (values[i]) { + fprintf(cfg_file, "%s=%s\n", keys[i], values[i]); + } + } + fprintf(cfg_file, "\n"); +} + +void hashconfig::rename(const char *d) +{ + xfree(domain); + domain = d ? strdup(d) : 0; +} + +void hashconfig::merge(const hashconfig *h) +{ + int i; + + for (i = 0; i < h->nkeys; i++) { + set(h->keys[i], h->values[i]); + } +} + +// The config-class itself. + +Config::Config (const char *cfg, const char *d) +: filename(strdup(cfg)), domain(d ? strdup(d) : 0), hash(0), ndomains(0), willwrite(false) +{ + FILE *cfg_file; + char t[MAXLINELEN]; + + if (!(cfg_file = fopen(cfg, "r"))) { + debug(1, "Unable to open configuration file: %s.\n", filename); + } else { + while (!feof(cfg_file)) { + if (!fgets(t, MAXLINELEN, cfg_file)) + continue; + if (t[0] != '#') { + if (t[0] == '[') { + // It's a new domain which begins here. + char *p = strchr(t, ']'); + if (!p) { + debug(1, "Config file buggy: no ] at the end of the domain name.\n"); + } else { + *p = 0; + set_domain(t + 1); + } + } else { + // It's a new key in the domain. + if (!domain) { + debug(1, "Config file buggy: we have a key without a domain first.\n"); + } + char *p = strchr(t, '\n'); + if (p) + *p = 0; + p = strchr(t, '\r'); + if (p) + *p = 0; + + if (!(p = strchr(t, '='))) { + if (strlen(t)) + debug(1, "Config file buggy: there is junk: %s\n", t); + } else { + char *key, *value; + *p = 0; + key = ltrim(rtrim(t)); + value = ltrim(p + 1); + set(key, value); + } + } + } + } + set_domain(d); + fclose(cfg_file); + } +} + +Config::~Config () { + int i; + + xfree(filename); + xfree(domain); + + for (i = 0; i < ndomains; i++) { + delete hash[i]; + } + xfree(hash); +} + +const char *Config::get(const char *key, const char *d) const +{ + int i; + + if (!d) + d = domain; + + for (i = 0; i < ndomains; i++) { + if (hash[i]->is_domain(d)) { + return hash[i]->get(key); + } + } + + return 0; +} + +const int Config::getInt(const char *key, int def, const char *d) const +{ + const char *value = get(key, d); + + if (value) + return atoi(value); + return def; +} + +const bool Config::getBool(const char *key, bool def, const char *d) const +{ + const char *value = get(key, d); + + if (value) + return !scumm_stricmp(value, "true"); + return def; +} + +const char *Config::set(const char *key, const char *value, const char *d) +{ + int i; + + if (!d) + d = domain; + + for (i = 0; i < ndomains; i++) { + if (hash[i]->is_domain(d)) { + return hash[i]->set(key, value); + } + } + + ndomains++; + hash = (hashconfig **)realloc(hash, ndomains * sizeof(hashconfig *)); + hash[ndomains - 1] = new hashconfig (d); + + return hash[ndomains - 1]->set(key, value); +} + +const char *Config::set(const char *key, int value_i, const char *d) +{ + char value[MAXLINELEN]; + sprintf(value, "%i", value_i); + return set(key, value, d); +} + +const char *Config::set(const char *key, bool value_b, const char *d) +{ + const char *value = value_b ? "true" : "false"; + return set(key, value, d); +} + +void Config::set_domain(const char *d) +{ + int i; + xfree(domain); + domain = d ? strdup(d) : 0; + + for (i = 0; i < ndomains; i++) { + if (hash[i]->is_domain(domain)) + return; + } + ndomains++; + hash = (hashconfig **)realloc(hash, ndomains * sizeof(hashconfig *)); + hash[ndomains - 1] = new hashconfig (domain); +} + +void Config::flush() const +{ + FILE *cfg_file; + int i; + + if (!willwrite) + return; + + if (!(cfg_file = fopen(filename, "w"))) { + debug(1, "Unable to write configuration file: %s.\n", filename); + } else { + for (i = 0; i < ndomains; i++) { + hash[i]->flush(cfg_file); + } + fclose(cfg_file); + } +} + +void Config::rename_domain(const char *d) +{ + int i, index = -1; + + for (i = 0; i < ndomains; i++) { + if (hash[i]->is_domain(d)) { + index = i; + } + } + + for (i = 0; i < ndomains; i++) { + if (hash[i]->is_domain(domain)) { + if (index >= 0) { + hash[i]->merge(hash[index]); + hash[index]->rename(0); + rename_domain(d); + } else { + hash[i]->rename(d); + set_domain(d); + } + } + } +} + +void Config::delete_domain(const char *d) +{ + int i; + + for (i = 0; i < ndomains; i++) { + if (hash[i]->is_domain(d)) { + hash[i]->rename(0); + } + } +} + +void Config::change_filename(const char *f) +{ + xfree(filename); + filename = f ? strdup(f) : 0; +} + +void Config::merge_config(const Config *c) +{ + int i, j; + bool found; + + for (i = 0; i < c->ndomains; i++) { + found = false; + for (j = 0; j < ndomains; j++) { + if (hash[j]->is_domain(c->hash[i]->getdomain())) { + hash[j]->merge(c->hash[i]); + found = true; + break; + } + } + if (!found) { + ndomains++; + hash = (hashconfig **)realloc(hash, ndomains * sizeof(hashconfig *)); + hash[ndomains - 1] = new hashconfig (domain); + hash[ndomains - 1]->merge(c->hash[i]); + } + } +} + +void Config::set_writing(bool w) +{ + willwrite = w; +} diff --git a/common/config-file.h b/common/config-file.h new file mode 100644 index 0000000000..eee4cfde59 --- /dev/null +++ b/common/config-file.h @@ -0,0 +1,57 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001/2002 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#ifndef CONFIG_FILE_H +#define CONFIG_FILE_H + +class hashconfig; + +class Config { +public: + Config (const char * = "config.cfg", const char * = "default"); + ~Config (); + const char *get(const char *key, const char *dom = 0) const; + const int getInt(const char *key, int def = 0, const char *dom = 0) const; + const bool getBool(const char *key, bool def = false, const char *dom = 0) const; + + const char *set(const char *key, const char *value, const char *dom = 0); + const char *set(const char *key, int value, const char *dom = 0); + const char *set(const char *key, bool value, const char *dom = 0); + + void set_domain(const char *); + void flush() const; + void rename_domain(const char *); + void delete_domain(const char *); + void change_filename(const char *); + void merge_config(const Config *); + void set_writing(bool); +private: + char *filename, *domain; + hashconfig **hash; + int ndomains; + bool willwrite; +}; + +// The global config object +extern Config *scummcfg; + +#endif diff --git a/common/gameDetector.cpp b/common/gameDetector.cpp new file mode 100644 index 0000000000..421dfd782e --- /dev/null +++ b/common/gameDetector.cpp @@ -0,0 +1,632 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001/2002 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + + +#include "stdafx.h" +#include "scumm/scumm.h" +#include "sound/mididrv.h" +#include "scumm/imuse.h" +#include "common/gameDetector.h" +#include "common/config-file.h" + + +#define CHECK_OPTION() if ((current_option != NULL) || (*s != '\0')) goto ShowHelpAndExit +#define HANDLE_OPTION() if ((*s == '\0') && (current_option == NULL)) goto ShowHelpAndExit; \ + if ((*s != '\0') && (current_option != NULL)) goto ShowHelpAndExit; \ + option = (*s == '\0' ? current_option : s); \ + current_option = NULL +#define HANDLE_OPT_OPTION() if ((*s != '\0') && (current_option != NULL)) goto ShowHelpAndExit; \ + if ((*s == '\0') && (current_option == NULL)) option = NULL; \ + else option = (*s == '\0' ? current_option : s); \ + current_option = NULL + +static const char USAGE_STRING[] = + "ScummVM - Scumm Interpreter\n" + "Syntax:\n" + "\tscummvm [-v] [-d[]] [-n] [-b] [-t] [-s] [-p] [-m] [-f] game\n" + "Flags:\n" + "\t-a - specify game is amiga version\n" + "\t-b - start in room \n" + "\t-c - use cdrom for cd audio\n" + "\t-d[] - enable debug output (debug level [1])\n" + "\t-e - set music engine (see readme.txt for details)\n" + "\t-f - fullscreen mode\n" + "\t-g - graphics mode (normal,2x,3x,2xsai,super2xsai,supereagle,advmame2x)\n" + "\t-l - load config file instead of default\n" + "\t-m - set music volume to (0-100)\n" + "\t-n - no subtitles for speech\n" + "\t-p - look for game in \n" + "\t-s - set sfx volume to (0-255)\n" + "\t-t - set music tempo (default- adlib: 0x1F0000, midi: 0x460000)\n" + "\t-v - show version info and exit\n" +#if defined(UNIX) + "\t-w[] - write to config file [~/.scummvmrc]\n" +#else + "\t-w[] - write to config file [scummvm.ini]\n" +#endif + "\t-x[] - save game slot to load (default: autosave)\n" + "\t-y - set text speed (default: 60)\n" +; + +void GameDetector::updateconfig() +{ + const char * val; + + _amiga = scummcfg->getBool("amiga", _amiga); + + _save_slot = scummcfg->getInt("save_slot", _save_slot); + + _cdrom = scummcfg->getInt("cdrom", _cdrom); + + if ((val = scummcfg->get("music_driver"))) + if (!parseMusicDriver(val)) { + printf("Error in the config file: invalid music_driver.\n"); + printf(USAGE_STRING); + exit(-1); + } + + _fullScreen = scummcfg->getBool("fullscreen", _fullScreen); + + if ((val = scummcfg->get("gfx_mode"))) + if ((_gfx_mode = parseGraphicsMode(val)) == -1) { + printf("Error in the config file: invalid gfx_mode.\n"); + printf(USAGE_STRING); + exit(-1); + } + + _music_volume = scummcfg->getInt("music_volume", _music_volume); + + _noSubtitles = scummcfg->getBool("nosubtitles", _noSubtitles); + + if ((val = scummcfg->get("path"))) + _gameDataPath = strdup(val); + + _sfx_volume = scummcfg->getInt("sfx_volume", _sfx_volume); + + // We use strtol for the tempo to allow it to be specified in hex. + if ((val = scummcfg->get("tempo"))) + _gameTempo = strtol(val, NULL, 0); + + _talkSpeed = scummcfg->getInt("talkspeed", _talkSpeed); +} + +void GameDetector::parseCommandLine(int argc, char **argv) +{ + int i; + char *s; + char *current_option = NULL; + char *option = NULL; + char c; + _save_slot = -1; + + // check for arguments + if (argc < 2) { + printf(USAGE_STRING); + //exit(1); + } + + scummcfg->set_domain("game-specific"); + /* Parse the arguments */ + for (i = argc - 1; i >= 1; i--) { + s = argv[i]; + + if (s[0] == '-') { + s++; + c = *s++; + switch (tolower(c)) { + case 'a': + CHECK_OPTION(); + _amiga = (c == 'a'); + scummcfg->set("amiga", _amiga); + break; + case 'b': + HANDLE_OPTION(); + _bootParam = atoi(option); + break; + case 'c': + HANDLE_OPTION(); + _cdrom = atoi(option); + scummcfg->set("cdrom", _cdrom); + break; + case 'd': + _debugMode = true; + HANDLE_OPT_OPTION(); + if (option != NULL) + _debugLevel = atoi(option); + debug(1,"Debugmode (level %d) on", _debugLevel); + break; + case 'e': + HANDLE_OPTION(); + if (!parseMusicDriver(option)) + goto ShowHelpAndExit; + scummcfg->set("music_driver", option); + break; + case 'f': + CHECK_OPTION(); + _fullScreen = (c == 'f'); + scummcfg->set("fullscreen", _fullScreen, "scummvm"); + break; + case 'g': + HANDLE_OPTION(); + _gfx_mode = parseGraphicsMode(option); + if (_gfx_mode == -1) + goto ShowHelpAndExit; + scummcfg->set("gfx_mode", option, "scummvm"); + break; + case 'l': + HANDLE_OPTION(); + { + Config * newconfig = new Config(option, "scummvm"); + scummcfg->merge_config(newconfig); + delete newconfig; + updateconfig(); + break; + } + break; + case 'm': + HANDLE_OPTION(); + _music_volume = atoi(option); + scummcfg->set("music_volume", _music_volume); + break; + case 'n': + CHECK_OPTION(); + _noSubtitles = (c == 'n'); + scummcfg->set("nosubtitles", _noSubtitles); + break; + case 'p': + HANDLE_OPTION(); + _gameDataPath = option; + scummcfg->set("path", _gameDataPath); + break; + case 'r': + HANDLE_OPTION(); + // Ignore -r for now, to ensure backward compatibility. + break; + case 's': + HANDLE_OPTION(); + _sfx_volume = atoi(option); + scummcfg->set("sfx_volume", _sfx_volume); + break; + case 't': + HANDLE_OPTION(); + _gameTempo = strtol(option, 0, 0); + scummcfg->set("tempo", option); + break; + case 'v': + CHECK_OPTION(); + printf("ScummVM " SCUMMVM_VERSION "\nBuilt on " __DATE__ " " + __TIME__ "\n"); +#ifdef SCUMMVM_PLATFORM_VERSION + printf(" " SCUMMVM_PLATFORM_VERSION "\n"); +#endif + exit(1); + case 'w': + _saveconfig = true; + scummcfg->set_writing(true); + HANDLE_OPT_OPTION(); + if (option != NULL) + scummcfg->change_filename(option); + break; + case 'x': + _save_slot = 0; + HANDLE_OPT_OPTION(); + if (option != NULL) { + _save_slot = atoi(option); + scummcfg->set("save_slot", _save_slot); + } + break; + case 'y': + HANDLE_OPTION(); + _talkSpeed = atoi(option); + scummcfg->set("talkspeed", _talkSpeed); + break; + default: + goto ShowHelpAndExit; + } + } else { + if (i == (argc - 1)) { + _exe_name = s; + scummcfg->set_domain(s); + scummcfg->rename_domain("game-specific"); + scummcfg->rename_domain(s); + updateconfig(); + } else { + if (current_option == NULL) + current_option = s; + else + goto ShowHelpAndExit; + } + } + } + + if (_exe_name) + scummcfg->flush(); + + return; + + ShowHelpAndExit: + printf(USAGE_STRING); + exit(1); +} + +int GameDetector::parseGraphicsMode(const char *s) { + struct GraphicsModes { + const char *name; + int id; + }; + + const struct GraphicsModes gfx_modes[] = { + {"normal",GFX_NORMAL}, + {"1x",GFX_NORMAL}, + {"2x",GFX_DOUBLESIZE}, + {"3x",GFX_TRIPLESIZE}, + {"2xsai",GFX_2XSAI}, + {"super2xsai",GFX_SUPER2XSAI}, + {"supereagle",GFX_SUPEREAGLE}, + {"advmame2x",GFX_ADVMAME2X} + }; + + const GraphicsModes *gm = gfx_modes; + int i; + for(i=0; i!=ARRAYSIZE(gfx_modes); i++,gm++) { + if (!scumm_stricmp(gm->name, s)) + return gm->id; + } + + return -1; +} + +bool GameDetector::parseMusicDriver(const char *s) { + struct MusicDrivers { + const char *name; + int id; + }; + + const struct MusicDrivers music_drivers[] = { + {"auto",MD_AUTO}, + {"null",MD_NULL}, + {"windows",MD_WINDOWS}, + {"seq",MD_SEQ}, + {"qt",MD_QTMUSIC}, + {"core",MD_COREAUDIO}, + {"amidi",MD_AMIDI}, + {"midiemu",MD_MIDIEMU}, + {"alsa", MD_ALSA}, + {"adlib",-1}, + }; + + const MusicDrivers *md = music_drivers; + int i; + + _use_adlib = false; + + for(i=0; i!=ARRAYSIZE(music_drivers); i++,md++) { + if (!scumm_stricmp(md->name, s)) { + if (md->id == -1) { + _use_adlib = true; + } + _midi_driver = md->id; + return true; + } + } + + return false; +} + + +struct VersionSettings { + const char *filename; + const char *gamename; + byte id, major, middle, minor; + uint32 features; +}; + +/* + This is a list of all known SCUMM games. Commented games are not + supported at this time */ + +static const VersionSettings version_settings[] = { + /* Scumm Version 1 */ +// {"maniac", "Maniac Mansion (C64)", GID_MANIAC64, 1, 0, 0,}, +// {"zak", "Zak McKracken and the Alien Mindbenders (C64)", GID_ZAK64, 1, 0, 0,}, + + /* Scumm Version 2 */ +// {"maniac", "Maniac Mansion", GID_MANIAC, 2, 0, 0,}, +// {"zak", "Zak McKracken and the Alien Mindbenders", GID_ZAK, 2, 0, 0,}, +// {"indy3", "Indiana Jones and the Last Crusade", GID_INDY3, 2, 0, 0,}, + + /* Scumm Version 3 */ + {"indy3", "Indiana Jones and the Last Crusade (256)", GID_INDY3_256, 3, 0, 22, + GF_SMALL_HEADER | GF_USE_KEY | GF_SMALL_NAMES | GF_OLD256 | GF_NO_SCALLING}, + {"zak256", "Zak McKracken and the Alien Mindbenders (256)", GID_ZAK256, 3, 0, 0, + GF_SMALL_HEADER | GF_USE_KEY | GF_SMALL_NAMES | GF_OLD256 | GF_AUDIOTRACKS | GF_NO_SCALLING}, + {"loom", "Loom", GID_LOOM, 3, 5, 40, + GF_SMALL_HEADER | GF_USE_KEY | GF_SMALL_NAMES | GF_OLD_BUNDLE | GF_16COLOR | GF_NO_SCALLING}, + + /* Scumm Version 4 */ + {"monkeyEGA", "Monkey Island 1 (EGA)", GID_MONKEY_EGA, 4, 0, 67, + GF_SMALL_HEADER | GF_USE_KEY | GF_16COLOR}, // EGA version + + /* Scumm version 5 */ + {"monkeyVGA", "Monkey Island 1 (256 color Floppy version)", GID_MONKEY_VGA, 5, 0, 16, + GF_SMALL_HEADER | GF_USE_KEY | GF_AUDIOTRACKS | GF_ADLIB_DEFAULT}, + {"loomcd", "Loom (256 color CD version)", GID_LOOM256, 5, 1, 42, + GF_SMALL_HEADER | GF_USE_KEY | GF_AUDIOTRACKS | GF_ADLIB_DEFAULT}, + {"monkey", "Monkey Island 1", GID_MONKEY, 5, 2, 2, + GF_USE_KEY | GF_AUDIOTRACKS | GF_ADLIB_DEFAULT}, + {"monkey1", "Monkey Island 1 (alt)", GID_MONKEY, 5, 2, 2, + GF_USE_KEY | GF_AUDIOTRACKS | GF_ADLIB_DEFAULT}, + {"monkey2", "Monkey Island 2: LeChuck's revenge", GID_MONKEY2, 5, 2, 2, + GF_USE_KEY | GF_ADLIB_DEFAULT}, + {"atlantis", "Indiana Jones and the Fate of Atlantis", GID_INDY4, 5, 5, 0, + GF_USE_KEY | GF_ADLIB_DEFAULT}, + {"playfate", "Indiana Jones and the Fate of Atlantis (Demo)", GID_INDY4, 5, 5, 0, + GF_USE_KEY | GF_ADLIB_DEFAULT}, + {"fate", "Indiana Jones and the Fate of Atlantis (Demo)", GID_INDY4, 5, 5, 0, + GF_USE_KEY | GF_ADLIB_DEFAULT}, + + /* Scumm Version 6 */ + {"tentacle", "Day Of The Tentacle", GID_TENTACLE, 6, 4, 2, + GF_NEW_OPCODES | GF_AFTER_V6 | GF_USE_KEY | GF_ADLIB_DEFAULT}, + {"dottdemo", "Day Of The Tentacle (Demo)", GID_TENTACLE, 6, 3, 2, + GF_NEW_OPCODES | GF_AFTER_V6 | GF_USE_KEY | GF_ADLIB_DEFAULT}, + {"samnmax", "Sam & Max", GID_SAMNMAX, 6, 4, 2, + GF_NEW_OPCODES | GF_AFTER_V6 | GF_USE_KEY | GF_DRAWOBJ_OTHER_ORDER}, + {"samdemo", "Sam & Max (Demo)", GID_SAMNMAX, 6, 3, 0, + GF_NEW_OPCODES | GF_AFTER_V6 | GF_USE_KEY | GF_DRAWOBJ_OTHER_ORDER | GF_ADLIB_DEFAULT}, + {"snmdemo", "Sam & Max (Demo)", GID_SAMNMAX, 6, 3, 0, + GF_NEW_OPCODES | GF_AFTER_V6 | GF_USE_KEY | GF_DRAWOBJ_OTHER_ORDER | GF_ADLIB_DEFAULT}, + + {"puttdemo", "Putt Putt joins the parade (demo)", GID_SAMNMAX, 6, 3, 0, + GF_NEW_OPCODES | GF_AFTER_V6 | GF_USE_KEY | GF_ADLIB_DEFAULT | GF_HUMONGOUS}, + {"moondemo", "Putt Putt goes to the moon (demo)", GID_SAMNMAX, 6, 3, 0, + GF_NEW_OPCODES | GF_AFTER_V6 | GF_USE_KEY | GF_ADLIB_DEFAULT | GF_HUMONGOUS}, + + {"test", "Test demo game", GID_SAMNMAX, 6, 6, 6, GF_NEW_OPCODES | GF_AFTER_V6}, + + /* Scumm Version 7 */ + {"ft", "Full Throttle", GID_FT, 7, 3, 0, + GF_NEW_OPCODES | GF_AFTER_V6 | GF_AFTER_V7}, + {"dig", "The Dig", GID_DIG, 7, 5, 0, + GF_NEW_OPCODES | GF_AFTER_V6 | GF_AFTER_V7}, + + /* Simon the Sorcerer 1 & 2 (not SCUMM games) */ + {"simon1dos", "Simon the Sorcerer 1 for DOS", GID_SIMON_FIRST+0, 99, 99, 99, 0}, + {"simon2dos", "Simon the Sorcerer 2 for DOS", GID_SIMON_FIRST+1, 99, 99, 99, 0}, + {"simon1win", "Simon the Sorcerer 1 for Windows", GID_SIMON_FIRST+2, 99, 99, 99, 0}, + {"simon2win", "Simon the Sorcerer 2 for Windows", GID_SIMON_FIRST+3, 99, 99, 99, 0}, + + /* Scumm Version 8 */ + {"comi", "The Curse of Monkey Island", GID_CMI, 8, 1, 0, + GF_NEW_OPCODES | GF_AFTER_V6 | GF_AFTER_V7 | GF_AFTER_V8}, + + {NULL, NULL} +}; + +bool GameDetector::detectGame() +{ + const VersionSettings *gnl = version_settings; + + _gameId = 0; + _gameText = NULL; + do { + if (!scumm_stricmp(_exe_name, gnl->filename)) { + _gameId = gnl->id; + _scummVersion = gnl->major; + + _features = gnl->features; + _gameText = gnl->gamename; + debug(1, "Detected game '%s', version %d.%d.%d", + gnl->gamename, gnl->major, gnl->middle, gnl->minor); + return true; + } + } while ((++gnl)->filename); + + debug(1, "Failed game detection"); + + return true; +} + +char *GameDetector::getGameName() +{ + if (_gameText == NULL) { + char buf[256]; + sprintf(buf, "Unknown game: \"%s\"", _exe_name); + return strdup(buf); + } + return strdup(_gameText); +} + +int GameDetector::detectMain(int argc, char **argv) +{ + _debugMode = 0; // off by default... + + _noSubtitles = 0; // use by default - should this depend on soundtrack? + + _talkSpeed = 60; + +#ifndef _WIN32_WCE + _gfx_mode = GFX_DOUBLESIZE; +#else + _gfx_mode = GFX_NORMAL; +#endif + _sfx_volume = kDefaultSFXVolume; + _music_volume = kDefaultMusicVolume; + +#if defined(USE_NULL_DRIVER) + _gfx_driver = GD_NULL; +#elif defined(__DC__) + _gfx_driver = GD_DC; +#elif defined(X11_BACKEND) + _gfx_driver = GD_X; +#elif defined(__MORPHOS__) + _gfx_driver = GD_MORPHOS; +#elif defined(_WIN32_WCE) + _gfx_driver = GD_WINCE; +#elif defined(MACOS_CARBON) + _gfx_driver = GD_MAC; +#else + /* SDL is the default driver for now */ + _gfx_driver = GD_SDL; +#endif + + _gameDataPath = NULL; + _gameTempo = 0; + _soundCardType = 3; + + + + _midi_driver = MD_AUTO; + +#if defined(__DC__) + extern int dc_setup(GameDetector &detector); + dc_setup(*this); +#elif defined(MACOS_CARBON) + extern char* SelectGame(); + char *game_name = SelectGame(); + printf(game_name); +#else + _saveconfig = false; + updateconfig(); + parseCommandLine(argc, argv); +#endif + + if (_exe_name == NULL) { + //launcherLoop(); + //setWindowName(this); + warning("No game was specified..."); + return (-1); + } + + + if (!detectGame()) { + warning("Game detection failed. Using default settings"); + _features = GF_DEFAULT; + _gameText = "Please choose a game"; + } + + /* Use the adlib sound driver if auto mode is selected, + * and the game is one of those that want adlib as + * default */ + if (_midi_driver == MD_AUTO && _features&GF_ADLIB_DEFAULT) { + _use_adlib = true; + } + + if (!_gameDataPath) { + warning("No path was provided. Assuming the data files are in the current directory"); + _gameDataPath = strdup(""); + } else if (_gameDataPath[strlen(_gameDataPath)-1] != '/' +#ifdef __MORPHOS__ + && _gameDataPath[strlen(_gameDataPath)-1] != ':' +#endif + && _gameDataPath[strlen(_gameDataPath)-1] != '\\') { + char slashless[1024]; /* Append slash to path */ + strcpy(slashless, _gameDataPath); + _gameDataPath = (char *)malloc((strlen(slashless) + 1) * sizeof(char)); + sprintf(_gameDataPath, "%s/", slashless); + } + + if (_amiga) + _features = _features | GF_AMIGA; + + return (0); +} + +OSystem *GameDetector::createSystem() { + /* auto is to use SDL */ + switch(_gfx_driver) { +#if defined(X11_BACKEND) + case GD_X: + return OSystem_X11_create(); +#elif defined(__DC__) + case GD_DC: + return OSystem_Dreamcast_create(); +#elif defined(_WIN32_WCE) + case GD_WINCE: + return OSystem_WINCE3_create(); +#elif defined(__MORPHOS__) + case GD_MORPHOS: + return OSystem_MorphOS_create(_gameId, _gfx_mode, _fullScreen); +#elif defined(MACOS_CARBON) + case GD_MAC: + return OSystem_MAC_create(_gfx_mode, _fullScreen); +#elif defined(USE_NULL_DRIVER) + case GD_NULL: + return OSystem_NULL_create(); +#else + case GD_SDL: + return OSystem_SDL_create(_gfx_mode, _fullScreen); +#endif + } + + error("Invalid graphics driver"); + return NULL; +} + +MidiDriver *GameDetector::createMidi() { + int drv = _midi_driver; + +#if defined (_WIN32_WCE) + /* Always use MIDI emulation on CE devices */ + if (drv == MD_AUTO) drv = MD_MIDIEMU; +#endif + +#if defined (WIN32) && !defined(_WIN32_WCE) + /* MD_WINDOWS is default MidiDriver on windows targets */ + if (drv == MD_AUTO) drv = MD_WINDOWS; +#elif defined(__APPLE__) || defined(macintosh) + /* MD_QTMUSIC is default MidiDriver on MacOS targets */ + if (drv == MD_AUTO) drv = MD_QTMUSIC; +#elif defined(UNIX) || defined(X11_BACKEND) + /* MD_MIDIEMU is default MidiDriver on UNIX targets. */ + /* FIXME: Attempt to detect if sequencer is available, + and use it in preference. */ + if (drv == MD_AUTO) drv = MD_MIDIEMU; +#endif + + switch(drv) { + case MD_AUTO: + case MD_NULL: return MidiDriver_NULL_create(); + case MD_MIDIEMU: return MidiDriver_MIDIEMU_create(); +#if defined(WIN32) && !defined(_WIN32_WCE) + case MD_WINDOWS: return MidiDriver_WIN_create(); +#endif +#if defined(__MORPHOS__) + case MD_AMIDI: return MidiDriver_AMIDI_create(); +#endif +#if defined(UNIX) && !defined(__BEOS__) + case MD_SEQ: return MidiDriver_SEQ_create(); +#endif +#if defined(__APPLE__) || defined(macintosh) + case MD_QTMUSIC: return MidiDriver_QT_create(); +#endif +#if defined(MACOSX) + case MD_COREAUDIO: return MidiDriver_CORE_create(); +#endif +#if defined(UNIX) && defined(USE_ALSA) + case MD_ALSA: return MidiDriver_ALSA_create(); +#endif + } + + error("Invalid midi driver selected"); + return NULL; +} diff --git a/common/gameDetector.h b/common/gameDetector.h new file mode 100644 index 0000000000..4cbfa3453f --- /dev/null +++ b/common/gameDetector.h @@ -0,0 +1,79 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001/2002 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#ifndef GAMEDETECTOR_H +#define GAMEDETECTOR_H + +class OSystem; +class MidiDriver; + +class GameDetector { +public: + int detectMain(int argc, char **argv); + void parseCommandLine(int argc, char **argv); + bool detectGame(void); + char *getGameName(void); + + bool _fullScreen; + byte _gameId; + bool _simon; + + bool _use_adlib; + + int _music_volume; + int _sfx_volume; + bool _amiga; + + uint16 _talkSpeed; + uint16 _debugMode; + uint16 _noSubtitles; + uint16 _bootParam; + uint16 _soundCardType; + + char *_gameDataPath; + int _gameTempo; + int _midi_driver; + char *_exe_name; + const char *_gameText; + uint32 _features; + + int _gfx_driver; + int _gfx_mode; + + int _scummVersion; + int _cdrom; + int _save_slot; + + bool _saveconfig; + + int parseGraphicsMode(const char *s); + + bool parseMusicDriver(const char *s); + + void updateconfig(); + +public: + OSystem *createSystem(); + MidiDriver *createMidi(); +}; + +#endif diff --git a/common/main.cpp b/common/main.cpp new file mode 100644 index 0000000000..43fd2e4563 --- /dev/null +++ b/common/main.cpp @@ -0,0 +1,150 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001/2002 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#include "stdafx.h" +#include "engine.h" +#include "scumm.h" +#include "sound/mididrv.h" +#include "gameDetector.h" +#include "simon/simon.h" +#include "config-file.h" + +GameDetector detector; + +Config *scummcfg = 0; + + +#if defined(QTOPIA) +// FIXME - why exactly is this needed? +extern "C" int main(int argc, char *argv[]); +#endif + +#if defined(MACOSX) || defined(QTOPIA) +#include +#elif !defined(__MORPHOS__) +#undef main +#endif + +#if defined(UNIX) +#include +#ifndef MAXPATHLEN +#define MAXPATHLEN 256 +#endif +#define DEFAULT_CONFIG_FILE ".scummvmrc" +#else +#define DEFAULT_CONFIG_FILE "scummvm.ini" +#endif + +#if defined(UNIX) +#include + +#ifndef SCUMM_NEED_ALIGNMENT +static void handle_errors(int sig_num) { + error("Your system does not support unaligned memory accesses. Please rebuild with SCUMM_NEED_ALIGNMENT "); +} +#endif + +/* This function is here to test if the endianness / alignement compiled it is matching + with the one at run-time. */ +static void do_memory_test(void) { + unsigned char test[8] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 }; + unsigned int value; + /* First test endianness */ +#ifdef SCUMM_LITTLE_ENDIAN + if (*((int *) test) != 0x44332211) { + error("Compiled as LITTLE_ENDIAN on a big endian system. Please rebuild "); + } + value = 0x55443322; +#else + if (*((int *) test) != 0x11223344) { + error("Compiled as BIG_ENDIAN on a little endian system. Please rebuild "); + } + value = 0x22334455; +#endif + /* Then check if one really supports unaligned memory accesses */ +#ifndef SCUMM_NEED_ALIGNMENT + signal(SIGBUS, handle_errors); + signal(SIGABRT, handle_errors); + signal(SIGSEGV, handle_errors); + if (*((unsigned int *) ((char *) test + 1)) != value) { + error("Your system does not support unaligned memory accesses. Please rebuild with SCUMM_NEED_ALIGNMENT "); + } + signal(SIGBUS, SIG_DFL); + signal(SIGABRT, SIG_DFL); + signal(SIGSEGV, SIG_DFL); +#endif +} + +#endif + +int main(int argc, char *argv[]) +{ +#ifdef __DC__ + extern void dc_init_hardware(); + dc_init_hardware(); +#endif + +#if defined(UNIX) + /* On Unix, do a quick endian / alignement check before starting */ + do_memory_test(); + + char scummhome[MAXPATHLEN]; + if(getenv("HOME") != NULL) + sprintf(scummhome,"%s/%s", getenv("HOME"), DEFAULT_CONFIG_FILE); + else strcpy(scummhome,DEFAULT_CONFIG_FILE); +#else + char scummhome[255]; + #if defined (WIN32) && !defined(_WIN32_WCE) + GetWindowsDirectory(scummhome, 255); + strcat(scummhome, "\\"); + strcat(scummhome, DEFAULT_CONFIG_FILE); + #else + strcpy(scummhome,DEFAULT_CONFIG_FILE); + #endif +#endif + + scummcfg = new Config(scummhome, "scummvm"); + scummcfg->set("versioninfo", SCUMMVM_VERSION); + if (detector.detectMain(argc, argv)) + return (-1); + + OSystem *system = detector.createSystem(); + + { + char *s = detector.getGameName(); + OSystem::Property prop; + + prop.caption = s; + system->property(OSystem::PROP_SET_WINDOW_CAPTION, &prop); + free(s); + } + + // Create the game engine + Engine *engine = Engine::createFromDetector(&detector, system); + + // Run the game engine + engine->go(); + + delete scummcfg; + + return 0; +} diff --git a/common/scummsys.h b/common/scummsys.h new file mode 100644 index 0000000000..74fcfbcb84 --- /dev/null +++ b/common/scummsys.h @@ -0,0 +1,366 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +#ifndef __SCUMMSYS_H_ +#define __SCUMMSYS_H_ + +#include + +#if defined(HAVE_NO_BOOL) +typedef int bool; +const bool true(1), false(0); +#endif /* HAVE_NO_BOOL */ + +#if defined(_MSC_VER) + +//#pragma warning (disable: 4244) +//#pragma warning (disable: 4101) + +#define scumm_stricmp stricmp + +#if defined(CHECK_HEAP) +#undef CHECK_HEAP +#define CHECK_HEAP checkHeap(); +#else +#define CHECK_HEAP +#endif + +#define SCUMM_LITTLE_ENDIAN + +#define FORCEINLINE __forceinline +#define NORETURN _declspec(noreturn) + +typedef unsigned char byte; +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned long uint32; +typedef unsigned int uint; +typedef signed char int8; +typedef signed short int16; +typedef signed long int32; + +#define START_PACK_STRUCTS pack (push,1) +#define END_PACK_STRUCTS pack(pop) +#define GCC_PACK + +#elif defined(__MINGW32__) + +#define scumm_stricmp stricmp +#define CHECK_HEAP +#define SCUMM_LITTLE_ENDIAN + +#define FORCEINLINE inline +#define NORETURN __attribute__((__noreturn__)) +#define GCC_PACK __attribute__((packed)) +#define _HEAPOK 0 + +typedef unsigned char byte; +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned long uint32; +typedef unsigned int uint; +typedef signed char int8; +typedef signed short int16; +typedef signed long int32; + +#define START_PACK_STRUCTS pack (push,1) +#define END_PACK_STRUCTS pack(pop) + +#elif defined(UNIX) || defined(__APPLE__) + +#define scumm_stricmp strcasecmp + +#define CHECK_HEAP + +#ifdef X11_BACKEND + +/* You need to set those manually */ +#define SCUMM_LITTLE_ENDIAN +/* #define SCUMM_NEED_ALIGNMENT */ + +#else +/* need this for the SDL_BYTEORDER define */ +#include + +#if SDL_BYTEORDER == SDL_LIL_ENDIAN +#define SCUMM_LITTLE_ENDIAN +#elif SDL_BYTEORDER == SDL_BIG_ENDIAN +#define SCUMM_BIG_ENDIAN +#define SCUMM_NEED_ALIGNMENT +#else +#error Neither SDL_BIG_ENDIAN nor SDL_LITTLE_ENDIAN is set. +#endif +#endif + +#define FORCEINLINE inline +#define CDECL + +typedef unsigned char byte; +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint; +typedef signed char int8; +typedef signed short int16; + +# if defined(__DECCXX) // Assume alpha architecture + +# define INVERSE_MKID +# define SCUMM_NEED_ALIGNMENT + +typedef unsigned int uint32; +typedef signed int int32; + +# else + +typedef unsigned long uint32; +typedef signed long int32; + +# endif + + +#if defined(__GNUC__) +#define START_PACK_STRUCTS +#define END_PACK_STRUCTS +#define GCC_PACK __attribute__((packed)) +#define NORETURN __attribute__((__noreturn__)) +#else +#define START_PACK_STRUCTS pack (1) +#define END_PACK_STRUCTS pack () +#define GCC_PACK +#define NORETURN +#endif + +#elif defined(macintosh) +#include + +#include "macos.h" + +#define scumm_stricmp strcmp +inline char* strdup(char *buf) {return (char*)buf;}; + +#define CHECK_HEAP +#define SCUMM_BIG_ENDIAN + +#define FORCEINLINE inline +#define CDECL + +typedef unsigned char byte; +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned long uint32; +typedef unsigned int uint; +typedef signed char int8; +typedef signed short int16; +typedef signed long int32; + +#define START_PACK_STRUCTS pack (1) +#define END_PACK_STRUCTS pack () +#define GCC_PACK +#define NORETURN +#define USE_QTMUSIC +#define NEED_STRDUP + +#elif defined(__MORPHOS__) +#define scumm_stricmp stricmp +#define CHECK_HEAP + +#define SCUMM_BIG_ENDIAN +#define SCUMM_NEED_ALIGNMENT + +#define FORCEINLINE inline +#define CDECL + +typedef unsigned char byte; +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned long uint32; +typedef unsigned int uint; +typedef signed char int8; +typedef signed short int16; +typedef signed long int32; + +#if defined(__GNUC__) + #define START_PACK_STRUCTS + #define END_PACK_STRUCTS + #define GCC_PACK __attribute__((packed)) + #define NORETURN __attribute__((__noreturn__)) +#else + #define START_PACK_STRUCTS pack (1) + #define END_PACK_STRUCTS pack () + #define GCC_PACK + #define NORETURN +#endif +#define main morphos_main +#elif defined(__DC__) + +#define scumm_stricmp strcasecmp +#define CHECK_HEAP +#define SCUMM_LITTLE_ENDIAN +#define SCUMM_NEED_ALIGNMENT + +#define FORCEINLINE inline +#define NORETURN __attribute__((__noreturn__)) +#define GCC_PACK __attribute__((packed)) +#define CDECL + +typedef unsigned char byte; +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned long uint32; +typedef unsigned int uint; +typedef signed char int8; +typedef signed short int16; +typedef signed long int32; + +#define START_PACK_STRUCTS pack (push,1) +#define END_PACK_STRUCTS pack(pop) + +#else +#error No system type defined +#endif + + +#if defined(SCUMM_LITTLE_ENDIAN) + +//#if defined(SCUMM_NEED_ALIGNMENT) +//#error Little endian processors that need alignment is not implemented +//#endif + + +#define PROTO_MKID(a) ((((a)>>24)&0xFF) | (((a)>>8)&0xFF00) | (((a)<<8)&0xFF0000) | (((a)<<24)&0xFF000000)) +#define PROTO_MKID_BE(a) (a & 0xffffffff) + +#if defined(INVERSE_MKID) +# define MKID(a) PROTO_MKID_BE(a) +# define MKID_BE(a) PROTO_MKID(a) +#else +# define MKID(a) PROTO_MKID(a) +# define MKID_BE(a) PROTO_MKID_BE(a) +#endif + + +#if defined(SCUMM_NEED_ALIGNMENT) + FORCEINLINE uint READ_LE_UINT16(void *ptr) { + return (((byte*)ptr)[1]<<8)|((byte*)ptr)[0]; + } +#else + FORCEINLINE uint READ_LE_UINT16(void *ptr) { + return *(uint16*)(ptr); + } +#endif + +FORCEINLINE uint READ_BE_UINT16(void *ptr) { + return (((byte*)ptr)[0]<<8)|((byte*)ptr)[1]; +} + +#if defined(SCUMM_NEED_ALIGNMENT) + FORCEINLINE uint32 READ_LE_UINT32(void *ptr) { + byte *b = (byte*)ptr; + return (b[3]<<24)+(b[2]<<16)+(b[1]<<8)+(b[0]); + } +#else + FORCEINLINE uint32 READ_LE_UINT32(void *ptr) { + return *(uint32*)(ptr); + } +#endif + +FORCEINLINE uint32 READ_BE_UINT32(void *ptr) { + byte *b = (byte*)ptr; + return (b[0]<<24)+(b[1]<<16)+(b[2]<<8)+(b[3]); +} + +#define READ_BE_UINT32_UNALIGNED READ_BE_UINT32 +#define READ_BE_UINT16_UNALIGNED READ_BE_UINT16 + +#define READ_UINT32_UNALIGNED(a) READ_LE_UINT32(a) + +#define FROM_LE_32(__a__) __a__ +#define FROM_LE_16(__a__) __a__ + +#define TO_LE_32(__a__) __a__ +#define TO_LE_16(__a__) __a__ + +#define TO_BE_32(a) ((((a)>>24)&0xFF) | (((a)>>8)&0xFF00) | (((a)<<8)&0xFF0000) | (((a)<<24)&0xFF000000)) + +uint16 FORCEINLINE TO_BE_16(uint16 a) { return (a>>8) | (a<<8); } + +#elif defined(SCUMM_BIG_ENDIAN) + +#define MKID(a) (a) +#define MKID_BE(a) (a) +//#define MKID_BE(a) ((((a)>>24)&0xFF) | (((a)>>8)&0xFF00) | (((a)<<8)&0xFF0000) | (((a)<<24)&0xFF000000)) + +uint32 FORCEINLINE FROM_LE_32(uint32 a) { + return ((a>>24)&0xFF) + ((a>>8)&0xFF00) + ((a<<8)&0xFF0000) + ((a<<24)&0xFF000000); +} + +uint16 FORCEINLINE FROM_LE_16(uint16 a) { + return ((a>>8)&0xFF) + ((a<<8)&0xFF00); +} + +#define TO_LE_32 FROM_LE_32 +#define TO_LE_16 FROM_LE_16 + +uint32 FORCEINLINE READ_LE_UINT32(void *ptr) { + byte *b = (byte*)ptr; + return (b[3]<<24)+(b[2]<<16)+(b[1]<<8)+(b[0]); +} + +uint32 FORCEINLINE READ_BE_UINT32(void *ptr) { + return *(uint32*)(ptr); +} + +uint FORCEINLINE READ_LE_UINT16(void *ptr) { + byte *b = (byte*)ptr; + return (b[1]<<8) + b[0]; +} + +uint FORCEINLINE READ_BE_UINT16(void *ptr) { + return *(uint16*)(ptr); +} + +uint FORCEINLINE READ_BE_UINT16_UNALIGNED(void *ptr) { + return (((byte*)ptr)[0]<<8)|((byte*)ptr)[1]; +} + +uint32 FORCEINLINE READ_BE_UINT32_UNALIGNED(void *ptr) { + byte *b = (byte*)ptr; + return (b[0]<<24)+(b[1]<<16)+(b[2]<<8)+(b[3]); +} + +#define READ_UINT32_UNALIGNED READ_BE_UINT32_UNALIGNED + +#define TO_BE_32(a) (a) +#define TO_BE_16(a) (a) +#else + +#error No endianness defined + +#endif + + +#ifdef NEED_STRDUP +char *strdup(const char *s); +#endif + +/* Initialized operator new */ +void * operator new(size_t size); + +#endif diff --git a/common/stdafx.cpp b/common/stdafx.cpp new file mode 100644 index 0000000000..fd4f341c7b --- /dev/null +++ b/common/stdafx.cpp @@ -0,0 +1 @@ +#include "stdafx.h" diff --git a/common/stdafx.h b/common/stdafx.h new file mode 100644 index 0000000000..de4f0156ce --- /dev/null +++ b/common/stdafx.h @@ -0,0 +1,169 @@ +/* + * $Id$ + * + * $Log$ + * Revision 1.1 2002/08/21 16:07:23 fingolfin + * Initial revision + * + * Revision 1.18 2002/07/08 13:33:10 fingolfin + * two more small QNX fixes + * + * Revision 1.17 2002/06/02 20:28:09 bbrox + * Small warning fix + double inclusion protection (can always be useful + * :) ). + * + * Revision 1.16 2002/05/05 20:04:25 fingolfin + * cleaning up the mess drigo left... + * + * Revision 1.15 2002/05/05 19:06:51 drigo + * Fixed some things for Macintosh ports + * + * Revision 1.14 2002/04/18 21:40:23 tomjoad + * Reenable MorphOS Midi driver, small updates to CD open code (only when CD audio is requested) and start options + * + * Revision 1.13 2002/04/12 21:26:34 strigeus + * new video engine (expect broken non-sdl builds), + * simon the sorcerer 1 & 2 support (non SCUMM games) + * + * Revision 1.12 2002/03/14 22:45:22 arisme + * Minor changes to compile WinCE port + * + * Revision 1.11 2002/03/09 13:48:53 drigo + * Support for MacOS classic port + * + * Revision 1.10 2002/03/08 17:05:09 mutle + * Some changes, need to be done to get the Mac Port running. For example Point is now called ScummPoint, as the name Point is already in use by Apple. + * + * Revision 1.9 2002/03/06 12:24:56 ender + * Applied cleanup and scaling patch by Rob. + * + * Revision 1.8 2001/11/20 07:13:01 vasyl + * Added ability for ports to override all includes in stdafx.h. To use this feature + * port must define symbol NONSTANDARD_PORT. Port must also provide + * port-specific portdefs.h with all includes, symbol defines and everything else + * port needs. + * + * Revision 1.7 2001/11/11 16:54:45 strigeus + * implemented some sam&max specific features, + * fixed some bugs + * + * Revision 1.6 2001/11/06 22:59:59 cmatsuoka + * Re-added changes to allow cygwin and beos cross-compilation. + * + */ + +#ifndef _STDAFX_H +#define _STDAFX_H + +#if defined(NONSTANDARD_PORT) + +#include + +#elif defined(WIN32) + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + +#if !defined(_WIN32_WCE) + + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define NOGDICAPMASKS +#define OEMRESOURCE +#define NONLS +#define NOICONS +#define NOMCX +#define NOPROFILER +#define NOKANJI +#define NOSERVICE +#define NOMETAFILE +#define NOCOMM +#define NOCRYPT +#define NOIME +#define NOATOM +#define NOCTLMGR +#define NOCLIPBOARD +#define NOMEMMGR +#define NOSYSMETRICS +#define NOMENUS +#define NOOPENFILE +#define NOWH +#define NOSOUND +#define NODRAWTEXT + + +#endif + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#else + +#if defined(__MORPHOS__) +#include +#undef CMD_INVALID +#endif +#if !defined(macintosh) +#include +#include +#endif +#if !defined (__BEOS__) +#include +#endif +#if defined(__QNXNTO__) +#include /* For strcasecmp */ +#endif +#include +#include +#include +#include +#include +#include +#include + + +#endif + + +/* Semi-Platform-specific version info */ +#ifdef ALLOW_GDI +/* Assume Win32 GDI is used, then... */ +#define SCUMMVM_PLATFORM_VERSION "Win32 GDI version" + +#else +#ifdef ALLOW_X11 +/* Assume pure X11 is used, then... */ +#define SCUMMVM_PLATFORM_VERSION "X11 version" + +#else + +#ifdef MACOS_CARBON +#define SCUMMVM_PLATFORM_VERSION "Macintosh version" +#else + +#ifdef SDL_COMPILEDVERSION +#define SCUMMVM_PLATFORM_VERSION "SDL version" +//SDL_COMPILEDVERSION is a number... :( +//SDL_Linked_Version returns an SDL_Version structure... + +#endif +#endif +#endif +#endif + +#endif diff --git a/common/system.h b/common/system.h new file mode 100644 index 0000000000..b8255eff48 --- /dev/null +++ b/common/system.h @@ -0,0 +1,199 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001/2002 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#ifndef _SYSTEM_H +#define _SYSTEM_H + +/* Interface to what's below ScummVM */ + +class OSystem { +public: + typedef int ThreadProc(void *param); + typedef void SoundProc(void *param, byte *buf, int len); + + struct Event { + int event_code; + struct { + uint16 ascii; + byte flags; + int keycode; + } kbd; + struct { + int x,y; + } mouse; + }; + + enum { + EVENT_KEYDOWN = 1, + EVENT_KEYUP = 2, + EVENT_MOUSEMOVE = 3, + EVENT_LBUTTONDOWN = 4, + EVENT_LBUTTONUP = 5, + EVENT_RBUTTONDOWN = 6, + EVENT_RBUTTONUP = 7, + }; + + enum { + KBD_CTRL = 1, + KBD_ALT = 2, + KBD_SHIFT = 4, + }; + + enum { + PROP_TOGGLE_FULLSCREEN = 1, + PROP_SET_WINDOW_CAPTION = 2, + PROP_OPEN_CD = 3, + PROP_SET_GFX_MODE = 4, + PROP_SHOW_DEFAULT_CURSOR = 5, + PROP_GET_SAMPLE_RATE = 6, + PROP_GET_FULLSCREEN = 7 + }; + union Property { + char *caption; + int cd_num; + int gfx_mode; + bool show_cursor; + }; + + enum { + SOUND_8BIT = 0, + SOUND_16BIT = 1, + }; + + // Set colors of the palette + virtual void set_palette(const byte *colors, uint start, uint num) = 0; + + // Set the size of the video bitmap. + // Typically, 320x200 + virtual void init_size(uint w, uint h) = 0; + + // Draw a bitmap to screen. + // The screen will not be updated to reflect the new bitmap + virtual void copy_rect(const byte *buf, int pitch, int x, int y, int w, int h) = 0; + + // Update the dirty areas of the screen + virtual void update_screen() = 0; + + // Either show or hide the mouse cursor + virtual bool show_mouse(bool visible) = 0; + + // Set the position of the mouse cursor + virtual void set_mouse_pos(int x, int y) = 0; + + // Set the bitmap that's used when drawing the cursor. + virtual void set_mouse_cursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y) = 0; + + // Shaking is used in SCUMM. Set current shake position. + virtual void set_shake_pos(int shake_pos) = 0; + + // Get the number of milliseconds since the program was started. + virtual uint32 get_msecs() = 0; + + // Delay for a specified amount of milliseconds + virtual void delay_msecs(uint msecs) = 0; + + // Create a thread + virtual void *create_thread(ThreadProc *proc, void *param) = 0; + + // Get the next event. + // Returns true if an event was retrieved. + virtual bool poll_event(Event *event) = 0; + + // Set the function to be invoked whenever samples need to be generated + // Format is the sample type format. + // Only 16-bit signed mode is needed for simon & scumm + virtual bool set_sound_proc(void *param, SoundProc *proc, byte format) = 0; + + // Get or set a property + virtual uint32 property(int param, Property *value) = 0; + + // Poll cdrom status + // Returns true if cd audio is playing + virtual bool poll_cdrom() = 0; + + // Play cdrom audio track + virtual void play_cdrom(int track, int num_loops, int start_frame, int end_frame) = 0; + + // Stop cdrom audio track + virtual void stop_cdrom() = 0; + + // Update cdrom audio status + virtual void update_cdrom() = 0; + + // Add a new callback timer + virtual void set_timer(int timer, int (*callback)(int)) = 0; + + // Mutex handling + virtual void *create_mutex(void) = 0; + virtual void lock_mutex(void *mutex) = 0; + virtual void unlock_mutex(void *mutex) = 0; + virtual void delete_mutex(void *mutex) = 0; + + // Quit + virtual void quit() = 0; +}; + + +/* Factory functions. This means we don't have to include the + * OSystem_SDL header file. (which in turn would require the SDL headers) + */ + +/* OSystem_SDL */ +extern OSystem *OSystem_SDL_create(int gfx_driver, bool full_screen); +extern OSystem *OSystem_NULL_create(); +extern OSystem *OSystem_MorphOS_create(int game_id, int gfx_driver, bool full_screen); +extern OSystem *OSystem_Dreamcast_create(); +extern OSystem *OSystem_WINCE3_create(); +extern OSystem *OSystem_X11_create(); +extern OSystem *OSystem_MAC_create(int gfx_mode, bool full_screen); + +enum { + GFX_NORMAL = 0, + GFX_DOUBLESIZE = 1, + GFX_TRIPLESIZE = 2, + GFX_2XSAI = 3, + GFX_SUPER2XSAI = 4, + GFX_SUPEREAGLE = 5, + GFX_ADVMAME2X = 6 +}; + + +/* Graphics drivers */ +enum { + GD_NULL = 0, + GD_SDL, + GD_X, + GD_MORPHOS, + GD_WINCE, + GD_MAC, + GD_DC +}; + +enum { +#ifdef _WIN32_WCE + SAMPLES_PER_SEC = 11025 +#else + SAMPLES_PER_SEC = 22050 +#endif +}; + +#endif diff --git a/common/timer.cpp b/common/timer.cpp new file mode 100644 index 0000000000..2a3fc74024 --- /dev/null +++ b/common/timer.cpp @@ -0,0 +1,157 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2002 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + */ + +#include "stdafx.h" +#include "scumm.h" +#include "scummsys.h" +#include "timer.h" + +static Scumm * scumm; + +Timer::Timer(Scumm * parent) { + _initialized = false; + _timerRunning = false; + scumm = _scumm = parent; +} + +Timer::~Timer() { + release (); +} + +static int timer_handler (int t) +{ + scumm->_timer->handler (&t); + return t; +} + +int Timer::handler(int * t) { + uint32 interval, l; + + if (_timerRunning) { + _lastTime = _thisTime; + _thisTime = _osystem->get_msecs(); + interval = _thisTime - _lastTime; + + for (l = 0; l < MAX_TIMERS; l++) { + if ((_timerSlots[l].procedure) && (_timerSlots[l].interval > 0)) { + _timerSlots[l].counter -= interval; + if (_timerSlots[l].counter <= 0) { + _timerSlots[l].counter += _timerSlots[l].interval; + _timerSlots[l].procedure (_scumm); + } + } + } + } + + return *t; +} + +bool Timer::init() { + int32 l; + + _osystem = _scumm->_system; + if (_osystem == NULL) { + printf("Timer: OSystem not initialized !\n"); + return false; + } + + if (_initialized == true) + return true; + + for (l = 0; l < MAX_TIMERS; l++) { + _timerSlots[l].procedure = NULL; + _timerSlots[l].interval = 0; + _timerSlots[l].counter = 0; + } + + _thisTime = _osystem->get_msecs(); + _osystem->set_timer (10, &timer_handler); + + _timerRunning = true; + _initialized = true; + return true; +} + +void Timer::release() { + int32 l; + + if (_initialized == false) + return; + + _timerRunning = false; + _osystem->set_timer (0, NULL); + _initialized = false; + + for (l = 0; l < MAX_TIMERS; l++) { + _timerSlots[l].procedure = NULL; + _timerSlots[l].interval = 0; + _timerSlots[l].counter = 0; + } +} + +bool Timer::installProcedure (TimerProc procedure, int32 interval) { + int32 l; + bool found = false; + + if (_initialized == false) { + printf ("Timer: is not initialized !"); + return false; + } + + _timerRunning = false; + for (l = 0; l < MAX_TIMERS; l++) { + if (!_timerSlots[l].procedure) { + _timerSlots[l].procedure = procedure; + _timerSlots[l].interval = interval; + _timerSlots[l].counter = interval; + found = true; + break; + } + } + + _timerRunning = true; + if (!found) { + printf ("Can't find free slot !"); + return false; + } + + return true; +} + +void Timer::releaseProcedure (TimerProc procedure) { + int32 l; + + if (_initialized == false) { + printf ("Timer: is not initialized !"); + return; + } + + _timerRunning = false; + for (l = 0; l < MAX_TIMERS; l++) { + if (_timerSlots[l].procedure == procedure) { + _timerSlots[l].procedure = 0; + _timerSlots[l].interval = 0; + _timerSlots[l].counter = 0; + } + } + _timerRunning = true; +} + + diff --git a/common/timer.h b/common/timer.h new file mode 100644 index 0000000000..a4f4c7080d --- /dev/null +++ b/common/timer.h @@ -0,0 +1,66 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2002 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + */ + +#ifndef TIMER_H +#define TIMER_H + +#include "scummsys.h" + +#define MAX_TIMERS 5 + +typedef void (*TimerProc)(Scumm *); + +#ifdef __MORPHOS__ +#include "morphos/morphos_timer.h" +#else + +class OSystem; + +class Timer { + +private: + OSystem *_osystem; + Scumm *_scumm; + bool _initialized; + bool _timerRunning; + void *_timerHandler; + int32 _thisTime; + int32 _lastTime; + + struct TimerSlots { + TimerProc procedure; + int32 interval; + int32 counter; + } _timerSlots[MAX_TIMERS]; + +public: + Timer(Scumm *system); + ~Timer(); + + int handler(int *t); + bool init(); + void release(); + bool installProcedure(TimerProc procedure, int32 interval); + void releaseProcedure(TimerProc procedure); +}; + +#endif + +#endif diff --git a/common/util.cpp b/common/util.cpp new file mode 100644 index 0000000000..4a5d50e369 --- /dev/null +++ b/common/util.cpp @@ -0,0 +1,312 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2002 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + */ + +#include "stdafx.h" +#include "util.h" + +// 8-bit alpha blending routines +int BlendCache[256][256]; + +int RGBMatch(byte *palette, int r, int g, int b) +{ + int i, bestidx = 0, besterr = 0xFFFFFF; + int error = 0; + + for (i = 0;i < 256;i++) { + byte *pal = palette + (i * 3); + int r_diff = r - (int)*pal++; + int g_diff = g - (int)*pal++; + int b_diff = b - (int)*pal++; + r_diff *= r_diff; g_diff *= g_diff; b_diff *= b_diff; + + error = r_diff + g_diff + b_diff; + if (error < besterr) { + besterr = error; + bestidx = i; + } + } + return bestidx; +} + +int Blend(int src, int dst, byte *palette) +{ + int r, g, b; + int alpha = 128; // Level of transparency [0-256] + byte *srcpal = palette + (dst * 3); + byte *dstpal = palette + (src * 3); + + if (BlendCache[dst][src] > -1) + return BlendCache[dst][src]; + + r = (*srcpal++ * alpha); + r += (*dstpal++ * (256-alpha)); + r /= 256; + + g = (*srcpal++ * alpha); + g += (*dstpal++ * (256-alpha)); + g /= 256; + + b = (*srcpal++ * alpha); + b += (*dstpal++ * (256-alpha)); + b /= 256; + + return (BlendCache[dst][src] = RGBMatch(palette, r , g , b )); +} + +void ClearBlendCache(byte *palette, int weight) +{ + for (int i = 0; i < 256; i++) + for (int j = 0 ; j < 256 ; j++) +// BlendCache[i][j] = i; // No alphablending +// BlendCache[i][j] = j; // 100% translucent + BlendCache[i][j] = -1; // Enable alphablending +} + + +#pragma mark - + +/* + * Print hexdump of the data passed in, 8 bytes a row + */ +void hexdump(const byte * data, int len) +{ + int i; + byte c; + while (len >= 8) { + for (i = 0; i < 8; i++) + printf("%02x ", data[i]); + printf(" |"); + for (i = 0; i < 8; i++) { + c = data[i]; + if (c < 32 || c > 127) + c = '.'; + printf("%c", c); + } + printf("|\n"); + data += 8; + len -= 8; + } + + if (len <= 0) + return; + + for (i = 0; i < len; i++) + printf("%02x ", data[i]); + for (; i < 8; i++) + printf(" "); + printf(" |"); + for (i = 0; i < len; i++) { + c = data[i]; + if (c < 32 || c > 127) + c = '.'; + printf("%c", c); + } + for (; i < 8; i++) + printf(" "); + printf("|\n"); +} + + +#pragma mark - + + +namespace ScummVM { + +String::String(const char *str) +{ + _refCount = new int(1); + _capacity = _len = strlen(str); + _str = (char *)calloc(1, _capacity+1); + memcpy(_str, str, _len+1); +} + +String::String(const String &str) +{ + ++(*str._refCount); + + _refCount = str._refCount; + _capacity = str._capacity; + _len = str._capacity; + _str = str._str; +} + +String::~String() +{ + decRefCount(); +} + +void String::decRefCount() +{ + --(*_refCount); + if (*_refCount <= 0) { + delete _refCount; + if (_str) + free(_str); + } +} + +String& String::operator =(const char* str) +{ + int len = strlen(str); + if (len > 0) { + ensureCapacity(len, false); + + _len = len; + memcpy(_str, str, _len + 1); + } else if (_len > 0) { + decRefCount(); + + _refCount = new int(1); + _capacity = 0; + _len = 0; + _str = 0; + } + return *this; +} + +String& String::operator =(const String& str) +{ + ++(*str._refCount); + + decRefCount(); + + _refCount = str._refCount; + _capacity = str._capacity; + _len = str._len; + _str = str._str; + + return *this; +} + +String& String::operator +=(const char* str) +{ + int len = strlen(str); + if (len > 0) { + ensureCapacity(_len + len, true); + + memcpy(_str + _len, str, len + 1); + _len += len; + } + return *this; +} + +String& String::operator +=(const String& str) +{ + int len = str._len; + if (len > 0) { + ensureCapacity(_len + len, true); + + memcpy(_str + _len, str._str, len + 1); + _len += len; + } + return *this; +} + +String& String::operator +=(char c) +{ + ensureCapacity(_len + 1, true); + + _str[_len++] = c; + _str[_len] = 0; + + return *this; +} + +bool String::operator ==(const String& x) +{ + return (_len == x._len) && ((_len == 0) || (0 == strcmp(_str, x._str))); +} + +bool String::operator ==(const char* x) +{ + if (_str == 0) + return (x == 0) || (*x == 0); + if (x == 0) + return (_len == 0); + return (0 != strcmp(_str, x)); +} + +bool String::operator !=(const String& x) +{ + return (_len != x._len) || ((_len != 0) && (0 != strcmp(_str, x._str))); +} + +bool String::operator !=(const char* x) +{ + if (_str == 0) + return (x != 0) && (*x != 0); + if (x == 0) + return (_len != 0); + return (0 == strcmp(_str, x)); +} + + +void String::deleteLastChar() { + if (_len > 0) { + ensureCapacity(_len - 1, true); + _str[--_len] = 0; + } +} + +void String::clear() +{ + if (_capacity) { + decRefCount(); + + _refCount = new int(1); + _capacity = 0; + _len = 0; + _str = 0; + } +} + +void String::ensureCapacity(int new_len, bool keep_old) +{ + // If there is not enough space, or if we are not the only owner + // of the current data, then we have to reallocate it. + if (new_len <= _capacity && *_refCount == 1) + return; + + int newCapacity = (new_len <= _capacity) ? _capacity : new_len + 32; + char *newStr = (char *)calloc(1, newCapacity+1); + + if (keep_old && _str) + memcpy(newStr, _str, _len + 1); + else + _len = 0; + + decRefCount(); + + _refCount = new int(1); + _capacity = newCapacity; + _str = newStr; +} + +bool operator == (const char* y, const String& x) +{ + return x == y; +} + +bool operator != (const char* y, const String& x) +{ + return x != y; +} + +}; // End of namespace ScummVM diff --git a/common/util.h b/common/util.h new file mode 100644 index 0000000000..0f74ede00f --- /dev/null +++ b/common/util.h @@ -0,0 +1,183 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2002 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + */ + +#ifndef UTIL_H +#define UTIL_H + +#include "scummsys.h" + +int RGBMatch(byte *palette, int r, int g, int b); +int Blend(int src, int dst, byte *palette); +void ClearBlendCache(byte *palette, int weight); + +/* + * Print hexdump of the data passed in, 8 bytes a row + */ +void hexdump(const byte * data, int len); + + +namespace ScummVM { + +template +class List { +protected: + int _capacity; + int _size; + T *_data; + +public: + List() : _capacity(0), _size(0), _data(0) {} + List(const List& list) : _capacity(0), _size(0), _data(0) + { + _size = list._size; + _capacity = _size + 32; + _data = new T[_capacity]; + for (int i = 0; i < _size; i++) + _data[i] = list._data[i]; + } + + ~List() + { + if (_data) + delete [] _data; + } + + void push_back(const T& str) + { + ensureCapacity(_size + 1); + _data[_size++] = str; + } + + // TODO: insert, remove, ... + + T& operator [](int idx) + { + assert(idx >= 0 && idx < _size); + return _data[idx]; + } + + const T& operator [](int idx) const + { + assert(idx >= 0 && idx < _size); + return _data[idx]; + } + + List& operator =(const List& list) + { + if (_data) + delete [] _data; + _size = list._size; + _capacity = _size + 32; + _data = new T[_capacity]; + for (int i = 0; i < _size; i++) + _data[i] = list._data[i]; + + return *this; + } + + int size() const { return _size; } + + void clear() + { + if (_data) { + delete [] _data; + _data = 0; + } + _size = 0; + _capacity = 0; + } + + bool isEmpty() const { return (_size == 0); } + +protected: + void ensureCapacity(int new_len) + { + if (new_len <= _capacity) + return; + + T *old_data = _data; + _capacity = new_len + 32; + _data = new T[_capacity]; + + if (old_data) { + // Copy old data + for (int i = 0; i < _size; i++) + _data[i] = old_data[i]; + delete [] old_data; + } + } +}; + + +class String { +protected: + int *_refCount; + int _capacity; + int _len; + char *_str; +public: + String() : _capacity(0), _len(0), _str(0) { _refCount = new int(1); } + String(const char *str); + String(const String &str); + ~String(); + + String& operator =(const char* str); + String& operator =(const String& str); + String& operator +=(const char* str); + String& operator +=(const String& str); + String& operator +=(char c); + + bool operator ==(const String& x); + bool operator ==(const char* x); + bool operator !=(const String& x); + bool operator !=(const char* x); + +// operator char *() { return _str; } + operator const char *() const { return _str; } + const char *c_str() const { return _str; } + int size() const { return _len; } + + void deleteLastChar(); + void clear(); + + bool isEmpty() const { return (_len == 0); } + +protected: + void ensureCapacity(int new_len, bool keep_old); + void decRefCount(); +}; + +// Some useful additional comparision operators for Strings +bool operator == (const char* x, const String& y); +bool operator != (const char* x, const String& y); + +class StringList : public List { +public: + void push_back(const char* str) + { + ensureCapacity(_size + 1); + _data[_size] = str; + _size++; + } +}; + +}; // End of namespace ScummVM + +#endif -- cgit v1.2.3