Initial commit
This commit is contained in:
126
engines/ultima/ultima4/core/config.cpp
Normal file
126
engines/ultima/ultima4/core/config.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ultima/ultima4/core/config.h"
|
||||
#include "ultima/ultima4/core/settings.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
Config *Config::_instance;
|
||||
|
||||
Config::Config() {
|
||||
_instance = this;
|
||||
|
||||
if (!_doc.readConfigFile("data/conf/config.xml"))
|
||||
error("Failed to read core configuration");
|
||||
}
|
||||
|
||||
Config::~Config() {
|
||||
_instance = nullptr;
|
||||
}
|
||||
|
||||
ConfigElement Config::getElement(const Common::String &name) const {
|
||||
Common::String key = Common::String::format("config/%s", name.c_str());
|
||||
const Shared::XMLNode *node = _doc.getNode(key);
|
||||
assert(node);
|
||||
return ConfigElement(node);
|
||||
}
|
||||
|
||||
Std::vector<Common::String> Config::getGames() {
|
||||
Std::vector<Common::String> result;
|
||||
result.push_back("Ultima IV");
|
||||
return result;
|
||||
}
|
||||
|
||||
void Config::setGame(const Common::String &name) {
|
||||
// No implementation
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
ConfigElement::ConfigElement(const Shared::XMLNode *xmlNode) :
|
||||
_node(xmlNode), _name(xmlNode->id().c_str()) {
|
||||
}
|
||||
|
||||
ConfigElement::ConfigElement(const ConfigElement &e) : _node(e._node), _name(e._name) {
|
||||
}
|
||||
|
||||
ConfigElement::ConfigElement() : _node(nullptr) {
|
||||
}
|
||||
|
||||
ConfigElement::~ConfigElement() {
|
||||
}
|
||||
|
||||
ConfigElement &ConfigElement::operator=(const ConfigElement &e) {
|
||||
if (&e != this) {
|
||||
_node = e._node;
|
||||
_name = e._name;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool ConfigElement::exists(const Common::String &name) const {
|
||||
return !(*_node)[name].empty();
|
||||
}
|
||||
|
||||
Common::String ConfigElement::getString(const Common::String &name) const {
|
||||
return (*_node)[name];
|
||||
}
|
||||
|
||||
int ConfigElement::getInt(const Common::String &name, int defaultValue) const {
|
||||
Common::String str = (*_node)[name];
|
||||
return str.empty() ? defaultValue : atol(str.c_str());
|
||||
}
|
||||
|
||||
bool ConfigElement::getBool(const Common::String &name) const {
|
||||
Common::String str = (*_node)[name];
|
||||
if (str.empty())
|
||||
return false;
|
||||
|
||||
return toupper(str[0]) == 'T' || str == "1";
|
||||
}
|
||||
|
||||
int ConfigElement::getEnum(const Common::String &name, const char *const enumValues[]) const {
|
||||
Common::String str = (*_node)[name];
|
||||
if (str.empty())
|
||||
return 0;
|
||||
|
||||
for (int i = 0; enumValues[i]; ++i) {
|
||||
if (str.equalsIgnoreCase(enumValues[i]))
|
||||
return i;
|
||||
}
|
||||
|
||||
error("invalid enum value for %s: %s", name.c_str(), str.c_str());
|
||||
}
|
||||
|
||||
Std::vector<ConfigElement> ConfigElement::getChildren() const {
|
||||
const Common::Array<Shared::XMLNode *> &children = _node->children();
|
||||
Std::vector<ConfigElement> result;
|
||||
|
||||
for (const auto &c : children)
|
||||
result.push_back(c);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
159
engines/ultima/ultima4/core/config.h
Normal file
159
engines/ultima/ultima4/core/config.h
Normal file
@@ -0,0 +1,159 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ULTIMA4_CORE_CONFIG_H
|
||||
#define ULTIMA4_CORE_CONFIG_H
|
||||
|
||||
#include "ultima/shared/conf/xml_tree.h"
|
||||
#include "ultima/shared/conf/xml_node.h"
|
||||
#include "ultima/shared/std/containers.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
/* info for loading city data from *.ult and *.tlk */
|
||||
#define CITY_HEIGHT 32
|
||||
#define CITY_WIDTH 32
|
||||
#define CITY_MAX_PERSONS 32
|
||||
|
||||
/* info for loading area data from *.con */
|
||||
#define CON_HEIGHT 11
|
||||
#define CON_WIDTH 11
|
||||
|
||||
/* info for loading dungeon map data from *.dng */
|
||||
#define DNG_HEIGHT 8
|
||||
#define DNG_WIDTH 8
|
||||
|
||||
/* info for loading image data from shapes.ega */
|
||||
#define N_TILES 256
|
||||
#define TILE_WIDTH (2 * CHAR_WIDTH)
|
||||
#define TILE_HEIGHT (2 * CHAR_HEIGHT)
|
||||
|
||||
/* info for loading image data from charset.ega */
|
||||
#define CHAR_WIDTH 8
|
||||
#define CHAR_HEIGHT 8
|
||||
|
||||
/* some character defines */
|
||||
#define CHARSET_ANKH '\0'
|
||||
#define CHARSET_REDDOT '\01'
|
||||
#define CHARSET_SDOOR '\02'
|
||||
#define CHARSET_WALL '\03'
|
||||
#define CHARSET_LADDER_UPDOWN '\04'
|
||||
#define CHARSET_LADDER_DOWN '\05'
|
||||
#define CHARSET_LADDER_UP '\06'
|
||||
#define CHARSET_BULLET '\010'
|
||||
#define CHARSET_COPYRIGHT '\011'
|
||||
#define CHARSET_REGISTERED '\012'
|
||||
#define CHARSET_MALE '\013'
|
||||
#define CHARSET_FEMALE '\014'
|
||||
#define CHARSET_HORIZBAR '\015'
|
||||
#define CHARSET_ROOM '\016'
|
||||
#define CHARSET_ORB '\017'
|
||||
#define CHARSET_PROMPT '\020'
|
||||
#define CHARSET_FLOOR '\022'
|
||||
|
||||
/* map viewport size (in tiles) */
|
||||
#define VIEWPORT_W 11
|
||||
#define VIEWPORT_H 11
|
||||
|
||||
/* screen border size (in pixels) */
|
||||
#define BORDER_WIDTH 8
|
||||
#define BORDER_HEIGHT 8
|
||||
|
||||
/* text area (in character units) */
|
||||
#define TEXT_AREA_X 24
|
||||
#define TEXT_AREA_Y 12
|
||||
#define TEXT_AREA_W 16
|
||||
#define TEXT_AREA_H 12
|
||||
|
||||
/* moons/moongates */
|
||||
#define MOON_PHASES 24
|
||||
#define MOON_SECONDS_PER_PHASE 4
|
||||
#define MOON_CHAR 20
|
||||
|
||||
/* wind */
|
||||
#define WIND_AREA_X 7
|
||||
#define WIND_AREA_Y 23
|
||||
#define WIND_AREA_W 10
|
||||
#define WIND_AREA_H 1
|
||||
#define WIND_SECONDS_PER_PHASE 1
|
||||
|
||||
|
||||
class ConfigElement;
|
||||
|
||||
/**
|
||||
* Singleton class that manages the XML configuration tree.
|
||||
*/
|
||||
class Config {
|
||||
private:
|
||||
static Config *_instance;
|
||||
Shared::XMLTree _doc;
|
||||
public:
|
||||
static const Config *getInstance() {
|
||||
return _instance;
|
||||
}
|
||||
public:
|
||||
Config();
|
||||
~Config();
|
||||
|
||||
ConfigElement getElement(const Common::String &name) const;
|
||||
|
||||
static Std::vector<Common::String> getGames();
|
||||
static void setGame(const Common::String &name);
|
||||
};
|
||||
|
||||
/**
|
||||
* A single configuration element in the config tree. Right now, a
|
||||
* thin wrapper around the XML DOM element.
|
||||
*/
|
||||
class ConfigElement {
|
||||
private:
|
||||
const Shared::XMLNode *_node;
|
||||
Common::String _name;
|
||||
public:
|
||||
ConfigElement(const Shared::XMLNode *xmlNode);
|
||||
ConfigElement(const ConfigElement &e);
|
||||
ConfigElement();
|
||||
~ConfigElement();
|
||||
|
||||
ConfigElement &operator=(const ConfigElement &e);
|
||||
|
||||
const Common::String getName() const {
|
||||
return _name;
|
||||
}
|
||||
|
||||
bool exists(const Common::String &name) const;
|
||||
Common::String getString(const Common::String &name) const;
|
||||
int getInt(const Common::String &name, int defaultValue = 0) const;
|
||||
bool getBool(const Common::String &name) const;
|
||||
int getEnum(const Common::String &name, const char *const enumValues[]) const;
|
||||
|
||||
Std::vector<ConfigElement> getChildren() const;
|
||||
|
||||
const Shared::XMLNode *getNode() const {
|
||||
return _node;
|
||||
}
|
||||
};
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
||||
48
engines/ultima/ultima4/core/coords.h
Normal file
48
engines/ultima/ultima4/core/coords.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ULTIMA4_CORE_COORDS_H
|
||||
#define ULTIMA4_CORE_COORDS_H
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
/**
|
||||
* A simple representation of a point in 3D space.
|
||||
*/
|
||||
class Coords {
|
||||
public:
|
||||
int x, y, z;
|
||||
|
||||
Coords(int initx = 0, int inity = 0, int initz = 0) : x(initx), y(inity), z(initz) {}
|
||||
|
||||
bool operator==(const Coords &a) const {
|
||||
return x == a.x && y == a.y && z == a.z;
|
||||
}
|
||||
bool operator!=(const Coords &a) const {
|
||||
return !operator==(a);
|
||||
}
|
||||
};
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
||||
2002
engines/ultima/ultima4/core/debugger.cpp
Normal file
2002
engines/ultima/ultima4/core/debugger.cpp
Normal file
File diff suppressed because it is too large
Load Diff
433
engines/ultima/ultima4/core/debugger.h
Normal file
433
engines/ultima/ultima4/core/debugger.h
Normal file
@@ -0,0 +1,433 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ULTIMA4_CORE_DEBUGGER_H
|
||||
#define ULTIMA4_CORE_DEBUGGER_H
|
||||
|
||||
#include "ultima/ultima4/core/coords.h"
|
||||
#include "ultima/ultima4/core/types.h"
|
||||
#include "ultima/ultima4/core/debugger_actions.h"
|
||||
#include "gui/debugger.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
/**
|
||||
* Debugger base class
|
||||
*/
|
||||
class Debugger : public GUI::Debugger, public DebuggerActions {
|
||||
private:
|
||||
MapTile _horse, _ship, _balloon;
|
||||
bool _dontEndTurn;
|
||||
protected:
|
||||
/**
|
||||
* Returns true if the debugger is active
|
||||
*/
|
||||
bool isDebuggerActive() const override {
|
||||
return isActive();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the given command line.
|
||||
* Returns true if and only if argv[0] is a known command and was
|
||||
* handled, false otherwise.
|
||||
*/
|
||||
bool handleCommand(int argc, const char **argv, bool &keepRunning) override;
|
||||
|
||||
/**
|
||||
* Prints a message to the console if it's active, or to the
|
||||
* game screen if not
|
||||
*/
|
||||
void print(const char *fmt, ...) override;
|
||||
|
||||
/**
|
||||
* Prints a message to the console if it's active, or to the
|
||||
* game screen if not, with no newline
|
||||
*/
|
||||
void printN(const char *fmt, ...) override;
|
||||
|
||||
/**
|
||||
* Prompts for input, but only if debugger isn't running
|
||||
*/
|
||||
void prompt() override;
|
||||
|
||||
/**
|
||||
* Gets the direction for an action
|
||||
*/
|
||||
Direction getDirection(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Used by methods so that when they're triggered by a keybinding
|
||||
* action, stops the turn from being finished when they're done
|
||||
*/
|
||||
void dontEndTurn() {
|
||||
_dontEndTurn = true;
|
||||
}
|
||||
private:
|
||||
/**
|
||||
* Move the avatar in a given direction
|
||||
*/
|
||||
bool cmdMove(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Attack
|
||||
*/
|
||||
bool cmdAttack(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Board transport
|
||||
*/
|
||||
bool cmdBoard(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Cast spell
|
||||
*/
|
||||
bool cmdCastSpell(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Climb
|
||||
*/
|
||||
bool cmdClimb(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Descend
|
||||
*/
|
||||
bool cmdDescend(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Enter location
|
||||
*/
|
||||
bool cmdEnter(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Exit
|
||||
*/
|
||||
bool cmdExit(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Fire
|
||||
*/
|
||||
bool cmdFire(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Get chest
|
||||
*/
|
||||
bool cmdGetChest(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Hole Up & Camp
|
||||
*/
|
||||
bool cmdCamp(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Ignite Torch
|
||||
*/
|
||||
bool cmdIgnite(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Generic interaction
|
||||
*/
|
||||
bool cmdInteract(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Jimmy lock
|
||||
*/
|
||||
bool cmdJimmy(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Locate position
|
||||
*/
|
||||
bool cmdLocate(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Mix reagents
|
||||
*/
|
||||
bool cmdMixReagents(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Exchanges the position of two players in the party. Prompts the
|
||||
* user for the player numbers.
|
||||
*/
|
||||
bool cmdNewOrder(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Open door
|
||||
*/
|
||||
bool cmdOpenDoor(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Specifies a particular party number
|
||||
*/
|
||||
bool cmdParty(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Pass turn
|
||||
*/
|
||||
bool cmdPass(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Peer
|
||||
*/
|
||||
bool cmdPeer(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Save and quit
|
||||
*/
|
||||
bool cmdQuitAndSave(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Readies a weapon for a player. Prompts for the player and/or the
|
||||
* weapon if not provided.
|
||||
*/
|
||||
bool cmdReadyWeapon(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Search
|
||||
*/
|
||||
bool cmdSearch(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Speed up, down, or normal
|
||||
*/
|
||||
bool cmdSpeed(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Combat speed up, down, or normal
|
||||
*/
|
||||
bool cmdCombatSpeed(int argc, const char **argv);
|
||||
|
||||
|
||||
/**
|
||||
* Show character stats
|
||||
*/
|
||||
bool cmdStats(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Talk
|
||||
*/
|
||||
bool cmdTalk(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Use
|
||||
*/
|
||||
bool cmdUse(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Changes a player's armor
|
||||
*/
|
||||
bool cmdWearArmor(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Yell
|
||||
*/
|
||||
bool cmdYell(int argc, const char **argv);
|
||||
private:
|
||||
/**
|
||||
* Collision detection on/off
|
||||
*/
|
||||
bool cmd3d(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Teleports to the Abyss final altar
|
||||
*/
|
||||
bool cmdAbyss(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Collision detection on/off
|
||||
*/
|
||||
bool cmdCollisions(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Have all the companions join the party
|
||||
*/
|
||||
bool cmdCompanions(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Toggle whether combat occurs
|
||||
*/
|
||||
bool cmdCombat(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Destroy an object
|
||||
*/
|
||||
bool cmdDestroy(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Destroy all creatures
|
||||
*/
|
||||
bool cmdDestroyCreatures(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Jumps to a given dungeon
|
||||
*/
|
||||
bool cmdDungeon(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Flee from combat
|
||||
*/
|
||||
bool cmdFlee(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* All equipement
|
||||
*/
|
||||
bool cmdEquipment(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Full stats
|
||||
*/
|
||||
bool cmdFullStats(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Toggle hunger on or off
|
||||
*/
|
||||
bool cmdHunger(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Moongate teleportation
|
||||
*/
|
||||
bool cmdGate(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Go to any specified location by name
|
||||
*/
|
||||
bool cmdGoto(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Help.. sends the party to Lord British
|
||||
*/
|
||||
bool cmdLorddBritish(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Grant karma
|
||||
*/
|
||||
bool cmdKarma(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Give all the items
|
||||
*/
|
||||
bool cmdItems(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Leave the current location
|
||||
*/
|
||||
bool cmdLeave(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Displays the current location
|
||||
*/
|
||||
bool cmdLocation(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Give all the mixtures
|
||||
*/
|
||||
bool cmdMixtures(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Moon phase
|
||||
*/
|
||||
bool cmdMoon(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Toggle opacity
|
||||
*/
|
||||
bool cmdOpacity(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Toggle overhead view
|
||||
*/
|
||||
bool cmdOverhead(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Give all the reagents
|
||||
*/
|
||||
bool cmdReagents(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Summons a creature to fight
|
||||
*/
|
||||
bool cmdSummon(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Returns the torch duration
|
||||
*/
|
||||
bool cmdTorch(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Creates a given transport
|
||||
*/
|
||||
bool cmdTransport(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Move up a floor
|
||||
*/
|
||||
bool cmdUp(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Move down a floor
|
||||
*/
|
||||
bool cmdDown(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Gives full virtue, or increments a specific virtue
|
||||
*/
|
||||
bool cmdVirtue(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Set wind direction or locks the direction
|
||||
*/
|
||||
bool cmdWind(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Lists the triggers in a dungeon room
|
||||
*/
|
||||
bool cmdListTriggers(int argc, const char **argv);
|
||||
public:
|
||||
bool _collisionOverride;
|
||||
bool _disableHunger;
|
||||
bool _disableCombat;
|
||||
public:
|
||||
Debugger();
|
||||
~Debugger() override;
|
||||
|
||||
/**
|
||||
* Gets a chest.
|
||||
* If the default -2 is used, it bypasses prompting for a
|
||||
* user. Otherwise, a non-negative player number is expected
|
||||
*/
|
||||
void getChest(int player = -2);
|
||||
|
||||
/**
|
||||
* Executes the given command
|
||||
*/
|
||||
void executeCommand(const Common::String &cmd);
|
||||
|
||||
/**
|
||||
* Executes the given command
|
||||
*/
|
||||
void executeCommand(int argc, const char **argv);
|
||||
};
|
||||
|
||||
extern Debugger *g_debugger;
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
||||
501
engines/ultima/ultima4/core/debugger_actions.cpp
Normal file
501
engines/ultima/ultima4/core/debugger_actions.cpp
Normal file
@@ -0,0 +1,501 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ultima/ultima4/core/debugger_actions.h"
|
||||
#include "ultima/ultima4/core/config.h"
|
||||
#include "ultima/ultima4/core/utils.h"
|
||||
#include "ultima/ultima4/controllers/combat_controller.h"
|
||||
#include "ultima/ultima4/controllers/read_choice_controller.h"
|
||||
#include "ultima/ultima4/controllers/read_int_controller.h"
|
||||
#include "ultima/ultima4/controllers/reagents_menu_controller.h"
|
||||
#include "ultima/ultima4/conversation/conversation.h"
|
||||
#include "ultima/ultima4/game/context.h"
|
||||
#include "ultima/ultima4/game/player.h"
|
||||
#include "ultima/ultima4/views/stats.h"
|
||||
#include "ultima/ultima4/gfx/screen.h"
|
||||
#include "ultima/ultima4/gfx/textcolor.h"
|
||||
#include "ultima/ultima4/map/annotation.h"
|
||||
#include "ultima/ultima4/map/city.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
void DebuggerActions::summonCreature(const Common::String &name) {
|
||||
const Creature *m = nullptr;
|
||||
Common::String creatureName = name;
|
||||
|
||||
creatureName.trim();
|
||||
if (creatureName.empty()) {
|
||||
print("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* find the creature by its id and spawn it */
|
||||
uint id = atoi(creatureName.c_str());
|
||||
if (id > 0)
|
||||
m = creatureMgr->getById(id);
|
||||
|
||||
if (!m)
|
||||
m = creatureMgr->getByName(creatureName);
|
||||
|
||||
if (m) {
|
||||
if (gameSpawnCreature(m))
|
||||
print("\n%s summoned!\n", m->getName().c_str());
|
||||
else
|
||||
print("\n\nNo place to put %s!\n\n", m->getName().c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
print("\n%s not found\n", creatureName.c_str());
|
||||
}
|
||||
|
||||
Direction DebuggerActions::directionFromName(const Common::String &dirStr) {
|
||||
Common::String dir = dirStr;
|
||||
dir.toLowercase();
|
||||
|
||||
if (dir == "up" || dir == "north")
|
||||
return DIR_NORTH;
|
||||
else if (dir == "down" || dir == "south")
|
||||
return DIR_SOUTH;
|
||||
else if (dir == "right" || dir == "east")
|
||||
return DIR_EAST;
|
||||
else if (dir == "left" || dir == "west")
|
||||
return DIR_WEST;
|
||||
|
||||
return DIR_NONE;
|
||||
}
|
||||
|
||||
bool DebuggerActions::destroyAt(const Coords &coords) {
|
||||
Object *obj = g_context->_location->_map->objectAt(coords);
|
||||
|
||||
if (obj) {
|
||||
if (isCreature(obj)) {
|
||||
Creature *c = dynamic_cast<Creature *>(obj);
|
||||
assert(c);
|
||||
g_screen->screenMessage("%s Destroyed!\n", c->getName().c_str());
|
||||
} else {
|
||||
Tile *t = g_context->_location->_map->_tileSet->get(obj->getTile()._id);
|
||||
g_screen->screenMessage("%s Destroyed!\n", t->getName().c_str());
|
||||
}
|
||||
|
||||
g_context->_location->_map->removeObject(obj);
|
||||
g_screen->screenPrompt();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DebuggerActions::getChestTrapHandler(int player) {
|
||||
TileEffect trapType;
|
||||
int randNum = xu4_random(4);
|
||||
|
||||
/* Do we use u4dos's way of trap-determination, or the original intended way? */
|
||||
int passTest = (settings._enhancements && settings._enhancementsOptions._c64ChestTraps) ?
|
||||
(xu4_random(2) == 0) : /* xu4-enhanced */
|
||||
((randNum & 1) == 0); /* u4dos original way (only allows even numbers through, so only acid and poison show) */
|
||||
|
||||
/* Chest is trapped! 50/50 chance */
|
||||
if (passTest) {
|
||||
/* Figure out which trap the chest has */
|
||||
switch (randNum & xu4_random(4)) {
|
||||
case 0:
|
||||
trapType = EFFECT_FIRE;
|
||||
break; /* acid trap (56% chance - 9/16) */
|
||||
case 1:
|
||||
trapType = EFFECT_SLEEP;
|
||||
break; /* sleep trap (19% chance - 3/16) */
|
||||
case 2:
|
||||
trapType = EFFECT_POISON;
|
||||
break; /* poison trap (19% chance - 3/16) */
|
||||
case 3:
|
||||
trapType = EFFECT_LAVA;
|
||||
break; /* bomb trap (6% chance - 1/16) */
|
||||
default:
|
||||
trapType = EFFECT_FIRE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* apply the effects from the trap */
|
||||
if (trapType == EFFECT_FIRE)
|
||||
g_screen->screenMessage("%cAcid%c Trap!\n", FG_RED, FG_WHITE);
|
||||
else if (trapType == EFFECT_POISON)
|
||||
g_screen->screenMessage("%cPoison%c Trap!\n", FG_GREEN, FG_WHITE);
|
||||
else if (trapType == EFFECT_SLEEP)
|
||||
g_screen->screenMessage("%cSleep%c Trap!\n", FG_PURPLE, FG_WHITE);
|
||||
else if (trapType == EFFECT_LAVA)
|
||||
g_screen->screenMessage("%cBomb%c Trap!\n", FG_RED, FG_WHITE);
|
||||
|
||||
// player is < 0 during the 'O'pen spell (immune to traps)
|
||||
//
|
||||
// if the chest was opened by a PC, see if the trap was
|
||||
// evaded by testing the PC's dex
|
||||
//
|
||||
if ((player >= 0) &&
|
||||
(g_ultima->_saveGame->_players[player]._dex + 25 < xu4_random(100))) {
|
||||
if (trapType == EFFECT_LAVA) /* bomb trap */
|
||||
g_context->_party->applyEffect(trapType);
|
||||
else
|
||||
g_context->_party->member(player)->applyEffect(trapType);
|
||||
} else {
|
||||
g_screen->screenMessage("Evaded!\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DebuggerActions::jimmyAt(const Coords &coords) {
|
||||
MapTile *tile = g_context->_location->_map->tileAt(coords, WITH_OBJECTS);
|
||||
|
||||
if (!tile->getTileType()->isLockedDoor())
|
||||
return false;
|
||||
|
||||
if (g_ultima->_saveGame->_keys) {
|
||||
Tile *door = g_context->_location->_map->_tileSet->getByName("door");
|
||||
assertMsg(door, "no door tile found in tileset");
|
||||
g_ultima->_saveGame->_keys--;
|
||||
g_context->_location->_map->_annotations->add(coords, door->getId());
|
||||
g_screen->screenMessage("\nUnlocked!\n");
|
||||
} else
|
||||
g_screen->screenMessage("%cNo keys left!%c\n", FG_GREY, FG_WHITE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DebuggerActions::mixReagentsForSpellU4(int spell) {
|
||||
Ingredients ingredients;
|
||||
|
||||
g_screen->screenMessage("Reagent: ");
|
||||
|
||||
while (1) {
|
||||
int choice = ReadChoiceController::get("abcdefgh\n\r \033");
|
||||
|
||||
// done selecting reagents? mix it up and prompt to mix
|
||||
// another spell
|
||||
if (choice == '\n' || choice == '\r' || choice == ' ') {
|
||||
g_screen->screenMessage("\n\nYou mix the Reagents, and...\n");
|
||||
|
||||
if (g_spells->spellMix(spell, &ingredients))
|
||||
g_screen->screenMessage("Success!\n\n");
|
||||
else
|
||||
g_screen->screenMessage("It Fizzles!\n\n");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// escape: put ingredients back and quit mixing
|
||||
if (choice == -1 || choice == '\033') {
|
||||
ingredients.revert();
|
||||
return true;
|
||||
}
|
||||
|
||||
g_screen->screenMessage("\n");
|
||||
if (!ingredients.addReagent((Reagent)(choice - 'a')))
|
||||
g_screen->screenMessage("%cNone Left!%c\n", FG_GREY, FG_WHITE);
|
||||
g_screen->screenMessage("Reagent: ");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DebuggerActions::mixReagentsForSpellU5(int spell) {
|
||||
Ingredients ingredients;
|
||||
|
||||
g_screen->screenDisableCursor();
|
||||
|
||||
g_context->_stats->getReagentsMenu()->reset(); // reset the menu, highlighting the first item
|
||||
ReagentsMenuController getReagentsController(g_context->_stats->getReagentsMenu(), &ingredients, g_context->_stats->getMainArea());
|
||||
eventHandler->pushController(&getReagentsController);
|
||||
getReagentsController.waitFor();
|
||||
|
||||
g_context->_stats->getMainArea()->disableCursor();
|
||||
g_screen->screenEnableCursor();
|
||||
|
||||
printN("How many? ");
|
||||
|
||||
int howmany = ReadIntController::get(2, TEXT_AREA_X + g_context->_col, TEXT_AREA_Y + g_context->_line);
|
||||
gameSpellMixHowMany(spell, howmany, &ingredients);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DebuggerActions::gameSpellMixHowMany(int spell, int num, Ingredients *ingredients) {
|
||||
int i;
|
||||
|
||||
// Entered 0 mixtures, don't mix anything!
|
||||
if (num == 0) {
|
||||
print("\nNone mixed!");
|
||||
ingredients->revert();
|
||||
return false;
|
||||
}
|
||||
|
||||
// If they ask for more than will give them 99, only use what they need
|
||||
if (num > 99 - g_ultima->_saveGame->_mixtures[spell]) {
|
||||
num = 99 - g_ultima->_saveGame->_mixtures[spell];
|
||||
print("\n%cOnly need %d!%c", FG_GREY, num, FG_WHITE);
|
||||
}
|
||||
|
||||
print("\nMixing %d...", num);
|
||||
|
||||
// See if there's enough reagents to make number of mixtures requested
|
||||
if (!ingredients->checkMultiple(num)) {
|
||||
print("\n%cYou don't have enough reagents to mix %d spells!%c", FG_GREY, num, FG_WHITE);
|
||||
ingredients->revert();
|
||||
return false;
|
||||
}
|
||||
|
||||
print("\nYou mix the Reagents, and...");
|
||||
if (g_spells->spellMix(spell, ingredients)) {
|
||||
print("Success!\n");
|
||||
// Mix the extra spells
|
||||
ingredients->multiply(num);
|
||||
for (i = 0; i < num - 1; i++)
|
||||
g_spells->spellMix(spell, ingredients);
|
||||
} else {
|
||||
print("It Fizzles!\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DebuggerActions::openAt(const Coords &coords) {
|
||||
const Tile *tile = g_context->_location->_map->tileTypeAt(coords, WITH_OBJECTS);
|
||||
|
||||
if (!tile->isDoor() &&
|
||||
!tile->isLockedDoor())
|
||||
return false;
|
||||
|
||||
if (tile->isLockedDoor()) {
|
||||
g_screen->screenMessage("%cCan't!%c\n", FG_GREY, FG_WHITE);
|
||||
return true;
|
||||
}
|
||||
|
||||
Tile *floor = g_context->_location->_map->_tileSet->getByName("brick_floor");
|
||||
assertMsg(floor, "no floor tile found in tileset");
|
||||
g_context->_location->_map->_annotations->add(coords, floor->getId(), false, true)->setTTL(4);
|
||||
|
||||
g_screen->screenMessage("\nOpened!\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DebuggerActions::gameCastSpell(uint spell, int caster, int param) {
|
||||
SpellCastError spellError;
|
||||
Common::String msg;
|
||||
|
||||
if (!g_spells->spellCast(spell, caster, param, &spellError, true)) {
|
||||
msg = g_spells->spellGetErrorMessage(spell, spellError);
|
||||
if (!msg.empty())
|
||||
g_screen->screenMessage("%s", msg.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
bool DebuggerActions::talkAt(const Coords &coords) {
|
||||
extern int personIsVendor(const Person * person);
|
||||
City *city;
|
||||
|
||||
/* can't have any conversations outside of town */
|
||||
if (!isCity(g_context->_location->_map)) {
|
||||
g_screen->screenMessage("Funny, no response!\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
city = dynamic_cast<City *>(g_context->_location->_map);
|
||||
assert(city);
|
||||
Person *talker = city ? city->personAt(coords) : nullptr;
|
||||
|
||||
// Make sure we have someone we can talk with
|
||||
if (!talker || !talker->canConverse())
|
||||
return false;
|
||||
|
||||
/* No response from alerted guards... does any monster both
|
||||
attack and talk besides Nate the Snake? */
|
||||
if (talker->getMovementBehavior() == MOVEMENT_ATTACK_AVATAR &&
|
||||
talker->getId() != PYTHON_ID)
|
||||
return false;
|
||||
|
||||
// If we're talking to Lord British and the avatar is dead, LB resurrects them!
|
||||
if (talker->getNpcType() == NPC_LORD_BRITISH &&
|
||||
g_context->_party->member(0)->getStatus() == STAT_DEAD) {
|
||||
g_screen->screenMessage("%s, Thou shalt live again!\n", g_context->_party->member(0)->getName().c_str());
|
||||
|
||||
g_context->_party->member(0)->setStatus(STAT_GOOD);
|
||||
g_context->_party->member(0)->heal(HT_FULLHEAL);
|
||||
gameSpellEffect('r', -1, SOUND_LBHEAL);
|
||||
}
|
||||
|
||||
Conversation conv;
|
||||
conv._script->addProvider("party", g_context->_party);
|
||||
conv._script->addProvider("context", g_context);
|
||||
|
||||
conv._state = Conversation::INTRO;
|
||||
conv._reply = talker->getConversationText(&conv, "");
|
||||
conv._playerInput.clear();
|
||||
talkRunConversation(conv, talker, false);
|
||||
|
||||
// Ensure the end of the conversation ends the line
|
||||
if (g_context->_col != 0)
|
||||
g_screen->screenMessage("\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DebuggerActions::talkRunConversation(Conversation &conv, Person *talker, bool showPrompt) {
|
||||
while (conv._state != Conversation::DONE) {
|
||||
// TODO: instead of calculating linesused again, cache the
|
||||
// result in person.cpp somewhere.
|
||||
int linesused = linecount(conv._reply.front(), TEXT_AREA_W);
|
||||
g_screen->screenMessage("%s", conv._reply.front().c_str());
|
||||
conv._reply.pop_front();
|
||||
|
||||
/* if all chunks haven't been shown, wait for a key and process next chunk*/
|
||||
int size = conv._reply.size();
|
||||
if (size > 0) {
|
||||
#ifdef IOS_ULTIMA4
|
||||
U4IOS::IOSConversationChoiceHelper continueDialog;
|
||||
continueDialog.updateChoices(" ");
|
||||
#endif
|
||||
ReadChoiceController::get("");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* otherwise, clear current reply and proceed based on conversation state */
|
||||
conv._reply.clear();
|
||||
|
||||
/* they're attacking you! */
|
||||
if (conv._state == Conversation::ATTACK) {
|
||||
conv._state = Conversation::DONE;
|
||||
talker->setMovementBehavior(MOVEMENT_ATTACK_AVATAR);
|
||||
}
|
||||
|
||||
if (conv._state == Conversation::DONE)
|
||||
break;
|
||||
|
||||
/* When Lord British heals the party */
|
||||
else if (conv._state == Conversation::FULLHEAL) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < g_context->_party->size(); i++) {
|
||||
g_context->_party->member(i)->heal(HT_CURE); // cure the party
|
||||
g_context->_party->member(i)->heal(HT_FULLHEAL); // heal the party
|
||||
}
|
||||
gameSpellEffect('r', -1, SOUND_MAGIC); // same spell effect as 'r'esurrect
|
||||
|
||||
conv._state = Conversation::TALK;
|
||||
}
|
||||
/* When Lord British checks and advances each party member's level */
|
||||
else if (conv._state == Conversation::ADVANCELEVELS) {
|
||||
gameLordBritishCheckLevels();
|
||||
conv._state = Conversation::TALK;
|
||||
}
|
||||
|
||||
if (showPrompt) {
|
||||
Common::String prompt = talker->getPrompt(&conv);
|
||||
if (!prompt.empty()) {
|
||||
if (linesused + linecount(prompt, TEXT_AREA_W) > TEXT_AREA_H) {
|
||||
#ifdef IOS_ULTIMA4
|
||||
U4IOS::IOSConversationChoiceHelper continueDialog;
|
||||
continueDialog.updateChoices(" ");
|
||||
#endif
|
||||
ReadChoiceController::get("");
|
||||
}
|
||||
|
||||
g_screen->screenMessage("%s", prompt.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
int maxlen;
|
||||
switch (conv.getInputRequired(&maxlen)) {
|
||||
case Conversation::INPUT_STRING: {
|
||||
conv._playerInput = gameGetInput(maxlen);
|
||||
#ifdef IOS_ULTIMA4
|
||||
g_screen->screenMessage("%s", conv.playerInput.c_str()); // Since we put this in a different window, we need to show it again.
|
||||
#endif
|
||||
conv._reply = talker->getConversationText(&conv, conv._playerInput.c_str());
|
||||
conv._playerInput.clear();
|
||||
showPrompt = true;
|
||||
break;
|
||||
}
|
||||
case Conversation::INPUT_CHARACTER: {
|
||||
char message[2];
|
||||
#ifdef IOS_ULTIMA4
|
||||
U4IOS::IOSConversationChoiceHelper yesNoHelper;
|
||||
yesNoHelper.updateChoices("yn ");
|
||||
#endif
|
||||
int choice = ReadChoiceController::get("");
|
||||
|
||||
|
||||
message[0] = choice;
|
||||
message[1] = '\0';
|
||||
|
||||
conv._reply = talker->getConversationText(&conv, message);
|
||||
conv._playerInput.clear();
|
||||
|
||||
showPrompt = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case Conversation::INPUT_NONE:
|
||||
conv._state = Conversation::DONE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (conv._reply.size() > 0)
|
||||
g_screen->screenMessage("%s", conv._reply.front().c_str());
|
||||
}
|
||||
|
||||
void DebuggerActions::gameLordBritishCheckLevels() {
|
||||
bool advanced = false;
|
||||
|
||||
for (int i = 0; i < g_context->_party->size(); i++) {
|
||||
PartyMember *player = g_context->_party->member(i);
|
||||
if (player->getRealLevel() <
|
||||
player->getMaxLevel())
|
||||
|
||||
// add an extra space to separate messages
|
||||
if (!advanced) {
|
||||
g_screen->screenMessage("\n");
|
||||
advanced = true;
|
||||
}
|
||||
|
||||
player->advanceLevel();
|
||||
}
|
||||
|
||||
g_screen->screenMessage("\nWhat would thou\nask of me?\n");
|
||||
}
|
||||
|
||||
bool DebuggerActions::isCombat() const {
|
||||
return dynamic_cast<CombatController *>(eventHandler->getController()) != nullptr;
|
||||
}
|
||||
|
||||
int DebuggerActions::getCombatFocus() const {
|
||||
CombatController *cc = dynamic_cast<CombatController *>(eventHandler->getController());
|
||||
assert(cc);
|
||||
return cc->getFocus();
|
||||
}
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
144
engines/ultima/ultima4/core/debugger_actions.h
Normal file
144
engines/ultima/ultima4/core/debugger_actions.h
Normal file
@@ -0,0 +1,144 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ULTIMA4_CORE_DEBUGGER_ACTIONS_H
|
||||
#define ULTIMA4_CORE_DEBUGGER_ACTIONS_H
|
||||
|
||||
#include "ultima/ultima4/core/coords.h"
|
||||
#include "ultima/ultima4/game/spell.h"
|
||||
#include "ultima/ultima4/core/types.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
/**
|
||||
* This is a secondary class inherited by the Debugger class
|
||||
* that contains various support methods for implementing the
|
||||
* different actions players can take in the game
|
||||
*/
|
||||
class DebuggerActions {
|
||||
private:
|
||||
/**
|
||||
* Executes the current conversation until it is done.
|
||||
*/
|
||||
void talkRunConversation(Conversation &conv, Person *talker, bool showPrompt);
|
||||
|
||||
/**
|
||||
* Check the levels of each party member while talking to Lord British
|
||||
*/
|
||||
void gameLordBritishCheckLevels();
|
||||
protected:
|
||||
/**
|
||||
* Returns true if the debugger is active
|
||||
*/
|
||||
virtual bool isDebuggerActive() const = 0;
|
||||
|
||||
/**
|
||||
* Prints a message to the console if it's active, or to the
|
||||
* game screen if not
|
||||
*/
|
||||
virtual void print(const char *fmt, ...) = 0;
|
||||
|
||||
/**
|
||||
* Prints a message to the console if it's active, or to the
|
||||
* game screen if not
|
||||
*/
|
||||
virtual void printN(const char *fmt, ...) = 0;
|
||||
|
||||
/**
|
||||
* Prompts for input, but only if debugger isn't running
|
||||
*/
|
||||
virtual void prompt() = 0;
|
||||
|
||||
/**
|
||||
* Returns true if combat is currently active
|
||||
*/
|
||||
bool isCombat() const;
|
||||
|
||||
/**
|
||||
* Returns currently focused character in combat mode
|
||||
*/
|
||||
int getCombatFocus() const;
|
||||
public:
|
||||
virtual ~DebuggerActions() {}
|
||||
|
||||
/**
|
||||
* Summons a creature given by 'creatureName'. This can either be given
|
||||
* as the creature's name, or the creature's id. Once it finds the
|
||||
* creature to be summoned, it calls gameSpawnCreature() to spawn it.
|
||||
*/
|
||||
void summonCreature(const Common::String &name);
|
||||
|
||||
/**
|
||||
* Destroy object at a given co-ordinate
|
||||
*/
|
||||
bool destroyAt(const Coords &coords);
|
||||
|
||||
/**
|
||||
* Returns a direction from a given string
|
||||
*/
|
||||
Direction directionFromName(const Common::String &dirStr);
|
||||
|
||||
/**
|
||||
* Called by getChest() to handle possible traps on chests
|
||||
**/
|
||||
bool getChestTrapHandler(int player);
|
||||
|
||||
/**
|
||||
* Attempts to jimmy a locked door at map coordinates x,y. The locked
|
||||
* door is replaced by a permanent annotation of an unlocked door
|
||||
* tile.
|
||||
*/
|
||||
bool jimmyAt(const Coords &coords);
|
||||
|
||||
/**
|
||||
* Prompts for spell reagents to mix in the traditional Ultima IV
|
||||
* style.
|
||||
*/
|
||||
bool mixReagentsForSpellU4(int spell);
|
||||
|
||||
/**
|
||||
* Prompts for spell reagents to mix with an Ultima V-like menu.
|
||||
*/
|
||||
bool mixReagentsForSpellU5(int spell);
|
||||
|
||||
bool gameSpellMixHowMany(int spell, int num, Ingredients *ingredients);
|
||||
|
||||
/**
|
||||
* Attempts to open a door at map coordinates x,y. The door is
|
||||
* replaced by a temporary annotation of a floor tile for 4 turns.
|
||||
*/
|
||||
bool openAt(const Coords &coords);
|
||||
|
||||
void gameCastSpell(uint spell, int caster, int param);
|
||||
|
||||
|
||||
/**
|
||||
* Begins a conversation with the NPC at map coordinates x,y. If no
|
||||
* NPC is present at that point, zero is returned.
|
||||
*/
|
||||
bool talkAt(const Coords &coords);
|
||||
};
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
||||
83
engines/ultima/ultima4/core/lzw/hash.cpp
Normal file
83
engines/ultima/ultima4/core/lzw/hash.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ultima/ultima4/core/lzw/hash.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
namespace LZW {
|
||||
|
||||
int probe1(byte root, int codeword) {
|
||||
int newHashCode = ((root << 4) ^ codeword) & 0xfff;
|
||||
return (newHashCode);
|
||||
}
|
||||
|
||||
/* The secondary probe uses some assembler instructions that aren't easily translated to C. */
|
||||
int probe2(byte root, int codeword) {
|
||||
/* registers[0] == AX, registers[1] == DX */
|
||||
long registers[2], temp;
|
||||
long carry, oldCarry;
|
||||
int i, j;
|
||||
|
||||
/* the pre-mul part */
|
||||
registers[1] = 0;
|
||||
registers[0] = ((root << 1) + codeword) | 0x800;
|
||||
|
||||
/* the mul part (simulated mul instruction) */
|
||||
/* DX:AX = AX * AX */
|
||||
temp = (registers[0] & 0xff) * (registers[0] & 0xff);
|
||||
temp += 2 * (registers[0] & 0xff) * (registers[0] >> 8) * 0x100;
|
||||
registers[1] = (temp >> 16) + (registers[0] >> 8) * (registers[0] >> 8);
|
||||
registers[0] = temp & 0xffff;
|
||||
|
||||
/* if DX != 0, the mul instruction sets the carry flag */
|
||||
if (registers[1] == 00) {
|
||||
carry = 0;
|
||||
} else {
|
||||
carry = 1;
|
||||
}
|
||||
|
||||
/* the rcl part */
|
||||
for (i = 0; i < 2; i++) { /* 2 rcl's */
|
||||
for (j = 0; j < 2; j++) { /* rotate through 2 registers */
|
||||
oldCarry = carry;
|
||||
carry = (registers[j] >> 15) & 1;
|
||||
registers[j] = (registers[j] << 1) | oldCarry;
|
||||
registers[j] = registers[j] & 0xffff; /* make sure register stays 16 bit */
|
||||
}
|
||||
}
|
||||
|
||||
/* final touches */
|
||||
registers[0] = ((registers[0] >> 8) | (registers[1] << 8)) & 0xfff;
|
||||
|
||||
return ((int)registers[0]);
|
||||
}
|
||||
|
||||
int probe3(int hashCode) {
|
||||
const long probeOffset = 0x1fd; /* I think 0x1fd is prime */
|
||||
|
||||
long newHashCode = (hashCode + probeOffset) & 0xfff;
|
||||
return ((int)newHashCode);
|
||||
}
|
||||
|
||||
} // End of namespace LZW
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
39
engines/ultima/ultima4/core/lzw/hash.h
Normal file
39
engines/ultima/ultima4/core/lzw/hash.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ULTIMA4_CORE_LZW_HASH_H
|
||||
#define ULTIMA4_CORE_LZW_HASH_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
namespace LZW {
|
||||
|
||||
int probe1(byte root, int codeword);
|
||||
int probe2(byte root, int codeword);
|
||||
int probe3(int hashCode);
|
||||
|
||||
} // End of namespace LZW
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
||||
315
engines/ultima/ultima4/core/lzw/lzw.cpp
Normal file
315
engines/ultima/ultima4/core/lzw/lzw.cpp
Normal file
@@ -0,0 +1,315 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* A few files from Ultima 4 (PC version) have been compressed with the LZW algorithm.
|
||||
* There are two things that make the U4 implementation of the LZW decoding algorithm special:
|
||||
* 1) It uses a fixed codeword length of 12 bits.
|
||||
* The advantages over variable-length codewords are faster decompression and simpler code.
|
||||
* 2) The dictionary is implemented as a hash table.
|
||||
* While the dictionary is supposed to implemented as a hash table in the LZW *en*coder (to speed up
|
||||
* string searches), there is no reason not to implement it as a simple array in the decoder.
|
||||
* But since U4 uses a hash table in the decoder, this C version must do the same (or it won't be
|
||||
* able to decode the U4 files).
|
||||
*
|
||||
* An explanation on LZW data (de)compression can be found here:
|
||||
* https://web.archive.org/web/20191231131544/https://marknelson.us/posts/1989/10/01/lzw-data-compression.html
|
||||
* https://web.archive.org/web/20191231131532/https://marknelson.us/posts/2011/11/08/lzw-revisited.html
|
||||
*/
|
||||
|
||||
#include "ultima/ultima4/core/lzw/lzw.h"
|
||||
#include "ultima/ultima4/core/lzw/hash.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
namespace LZW {
|
||||
|
||||
typedef void (*WRITE_DECOMP)(byte root, byte *destination, long *position);
|
||||
|
||||
struct lzwDictionaryEntry {
|
||||
byte root;
|
||||
int codeword;
|
||||
byte occupied;
|
||||
};
|
||||
|
||||
long generalizedDecompress(WRITE_DECOMP outFunc, byte *compressedMem, byte *decompressedMem, long compressedSize);
|
||||
int getNextCodeword(long *bitsRead, byte *compressedMem);
|
||||
void discardRoot(byte root, byte *destination, long *position);
|
||||
void outputRoot(byte root, byte *destination, long *position);
|
||||
|
||||
void getString(int codeword, lzwDictionaryEntry *lzwDictionary, byte *stack, int *elementsInStack);
|
||||
int getNewHashCode(byte root, int codeword, lzwDictionaryEntry *dictionary);
|
||||
byte hashPosFound(int hashCode, byte root, int codeword, lzwDictionaryEntry *dictionary);
|
||||
|
||||
/*
|
||||
* This function returns the decompressed size of a block of compressed data.
|
||||
* It doesn't decompress the data.
|
||||
* Use this function if you want to decompress a block of data, but don't know the decompressed size
|
||||
* in advance.
|
||||
*
|
||||
* There is some error checking to detect if the compressed data is corrupt, but it's only rudimentary.
|
||||
* Returns:
|
||||
* No errors: (long) decompressed size
|
||||
* Error: (long) -1
|
||||
*/
|
||||
long lzwGetDecompressedSize(byte *compressedMem, long compressedSize) {
|
||||
return (generalizedDecompress(&discardRoot, compressedMem, nullptr, compressedSize));
|
||||
}
|
||||
|
||||
/*
|
||||
* Decompresses a block of compressed data from memory to memory.
|
||||
* Use this function if you already know the decompressed size.
|
||||
*
|
||||
* This function assumes that *decompressed_mem is already allocated, and that the decompressed data
|
||||
* will fit into *decompressed_mem.
|
||||
* There is some error checking to detect if the compressed data is corrupt, but it's only rudimentary.
|
||||
* Returns:
|
||||
* No errors: (long) decompressed size
|
||||
* Error: (long) -1
|
||||
*/
|
||||
long lzwDecompress(byte *compressedMem, byte *decompressedMem, long compressedSize) {
|
||||
return (generalizedDecompress(&outputRoot, compressedMem, decompressedMem, compressedSize));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------
|
||||
Functions used only inside lzw.c
|
||||
-------------------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* This function does the actual decompression work.
|
||||
* Parameters:
|
||||
* perform_decompression: FALSE ==> return decompressed size, but discard decompressed data
|
||||
* compressed_mem: compressed data
|
||||
* decompressed_mem: this is where the compressed data will be decompressed to
|
||||
* compressed_size: size of the compressed data (in bytes)
|
||||
*/
|
||||
long generalizedDecompress(WRITE_DECOMP outFunc, byte *compressedMem, byte *decompressedMem, long compressedSize) {
|
||||
int i;
|
||||
|
||||
/* re-initialize the dictionary when there are more than 0xccc entries */
|
||||
const int maxDictEntries = 0xccc;
|
||||
|
||||
const int lzwStackSize = 0x8000;
|
||||
const int lzwDictionarySize = 0x1000;
|
||||
|
||||
int old_code;
|
||||
int new_code;
|
||||
byte character;
|
||||
|
||||
long bitsRead = 0;
|
||||
long bytesWritten = 0;
|
||||
|
||||
/* newpos: position in the dictionary where new codeword was added */
|
||||
/* must be equal to current codeword (if it isn't, the compressed data must be corrupt) */
|
||||
/* unknownCodeword: is the current codeword in the dictionary? */
|
||||
int newpos;
|
||||
byte unknownCodeword;
|
||||
|
||||
/* initialize the dictionary and the stack */
|
||||
lzwDictionaryEntry *lzwDictionary = (lzwDictionaryEntry *) malloc(sizeof(lzwDictionaryEntry) * lzwDictionarySize);
|
||||
int codewordsInDictionary = 0;
|
||||
byte *lzwStack = (byte *) malloc(sizeof(byte) * lzwStackSize);
|
||||
int elementsInStack = 0;
|
||||
|
||||
/* clear the dictionary */
|
||||
memset(lzwDictionary, 0, sizeof(lzwDictionaryEntry) * lzwDictionarySize);
|
||||
for (i = 0; i < 0x100; i++) {
|
||||
lzwDictionary[i].occupied = 1;
|
||||
}
|
||||
|
||||
if (bitsRead + 12 <= compressedSize * 8) {
|
||||
/* read OLD_CODE */
|
||||
old_code = getNextCodeword(&bitsRead, compressedMem);
|
||||
/* CHARACTER = OLD_CODE */
|
||||
character = (byte)old_code;
|
||||
/* output OLD_CODE */
|
||||
outFunc(character, decompressedMem, &bytesWritten);
|
||||
|
||||
while (bitsRead + 12 <= compressedSize * 8) { /* WHILE there are still input characters DO */
|
||||
/* read NEW_CODE */
|
||||
new_code = getNextCodeword(&bitsRead, compressedMem);
|
||||
|
||||
if (lzwDictionary[new_code].occupied) { /* is the codeword in the dictionary? */
|
||||
/* codeword is present in the dictionary */
|
||||
/* it must either be a root or a non-root that has already been added to the dicionary */
|
||||
unknownCodeword = 0;
|
||||
|
||||
/* STRING = get translation of NEW_CODE */
|
||||
getString(new_code, lzwDictionary, lzwStack, &elementsInStack);
|
||||
} else {
|
||||
/* codeword is yet to be defined */
|
||||
unknownCodeword = 1;
|
||||
|
||||
/* STRING = get translation of OLD_CODE */
|
||||
/* STRING = STRING+CHARACTER */
|
||||
lzwStack[elementsInStack] = character; /* push character on the stack */
|
||||
elementsInStack++;
|
||||
|
||||
getString(old_code, lzwDictionary, lzwStack, &elementsInStack);
|
||||
}
|
||||
|
||||
/* CHARACTER = first character in STRING */
|
||||
character = lzwStack[elementsInStack - 1]; /* element at top of stack */
|
||||
|
||||
/* output STRING */
|
||||
while (elementsInStack > 0) {
|
||||
outFunc(lzwStack[elementsInStack - 1], decompressedMem, &bytesWritten);
|
||||
elementsInStack--;
|
||||
}
|
||||
|
||||
/* add OLD_CODE + CHARACTER to the translation table */
|
||||
newpos = getNewHashCode(character, old_code, lzwDictionary);
|
||||
|
||||
lzwDictionary[newpos].root = character;
|
||||
lzwDictionary[newpos].codeword = old_code;
|
||||
lzwDictionary[newpos].occupied = 1;
|
||||
codewordsInDictionary++;
|
||||
|
||||
/* check for errors */
|
||||
if (unknownCodeword && (newpos != new_code)) {
|
||||
/* clean up */
|
||||
free(lzwStack);
|
||||
free(lzwDictionary);
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (codewordsInDictionary > maxDictEntries) {
|
||||
/* wipe dictionary */
|
||||
codewordsInDictionary = 0;
|
||||
memset(lzwDictionary, 0, sizeof(lzwDictionaryEntry) * lzwDictionarySize);
|
||||
for (i = 0; i < 0x100; i++) {
|
||||
lzwDictionary[i].occupied = 1;
|
||||
}
|
||||
|
||||
if (bitsRead + 12 <= compressedSize * 8) {
|
||||
new_code = getNextCodeword(&bitsRead, compressedMem);
|
||||
character = (byte)new_code;
|
||||
|
||||
outFunc(character, decompressedMem, &bytesWritten);
|
||||
} else {
|
||||
/* clean up */
|
||||
free(lzwStack);
|
||||
free(lzwDictionary);
|
||||
|
||||
return (bytesWritten);
|
||||
}
|
||||
}
|
||||
|
||||
/* OLD_CODE = NEW_CODE */
|
||||
old_code = new_code;
|
||||
}
|
||||
}
|
||||
/* clean up */
|
||||
free(lzwStack);
|
||||
free(lzwDictionary);
|
||||
|
||||
return (bytesWritten);
|
||||
}
|
||||
|
||||
/* read the next 12-bit codeword from the compressed data */
|
||||
int getNextCodeword(long *bitsRead, byte *compressedMem) {
|
||||
int codeword = (compressedMem[(*bitsRead) / 8] << 8) + compressedMem[(*bitsRead) / 8 + 1];
|
||||
codeword = codeword >> (4 - ((*bitsRead) % 8));
|
||||
codeword = codeword & 0xfff;
|
||||
(*bitsRead) += 12;
|
||||
|
||||
return (codeword);
|
||||
}
|
||||
|
||||
/* increment position pointer, but do not write root to memory */
|
||||
void discardRoot(byte root, byte *destination, long *position) {
|
||||
(*position)++;
|
||||
}
|
||||
|
||||
/* output a root to memory */
|
||||
void outputRoot(byte root, byte *destination, long *position) {
|
||||
destination[*position] = root;
|
||||
(*position)++;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------
|
||||
Dictionary-related functions
|
||||
-------------------------------------------------------------------------------------- */
|
||||
|
||||
/* pushes the string associated with codeword onto the stack */
|
||||
void getString(int codeword, lzwDictionaryEntry *dictionary, byte *stack, int *elementsInStack) {
|
||||
byte root;
|
||||
int currentCodeword = codeword;
|
||||
|
||||
while (currentCodeword > 0xff) {
|
||||
root = dictionary[currentCodeword].root;
|
||||
currentCodeword = dictionary[currentCodeword].codeword;
|
||||
stack[*elementsInStack] = root;
|
||||
(*elementsInStack)++;
|
||||
}
|
||||
|
||||
/* push the root at the leaf */
|
||||
stack[*elementsInStack] = (byte)currentCodeword;
|
||||
(*elementsInStack)++;
|
||||
}
|
||||
|
||||
int getNewHashCode(byte root, int codeword, lzwDictionaryEntry *dictionary) {
|
||||
int hashCode;
|
||||
|
||||
/* probe 1 */
|
||||
hashCode = probe1(root, codeword);
|
||||
if (hashPosFound(hashCode, root, codeword, dictionary)) {
|
||||
return (hashCode);
|
||||
}
|
||||
/* probe 2 */
|
||||
hashCode = probe2(root, codeword);
|
||||
if (hashPosFound(hashCode, root, codeword, dictionary)) {
|
||||
return (hashCode);
|
||||
}
|
||||
/* probe 3 */
|
||||
do {
|
||||
hashCode = probe3(hashCode);
|
||||
} while (! hashPosFound(hashCode, root, codeword, dictionary));
|
||||
|
||||
return (hashCode);
|
||||
}
|
||||
|
||||
byte hashPosFound(int hashCode, byte root, int codeword, lzwDictionaryEntry *dictionary) {
|
||||
if (hashCode > 0xff) {
|
||||
// hash codes must not be roots
|
||||
byte c1 = 0, c2 = 0, c3 = 0;
|
||||
|
||||
if (dictionary[hashCode].occupied) {
|
||||
// hash table position is occupied
|
||||
c1 = 1;
|
||||
// is our (root,codeword) pair already in the hash table?
|
||||
c2 = dictionary[hashCode].root == root;
|
||||
c3 = dictionary[hashCode].codeword == codeword;
|
||||
} else {
|
||||
// hash table position is free
|
||||
c1 = 0;
|
||||
}
|
||||
|
||||
return (!c1) || (c1 && c2 && c3);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace LZW
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
38
engines/ultima/ultima4/core/lzw/lzw.h
Normal file
38
engines/ultima/ultima4/core/lzw/lzw.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ULTIMA4_CORE_LZW_LZW_H
|
||||
#define ULTIMA4_CORE_LZW_LZW_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
namespace LZW {
|
||||
|
||||
long lzwGetDecompressedSize(byte *compressedMem, long compressedSize);
|
||||
long lzwDecompress(byte *compressedMem, byte *decompressedMem, long compressedSize);
|
||||
|
||||
} // End of namespace LZW
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
||||
155
engines/ultima/ultima4/core/lzw/u4decode.cpp
Normal file
155
engines/ultima/ultima4/core/lzw/u4decode.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ultima/ultima4/core/lzw/lzw.h"
|
||||
#include "ultima/ultima4/core/lzw/u4decode.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
namespace LZW {
|
||||
|
||||
/*
|
||||
* Loads a file, decompresses it (from memory to memory), and writes the decompressed data to another file
|
||||
* Returns:
|
||||
* -1 if there was an error
|
||||
* the decompressed file length, on success
|
||||
*/
|
||||
long decompress_u4_file(Common::SeekableReadStream *in, long filesize, void **out) {
|
||||
byte *compressed_mem, *decompressed_mem;
|
||||
long compressed_filesize, decompressed_filesize;
|
||||
long errorCode;
|
||||
|
||||
/* size of the compressed input file */
|
||||
compressed_filesize = filesize;
|
||||
|
||||
/* input file should be longer than 0 bytes */
|
||||
if (compressed_filesize == 0)
|
||||
return (-1);
|
||||
|
||||
/* check if the input file is _not_ a valid LZW-compressed file */
|
||||
if (!mightBeValidCompressedFile(in))
|
||||
return (-1);
|
||||
|
||||
/* load compressed file into compressed_mem[] */
|
||||
compressed_mem = (byte *) malloc(compressed_filesize);
|
||||
in->read(compressed_mem, compressed_filesize);
|
||||
|
||||
/*
|
||||
* determine decompressed file size
|
||||
* if lzw_get_decompressed_size() can't determine the decompressed size (i.e. the compressed
|
||||
* data is corrupt), it returns -1
|
||||
*/
|
||||
decompressed_filesize = lzwGetDecompressedSize(compressed_mem, compressed_filesize);
|
||||
|
||||
if (decompressed_filesize <= 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* decompress file from compressed_mem[] into decompressed_mem[] */
|
||||
decompressed_mem = (byte *) malloc(decompressed_filesize);
|
||||
|
||||
/* testing: clear destination mem */
|
||||
memset(decompressed_mem, 0, decompressed_filesize);
|
||||
|
||||
errorCode = lzwDecompress(compressed_mem, decompressed_mem, compressed_filesize);
|
||||
|
||||
free(compressed_mem);
|
||||
|
||||
*out = decompressed_mem;
|
||||
|
||||
return (errorCode);
|
||||
}
|
||||
|
||||
long decompress_u4_memory(void *in, long inlen, void **out) {
|
||||
byte *compressed_mem, *decompressed_mem;
|
||||
long compressed_filesize, decompressed_filesize;
|
||||
long errorCode;
|
||||
|
||||
/* size of the compressed input */
|
||||
compressed_filesize = inlen;
|
||||
|
||||
/* input file should be longer than 0 bytes */
|
||||
if (compressed_filesize == 0)
|
||||
return (-1);
|
||||
|
||||
compressed_mem = (byte *) in;
|
||||
|
||||
/*
|
||||
* determine decompressed data size
|
||||
* if lzw_get_decompressed_size() can't determine the decompressed size (i.e. the compressed
|
||||
* data is corrupt), it returns -1
|
||||
*/
|
||||
decompressed_filesize = lzwGetDecompressedSize(compressed_mem, compressed_filesize);
|
||||
|
||||
if (decompressed_filesize <= 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* decompress file from compressed_mem[] into decompressed_mem[] */
|
||||
decompressed_mem = (byte *) malloc(decompressed_filesize);
|
||||
|
||||
/* testing: clear destination mem */
|
||||
memset(decompressed_mem, 0, decompressed_filesize);
|
||||
|
||||
errorCode = lzwDecompress(compressed_mem, decompressed_mem, compressed_filesize);
|
||||
|
||||
*out = decompressed_mem;
|
||||
|
||||
return (errorCode);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the size of a file, and moves the file pointer to the beginning.
|
||||
* The file must already be open when this function is called.
|
||||
*/
|
||||
long getFilesize(Common::SeekableReadStream *input_file) {
|
||||
return input_file->size();
|
||||
}
|
||||
|
||||
/*
|
||||
* If the input file is a valid LZW-compressed file, the upper 4 bits of
|
||||
* the first byte must be 0, because the first codeword is always a root.
|
||||
*/
|
||||
byte mightBeValidCompressedFile(Common::SeekableReadStream *input_file) {
|
||||
byte firstByte;
|
||||
byte c1, c2, c3; /* booleans */
|
||||
long input_filesize;
|
||||
|
||||
/* check if the input file has a valid size */
|
||||
/* the compressed file is made up of 12-bit codewords, */
|
||||
/* so there are either 0 or 4 bits of wasted space */
|
||||
input_filesize = getFilesize(input_file);
|
||||
c1 = (input_filesize * 8) % 12 == 0;
|
||||
c2 = (input_filesize * 8 - 4) % 12 == 0;
|
||||
|
||||
// read first byte, and then reset back file pointer
|
||||
input_file->seek(0);
|
||||
firstByte = input_file->readByte();
|
||||
input_file->seek(0);
|
||||
c3 = (firstByte >> 4) == 0;
|
||||
|
||||
// check if upper 4 bits are 0
|
||||
return ((c1 || c2) && c3);
|
||||
}
|
||||
|
||||
} // End of namespace LZW
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
40
engines/ultima/ultima4/core/lzw/u4decode.h
Normal file
40
engines/ultima/ultima4/core/lzw/u4decode.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ULTIMA4_CORE_LZW_U4DECODE_H
|
||||
#define ULTIMA4_CORE_LZW_U4DECODE_H
|
||||
|
||||
#include "common/stream.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
namespace LZW {
|
||||
|
||||
long decompress_u4_file(Common::SeekableReadStream *in, long filesize, void **out);
|
||||
long getFilesize(Common::SeekableReadStream *input_file);
|
||||
byte mightBeValidCompressedFile(Common::SeekableReadStream *compressed_file);
|
||||
long decompress_u4_memory(void *in, long inlen, void **out);
|
||||
|
||||
} // End of namespace LZW
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
||||
107
engines/ultima/ultima4/core/observable.h
Normal file
107
engines/ultima/ultima4/core/observable.h
Normal file
@@ -0,0 +1,107 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ULTIMA4_CORE_OBSERVABLE_H
|
||||
#define ULTIMA4_CORE_OBSERVABLE_H
|
||||
|
||||
#include "ultima/ultima4/core/observer.h"
|
||||
#include "ultima/shared/std/containers.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
/**
|
||||
* Classes can report updates to a list of decoupled Observers by
|
||||
* extending this class.
|
||||
*
|
||||
* The O class parameter should be a pointer to the class of the
|
||||
* observable itself, so it can be passed in a typesafe manner to the
|
||||
* observers update method.
|
||||
*
|
||||
* The A class can be any additional information to pass to observers.
|
||||
* Observables that don't need to pass an argument when they update
|
||||
* observers should use the default "NoArg" class for the second
|
||||
* template parameter and pass nullptr to notifyObservers.
|
||||
*/
|
||||
template <class O, class A = NoArg *>
|
||||
class Observable {
|
||||
public:
|
||||
Observable() : _changed(false) {}
|
||||
|
||||
void addObserver(Observer<O, A> *o) {
|
||||
typename Std::vector< Observer<O, A> *>::iterator i;
|
||||
i = Common::find(_observers.begin(), _observers.end(), o);
|
||||
if (i == _observers.end())
|
||||
_observers.push_back(o);
|
||||
}
|
||||
|
||||
int countObservers() const {
|
||||
return _observers.size();
|
||||
}
|
||||
|
||||
void deleteObserver(Observer<O, A> *o) {
|
||||
typename Std::vector< Observer<O, A> *>::iterator i;
|
||||
i = Common::find(_observers.begin(), _observers.end(), o);
|
||||
if (i != _observers.end())
|
||||
_observers.erase(i);
|
||||
}
|
||||
|
||||
void deleteObservers() {
|
||||
_observers.clear();
|
||||
}
|
||||
|
||||
bool hasChanged() const {
|
||||
return _changed;
|
||||
}
|
||||
|
||||
void notifyObservers(A arg) {
|
||||
if (!_changed)
|
||||
return;
|
||||
|
||||
// vector iterators are invalidated if erase is called, so a copy
|
||||
// is used to prevent problems if the observer removes itself (or
|
||||
// otherwise changes the observer list)
|
||||
typename Std::vector< Observer<O, A> *> tmp = _observers;
|
||||
|
||||
clearChanged();
|
||||
|
||||
for (auto *observer : tmp) {
|
||||
observer->update(static_cast<O>(this), arg);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
void clearChanged() {
|
||||
_changed = false;
|
||||
}
|
||||
void setChanged() {
|
||||
_changed = true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool _changed;
|
||||
Std::vector< Observer<O, A> *> _observers;
|
||||
};
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
||||
67
engines/ultima/ultima4/core/observer.h
Normal file
67
engines/ultima/ultima4/core/observer.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ULTIMA4_CORE_OBSERVER_H
|
||||
#define ULTIMA4_CORE_OBSERVER_H
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
template<class O, class A>
|
||||
class Observable;
|
||||
class NoArg;
|
||||
|
||||
/**
|
||||
* This is the interface a class must implement to watch an
|
||||
* Observable.
|
||||
*/
|
||||
template<class O, class A = NoArg *>
|
||||
class Observer {
|
||||
public:
|
||||
virtual void update(O observable, A arg) = 0;
|
||||
virtual ~Observer() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* A specialized observer for watching observables that don't use the
|
||||
* "arg" parameter to update.
|
||||
*/
|
||||
template<class O>
|
||||
class Observer<O, NoArg *> {
|
||||
public:
|
||||
virtual void update(O observable, NoArg *arg) {
|
||||
update(observable);
|
||||
}
|
||||
virtual void update(O observable) = 0;
|
||||
virtual ~Observer() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Just an empty marker class to identify observers that take no args
|
||||
* on update.
|
||||
*/
|
||||
class NoArg {
|
||||
};
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
||||
190
engines/ultima/ultima4/core/settings.cpp
Normal file
190
engines/ultima/ultima4/core/settings.cpp
Normal file
@@ -0,0 +1,190 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ultima/ultima4/core/settings.h"
|
||||
#include "ultima/ultima4/events/event_handler.h"
|
||||
#include "ultima/ultima4/core/utils.h"
|
||||
#include "common/file.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
/*
|
||||
* Initialize static members
|
||||
*/
|
||||
Settings *Settings::_instance = nullptr;
|
||||
|
||||
bool SettingsEnhancementOptions::operator==(const SettingsEnhancementOptions &s) const {
|
||||
return _activePlayer == s._activePlayer
|
||||
&& _u5SpellMixing == s._u5SpellMixing
|
||||
&& _u5Shrines == s._u5Shrines
|
||||
&& _u5Combat == s._u5Combat
|
||||
&& _slimeDivides == s._slimeDivides
|
||||
&& _gazerSpawnsInsects == s._gazerSpawnsInsects
|
||||
&& _textColorization == s._textColorization
|
||||
&& _c64ChestTraps == s._c64ChestTraps
|
||||
&& _smartEnterKey == s._smartEnterKey
|
||||
&& _peerShowsObjects == s._peerShowsObjects
|
||||
&& _u4TileTransparencyHack == s._u4TileTransparencyHack
|
||||
&& _u4TileTransparencyHackPixelShadowOpacity == s._u4TileTransparencyHackPixelShadowOpacity
|
||||
&& _u4TrileTransparencyHackShadowBreadth == s._u4TrileTransparencyHackShadowBreadth;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
bool SettingsData::operator==(const SettingsData &s) const {
|
||||
return _videoType == s._videoType
|
||||
&& _battleSpeed == s._battleSpeed
|
||||
&& _campingAlwaysCombat == s._campingAlwaysCombat
|
||||
&& _campTime == s._campTime
|
||||
&& _debug == s._debug
|
||||
&& _enhancements == s._enhancements
|
||||
&& _enhancementsOptions == s._enhancementsOptions
|
||||
&& _filterMoveMessages == s._filterMoveMessages
|
||||
&& _gameCyclesPerSecond == s._gameCyclesPerSecond
|
||||
&& _screenAnimationFramesPerSecond == s._screenAnimationFramesPerSecond
|
||||
&& _innAlwaysCombat == s._innAlwaysCombat
|
||||
&& _innTime == s._innTime
|
||||
&& _mouseOptions == s._mouseOptions
|
||||
&& _screenShakes == s._screenShakes
|
||||
&& _gamma == s._gamma
|
||||
&& _shakeInterval == s._shakeInterval
|
||||
&& _shortcutCommands == s._shortcutCommands
|
||||
&& _shrineTime == s._shrineTime
|
||||
&& _spellEffectSpeed == s._spellEffectSpeed
|
||||
&& _validateXml == s._validateXml
|
||||
&& _volumeFades == s._volumeFades
|
||||
&& _titleSpeedRandom == s._titleSpeedRandom
|
||||
&& _titleSpeedOther == s._titleSpeedOther;
|
||||
}
|
||||
|
||||
bool SettingsData::operator!=(const SettingsData &s) const {
|
||||
return !operator==(s);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
Settings::Settings() {
|
||||
// Synchronize settings
|
||||
Shared::ConfSerializer s(false);
|
||||
synchronize(s);
|
||||
|
||||
// Set up various other constants that aren't configurable
|
||||
_game = "Ultima IV";
|
||||
_debug = gDebugLevel > 0;
|
||||
|
||||
_innAlwaysCombat = 0;
|
||||
_campingAlwaysCombat = 0;
|
||||
_screenAnimationFramesPerSecond = DEFAULT_ANIMATION_FRAMES_PER_SECOND;
|
||||
|
||||
bool isEnhanced = _videoType != "EGA";
|
||||
_scale = isEnhanced ? 2 : 1;
|
||||
_filter = isEnhanced ? "Scale2x" : "point";
|
||||
|
||||
_battleDiffs.push_back("Normal");
|
||||
_battleDiffs.push_back("Hard");
|
||||
_battleDiffs.push_back("Expert");
|
||||
|
||||
_eventTimerGranularity = (1000 / _gameCyclesPerSecond);
|
||||
}
|
||||
|
||||
Settings &Settings::getInstance() {
|
||||
if (_instance == nullptr)
|
||||
_instance = new Settings();
|
||||
return *_instance;
|
||||
}
|
||||
|
||||
void Settings::setData(const SettingsData &data) {
|
||||
// bitwise copy is safe
|
||||
*(SettingsData *)this = data;
|
||||
|
||||
bool isEnhanced = _videoType != "EGA";
|
||||
_scale = isEnhanced ? 2 : 1;
|
||||
_filter = isEnhanced ? "Scale2x" : "point";
|
||||
}
|
||||
|
||||
bool Settings::write() {
|
||||
Shared::ConfSerializer s(true);
|
||||
synchronize(s);
|
||||
|
||||
setChanged();
|
||||
notifyObservers(nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Settings::synchronize(Shared::ConfSerializer &s) {
|
||||
// General settings
|
||||
bool isEnhanced = g_ultima->isEnhanced();
|
||||
s.syncAsString("video", _videoType, isEnhanced ? "new" : "EGA");
|
||||
s.syncAsString("gemLayout", _gemLayout, DEFAULT_GEM_LAYOUT);
|
||||
s.syncAsString("lineOfSight", _lineOfSight, DEFAULT_LINEOFSIGHT);
|
||||
s.syncAsBool("screenShakes", _screenShakes, DEFAULT_SCREEN_SHAKES);
|
||||
s.syncAsInt("gamma", _gamma, DEFAULT_GAMMA);
|
||||
s.syncAsBool("volumeFades", _volumeFades, DEFAULT_VOLUME_FADES);
|
||||
s.syncAsBool("shortcutCommands", _shortcutCommands, DEFAULT_SHORTCUT_COMMANDS);
|
||||
s.syncAsBool("filterMoveMessages", _filterMoveMessages, DEFAULT_FILTER_MOVE_MESSAGES);
|
||||
s.syncAsInt("battlespeed", _battleSpeed, DEFAULT_BATTLE_SPEED);
|
||||
s.syncAsBool("enhancements", _enhancements, DEFAULT_ENHANCEMENTS);
|
||||
s.syncAsInt("gameCyclesPerSecond", _gameCyclesPerSecond, DEFAULT_CYCLES_PER_SECOND);
|
||||
s.syncAsString("battleDiff", _battleDiff, DEFAULT_BATTLE_DIFFICULTY);
|
||||
s.syncAsBool("validateXml", _validateXml, DEFAULT_VALIDATE_XML);
|
||||
s.syncAsInt("spellEffectSpeed", _spellEffectSpeed, DEFAULT_SPELL_EFFECT_SPEED);
|
||||
s.syncAsInt("campTime", _campTime, DEFAULT_CAMP_TIME);
|
||||
s.syncAsInt("innTime", _innTime, DEFAULT_INN_TIME);
|
||||
s.syncAsInt("shrineTime", _shrineTime, DEFAULT_SHRINE_TIME);
|
||||
s.syncAsInt("shakeInterval", _shakeInterval, DEFAULT_SHAKE_INTERVAL);
|
||||
s.syncAsInt("titleSpeedRandom", _titleSpeedRandom, DEFAULT_TITLE_SPEED_RANDOM);
|
||||
s.syncAsInt("titleSpeedOther", _titleSpeedOther, DEFAULT_TITLE_SPEED_OTHER);
|
||||
s.syncAsBool("innAlwaysCombat", _innAlwaysCombat, false);
|
||||
s.syncAsBool("campingAlwaysCombat", _campingAlwaysCombat, false);
|
||||
s.syncAsBool("u5spellMixing", _enhancementsOptions._u5SpellMixing, isEnhanced);
|
||||
|
||||
// all specific minor enhancements default to "on", any major enhancements default to "off"
|
||||
// minor enhancement options
|
||||
s.syncAsBool("activePlayer", _enhancementsOptions._activePlayer, true);
|
||||
s.syncAsBool("u5shrines", _enhancementsOptions._u5Shrines, true);
|
||||
s.syncAsBool("slimeDivides", _enhancementsOptions._slimeDivides, true);
|
||||
s.syncAsBool("gazerSpawnsInsects", _enhancementsOptions._gazerSpawnsInsects, true);
|
||||
s.syncAsBool("textColorization", _enhancementsOptions._textColorization, false);
|
||||
s.syncAsBool("c64chestTraps", _enhancementsOptions._c64ChestTraps, true);
|
||||
s.syncAsBool("smartEnterKey", _enhancementsOptions._smartEnterKey, true);
|
||||
|
||||
// major enhancement options
|
||||
s.syncAsBool("peerShowsObjects", _enhancementsOptions._peerShowsObjects, false);
|
||||
s.syncAsBool("u5combat", _enhancementsOptions._u5Combat, false);
|
||||
|
||||
// graphics enhancements options
|
||||
s.syncAsBool("renderTileTransparency", _enhancementsOptions._u4TileTransparencyHack, true);
|
||||
s.syncAsInt("transparentTilePixelShadowOpacity", _enhancementsOptions._u4TileTransparencyHackPixelShadowOpacity, DEFAULT_SHADOW_PIXEL_OPACITY);
|
||||
s.syncAsInt("transparentTileShadowSize", _enhancementsOptions._u4TrileTransparencyHackShadowBreadth, DEFAULT_SHADOW_PIXEL_SIZE);
|
||||
|
||||
// mouse options
|
||||
s.syncAsBool("mouseEnabled", _mouseOptions._enabled, true);
|
||||
s.syncAsString("logging", _logging, DEFAULT_LOGGING);
|
||||
}
|
||||
|
||||
const Std::vector<Common::String> &Settings::getBattleDiffs() {
|
||||
return _battleDiffs;
|
||||
}
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
186
engines/ultima/ultima4/core/settings.h
Normal file
186
engines/ultima/ultima4/core/settings.h
Normal file
@@ -0,0 +1,186 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ULTIMA4_CORE_SETTINGS_H
|
||||
#define ULTIMA4_CORE_SETTINGS_H
|
||||
|
||||
#include "ultima/ultima4/core/observable.h"
|
||||
#include "ultima/ultima4/core/types.h"
|
||||
#include "ultima/shared/conf/conf_serializer.h"
|
||||
#include "common/hash-str.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
#define MIN_SHAKE_INTERVAL 50
|
||||
|
||||
#define MAX_BATTLE_SPEED 10
|
||||
#define MAX_KEY_DELAY 1000
|
||||
#define MAX_KEY_INTERVAL 100
|
||||
#define MAX_CYCLES_PER_SECOND 20
|
||||
#define MAX_SPELL_EFFECT_SPEED 10
|
||||
#define MAX_CAMP_TIME 10
|
||||
#define MAX_INN_TIME 10
|
||||
#define MAX_SHRINE_TIME 20
|
||||
#define MAX_SHAKE_INTERVAL 200
|
||||
#define MAX_VOLUME 10
|
||||
|
||||
#define DEFAULT_GEM_LAYOUT "Standard"
|
||||
#define DEFAULT_LINEOFSIGHT "DOS"
|
||||
#define DEFAULT_SCREEN_SHAKES 1
|
||||
#define DEFAULT_GAMMA 100
|
||||
#define DEFAULT_VOLUME_FADES 1
|
||||
#define DEFAULT_SHORTCUT_COMMANDS 0
|
||||
#define DEFAULT_KEY_DELAY 500
|
||||
#define DEFAULT_KEY_INTERVAL 30
|
||||
#define DEFAULT_FILTER_MOVE_MESSAGES 0
|
||||
#define DEFAULT_BATTLE_SPEED 5
|
||||
#define DEFAULT_ENHANCEMENTS 1
|
||||
#define DEFAULT_CYCLES_PER_SECOND 4
|
||||
#define DEFAULT_ANIMATION_FRAMES_PER_SECOND 24
|
||||
#define DEFAULT_DEBUG 0
|
||||
#define DEFAULT_VALIDATE_XML 1
|
||||
#define DEFAULT_SPELL_EFFECT_SPEED 10
|
||||
#define DEFAULT_CAMP_TIME 10
|
||||
#define DEFAULT_INN_TIME 8
|
||||
#define DEFAULT_SHRINE_TIME 16
|
||||
#define DEFAULT_SHAKE_INTERVAL 100
|
||||
#define DEFAULT_BATTLE_DIFFICULTY "Normal"
|
||||
#define DEFAULT_LOGGING ""
|
||||
#define DEFAULT_TITLE_SPEED_RANDOM 150
|
||||
#define DEFAULT_TITLE_SPEED_OTHER 30
|
||||
|
||||
//--Tile transparency stuff
|
||||
#define DEFAULT_SHADOW_PIXEL_OPACITY 64
|
||||
#define DEFAULT_SHADOW_PIXEL_SIZE 2
|
||||
|
||||
struct SettingsEnhancementOptions {
|
||||
bool _activePlayer;
|
||||
bool _u5SpellMixing;
|
||||
bool _u5Shrines;
|
||||
bool _u5Combat;
|
||||
bool _slimeDivides;
|
||||
bool _gazerSpawnsInsects;
|
||||
bool _textColorization;
|
||||
bool _c64ChestTraps;
|
||||
bool _smartEnterKey;
|
||||
bool _peerShowsObjects;
|
||||
bool _u4TileTransparencyHack;
|
||||
int _u4TileTransparencyHackPixelShadowOpacity;
|
||||
int _u4TrileTransparencyHackShadowBreadth;
|
||||
|
||||
bool operator==(const SettingsEnhancementOptions &s) const;
|
||||
};
|
||||
|
||||
struct MouseOptions {
|
||||
bool _enabled;
|
||||
|
||||
bool operator==(const MouseOptions &s) const {
|
||||
return _enabled == s._enabled;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* SettingsData stores all the settings information.
|
||||
*/
|
||||
class SettingsData {
|
||||
public:
|
||||
bool operator==(const SettingsData &) const;
|
||||
bool operator!=(const SettingsData &) const;
|
||||
|
||||
int _battleSpeed;
|
||||
bool _campingAlwaysCombat;
|
||||
int _campTime;
|
||||
bool _debug;
|
||||
bool _enhancements;
|
||||
SettingsEnhancementOptions _enhancementsOptions;
|
||||
bool _filterMoveMessages;
|
||||
int _gameCyclesPerSecond;
|
||||
int _screenAnimationFramesPerSecond;
|
||||
bool _innAlwaysCombat;
|
||||
int _innTime;
|
||||
MouseOptions _mouseOptions;
|
||||
uint _scale;
|
||||
bool _screenShakes;
|
||||
int _gamma;
|
||||
int _shakeInterval;
|
||||
bool _shortcutCommands;
|
||||
int _shrineTime;
|
||||
int _spellEffectSpeed;
|
||||
bool _validateXml;
|
||||
bool _volumeFades;
|
||||
int _titleSpeedRandom;
|
||||
int _titleSpeedOther;
|
||||
|
||||
int _eventTimerGranularity;
|
||||
Common::String _filter;
|
||||
Common::String _gemLayout;
|
||||
Common::String _lineOfSight;
|
||||
Common::String _videoType;
|
||||
Common::String _battleDiff;
|
||||
Common::String _logging;
|
||||
Common::String _game;
|
||||
};
|
||||
|
||||
/**
|
||||
* The settings class is a singleton that holds all the settings
|
||||
* information. It is dynamically initialized when first accessed.
|
||||
*/
|
||||
class Settings : public SettingsData, public Observable<Settings *> {
|
||||
typedef Common::HashMap<Common::String, Common::String> SettingsMap;
|
||||
private:
|
||||
static Settings *_instance;
|
||||
Std::vector<Common::String> _battleDiffs;
|
||||
private:
|
||||
/**
|
||||
* Default contructor. Settings is a singleton so this is private.
|
||||
*/
|
||||
Settings();
|
||||
|
||||
/**
|
||||
* Synchronize settings with ConfMan
|
||||
*/
|
||||
void synchronize(Shared::ConfSerializer &s);
|
||||
public:
|
||||
/* Methods */
|
||||
|
||||
/**
|
||||
* Return the global instance of settings.
|
||||
*/
|
||||
static Settings &getInstance();
|
||||
void setData(const SettingsData &data);
|
||||
|
||||
/**
|
||||
* Write the settings out into a human readable file. This also
|
||||
* notifies observers that changes have been committed.
|
||||
*/
|
||||
bool write();
|
||||
|
||||
const Std::vector<Common::String> &getBattleDiffs();
|
||||
};
|
||||
|
||||
/* the global settings */
|
||||
#define settings (Settings::getInstance())
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
||||
83
engines/ultima/ultima4/core/types.h
Normal file
83
engines/ultima/ultima4/core/types.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ULTIMA4_CORE_TYPES_H
|
||||
#define ULTIMA4_CORE_TYPES_H
|
||||
|
||||
#include "ultima/ultima4/map/direction.h"
|
||||
#include "common/scummsys.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
class Tile;
|
||||
|
||||
typedef uint TileId;
|
||||
typedef byte MapId;
|
||||
|
||||
enum TileSpeed {
|
||||
FAST,
|
||||
SLOW,
|
||||
VSLOW,
|
||||
VVSLOW
|
||||
};
|
||||
|
||||
enum TileEffect {
|
||||
EFFECT_NONE,
|
||||
EFFECT_FIRE,
|
||||
EFFECT_SLEEP,
|
||||
EFFECT_POISON,
|
||||
EFFECT_POISONFIELD,
|
||||
EFFECT_ELECTRICITY,
|
||||
EFFECT_LAVA
|
||||
};
|
||||
|
||||
enum TileAnimationStyle {
|
||||
ANIM_NONE,
|
||||
ANIM_SCROLL,
|
||||
ANIM_CAMPFIRE,
|
||||
ANIM_CITYFLAG,
|
||||
ANIM_CASTLEFLAG,
|
||||
ANIM_SHIPFLAG,
|
||||
ANIM_LCBFLAG,
|
||||
ANIM_FRAMES
|
||||
};
|
||||
|
||||
/**
|
||||
* An Uncopyable has no default copy constructor of operator=. A subclass may derive from
|
||||
* Uncopyable at any level of visibility, even private, and subclasses will not have a default copy
|
||||
* constructor or operator=. See also, boost::noncopyable Uncopyable (from the Boost project) and
|
||||
* Item 6 from Scott Meyers Effective C++.
|
||||
*/
|
||||
class Uncopyable {
|
||||
protected:
|
||||
Uncopyable() {}
|
||||
~Uncopyable() {}
|
||||
|
||||
private:
|
||||
Uncopyable(const Uncopyable &);
|
||||
const Uncopyable &operator=(const Uncopyable &);
|
||||
};
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
||||
103
engines/ultima/ultima4/core/utils.cpp
Normal file
103
engines/ultima/ultima4/core/utils.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ultima/ultima4/core/utils.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
void assertMsg(bool exp, const char *desc, ...) {
|
||||
if (!exp) {
|
||||
va_list args;
|
||||
va_start(args, desc);
|
||||
Common::String msg = Common::String::vformat(desc, args);
|
||||
va_end(args);
|
||||
|
||||
error("Assertion failed: %s", msg.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void xu4_srandom() {
|
||||
// srand((uint)time(nullptr));
|
||||
}
|
||||
|
||||
int xu4_random(int upperRange) {
|
||||
if (upperRange == 0) {
|
||||
warning("No upper range specified");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return g_ultima->getRandomNumber(upperRange - 1);
|
||||
}
|
||||
|
||||
Common::String &trim(Common::String &val, const Common::String &chars_to_trim) {
|
||||
Common::String::iterator i;
|
||||
if (val.size()) {
|
||||
size_t pos;
|
||||
for (i = val.begin(); (i != val.end()) && (pos = chars_to_trim.find(*i)) != Common::String::npos;)
|
||||
i = val.erase(i);
|
||||
for (i = val.end() - 1; (i != val.begin()) && (pos = chars_to_trim.find(*i)) != Common::String::npos;)
|
||||
i = val.erase(i) - 1;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
Common::String &lowercase(Common::String &val) {
|
||||
Common::String::iterator i;
|
||||
for (i = val.begin(); i != val.end(); i++)
|
||||
*i = tolower(*i);
|
||||
return val;
|
||||
}
|
||||
|
||||
Common::String &uppercase(Common::String &val) {
|
||||
Common::String::iterator i;
|
||||
for (i = val.begin(); i != val.end(); i++)
|
||||
*i = toupper(*i);
|
||||
return val;
|
||||
}
|
||||
|
||||
Common::String xu4_to_string(int val) {
|
||||
char buffer[16];
|
||||
Common::sprintf_s(buffer, "%d", val);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
Std::vector<Common::String> split(const Common::String &s, const Common::String &separators) {
|
||||
Std::vector<Common::String> result;
|
||||
Common::String current;
|
||||
|
||||
for (unsigned i = 0; i < s.size(); i++) {
|
||||
if (separators.find(s[i]) != Common::String::npos) {
|
||||
if (current.size() > 0)
|
||||
result.push_back(current);
|
||||
current.clear();
|
||||
} else
|
||||
current += s[i];
|
||||
}
|
||||
|
||||
if (current.size() > 0)
|
||||
result.push_back(current);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
124
engines/ultima/ultima4/core/utils.h
Normal file
124
engines/ultima/ultima4/core/utils.h
Normal file
@@ -0,0 +1,124 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ULTIMA4_CORE_UTILS_H
|
||||
#define ULTIMA4_CORE_UTILS_H
|
||||
|
||||
#include "ultima/ultima4/ultima4.h"
|
||||
#include "ultima/shared/std/containers.h"
|
||||
#include "common/savefile.h"
|
||||
#include "common/hash-str.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
extern void assertMsg(bool exp, const char *desc, ...);
|
||||
|
||||
/* The AdjustValue functions used to be #define'd macros, but these are
|
||||
* evil for several reasons, *especially* when they contain multiple
|
||||
* statements, and have if statements in them. The macros did both.
|
||||
* See https://isocpp.org/wiki/faq/inline-functions#inline-vs-macros
|
||||
* for more information.
|
||||
*/
|
||||
inline void AdjustValueMax(int &v, int val, int max) {
|
||||
v += val;
|
||||
if (v > max) v = max;
|
||||
}
|
||||
inline void AdjustValueMin(int &v, int val, int min) {
|
||||
v += val;
|
||||
if (v < min) v = min;
|
||||
}
|
||||
inline void AdjustValue(int &v, int val, int max, int min) {
|
||||
v += val;
|
||||
if (v > max) v = max;
|
||||
if (v < min) v = min;
|
||||
}
|
||||
|
||||
inline void AdjustValueMax(short &v, int val, int max) {
|
||||
v += val;
|
||||
if (v > max) v = max;
|
||||
}
|
||||
inline void AdjustValueMin(short &v, int val, int min) {
|
||||
v += val;
|
||||
if (v < min) v = min;
|
||||
}
|
||||
inline void AdjustValue(short &v, int val, int max, int min) {
|
||||
v += val;
|
||||
if (v > max) v = max;
|
||||
if (v < min) v = min;
|
||||
}
|
||||
|
||||
inline void AdjustValueMax(unsigned short &v, int val, int max) {
|
||||
v += val;
|
||||
if (v > max) v = max;
|
||||
}
|
||||
inline void AdjustValueMin(unsigned short &v, int val, int min) {
|
||||
v += val;
|
||||
if (v < min) v = min;
|
||||
}
|
||||
inline void AdjustValue(unsigned short &v, int val, int max, int min) {
|
||||
v += val;
|
||||
if (v > max) v = max;
|
||||
if (v < min) v = min;
|
||||
}
|
||||
|
||||
/**
|
||||
* Seed the random number generator.
|
||||
*/
|
||||
void xu4_srandom();
|
||||
|
||||
/**
|
||||
* Generate a random number between 0 and (upperRange - 1)
|
||||
*/
|
||||
int xu4_random(int upperval);
|
||||
|
||||
/**
|
||||
* Trims whitespace from a Common::String
|
||||
* @param val The Common::String you are trimming
|
||||
* @param chars_to_trim A list of characters that will be trimmed
|
||||
*/
|
||||
Common::String &trim(Common::String &val, const Common::String &chars_to_trim = "\t\013\014 \n\r");
|
||||
|
||||
/**
|
||||
* Converts the Common::String to lowercase
|
||||
*/
|
||||
Common::String &lowercase(Common::String &val);
|
||||
|
||||
/**
|
||||
* Converts the Common::String to uppercase
|
||||
*/
|
||||
Common::String &uppercase(Common::String &val);
|
||||
|
||||
/**
|
||||
* Converts an integer value to a Common::String
|
||||
*/
|
||||
Common::String xu4_to_string(int val);
|
||||
|
||||
/**
|
||||
* Splits a Common::String into substrings, divided by the charactars in
|
||||
* separators. Multiple adjacent separators are treated as one.
|
||||
*/
|
||||
Std::vector<Common::String> split(const Common::String &s, const Common::String &separators);
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user