Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,61 @@
/* 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/shared/actions/action.h"
#include "ultima/shared/early/game.h"
#include "ultima/shared/maps/map.h"
#include "ultima/shared/gfx/visual_item.h"
#include "ultima/shared/engine/messages.h"
namespace Ultima {
namespace Shared {
namespace Actions {
Action::Action(TreeItem *parent) : TreeItem() {
assert(parent);
addUnder(parent);
}
Game *Action::getGame() {
return static_cast<Game *>(TreeItem::getGame());
}
Maps::Map *Action::getMap() {
return static_cast<Maps::Map *>(getGame()->getMap());
}
void Action::addInfoMsg(const Common::String &text, bool newLine, bool replaceLine) {
CInfoMsg msg(text, newLine, replaceLine);
msg.execute(getView());
}
void Action::playFX(uint effectId) {
getGame()->playFX(effectId);
}
void Action::endOfTurn() {
getGame()->endOfTurn();
}
} // End of namespace Actions
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,85 @@
/* 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 ULTIMA_SHARED_ACTIONS_ACTION_H
#define ULTIMA_SHARED_ACTIONS_ACTION_H
#include "ultima/shared/core/tree_item.h"
namespace Ultima {
namespace Shared {
class Game;
namespace Maps {
class Map;
}
namespace Actions {
/**
* Base class for implementing the various actions the player can do, such as moving, climbing, entering, etc.
*/
class Action : public TreeItem {
protected:
/**
* Signals the end of the turn
*/
void endOfTurn();
public:
/**
* Constructor
*/
Action(TreeItem *parent);
/**
* Destructor
*/
~Action() override {}
/**
* Jumps up through the parents to find the root game
*/
Game *getGame();
/**
* Return the game's map
*/
Maps::Map *getMap();
/**
* Adds a text string to the info area
* @param text Text to add
* @param newLine Whether to apply a newline at the end
*/
void addInfoMsg(const Common::String &text, bool newLine = true, bool replaceLine = false);
/**
* Play a sound effect
*/
void playFX(uint effectId);
};
} // End of namespace Actions
} // End of namespace Shared
} // End of namespace Ultima
#endif

View 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/>.
*
*/
#include "ultima/shared/actions/huh.h"
namespace Ultima {
namespace Shared {
namespace Actions {
BEGIN_MESSAGE_MAP(Huh, Action)
ON_MESSAGE(HuhMsg)
END_MESSAGE_MAP()
bool Huh::HuhMsg(CHuhMsg *msg) {
addInfoMsg(_text);
endOfTurn();
return true;
}
} // End of namespace Actions
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,55 @@
/* 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 ULTIMA_SHARED_ACTIONS_HUH_H
#define ULTIMA_SHARED_ACTIONS_HUH_H
#include "ultima/shared/actions/action.h"
#include "ultima/shared/engine/messages.h"
namespace Ultima {
namespace Shared {
namespace Actions {
class Huh : public Action {
DECLARE_MESSAGE_MAP;
bool HuhMsg(CHuhMsg *msg);
private:
const char *&_text;
public:
CLASSDEF;
/**
* Constructor
*/
Huh(TreeItem *parent, const char *&text) : Action(parent), _text(text) {}
/**
* Destructor
*/
~Huh() override {}
};
} // End of namespace Actions
} // End of namespace Shared
} // End of namespace Ultima
#endif

View 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/>.
*
*/
#include "ultima/shared/actions/pass.h"
namespace Ultima {
namespace Shared {
namespace Actions {
BEGIN_MESSAGE_MAP(Pass, Action)
ON_MESSAGE(PassMsg)
END_MESSAGE_MAP()
bool Pass::PassMsg(CPassMsg *msg) {
addInfoMsg(_text);
endOfTurn();
return true;
}
} // End of namespace Actions
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,55 @@
/* 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 ULTIMA_SHARED_ACTIONS_PASS_H
#define ULTIMA_SHARED_ACTIONS_PASS_H
#include "ultima/shared/actions/action.h"
#include "ultima/shared/engine/messages.h"
namespace Ultima {
namespace Shared {
namespace Actions {
class Pass : public Action {
DECLARE_MESSAGE_MAP;
bool PassMsg(CPassMsg *msg);
private:
const char *&_text;
public:
CLASSDEF;
/**
* Constructor
*/
Pass(TreeItem *parent, const char *&text) : Action(parent), _text(text) {}
/**
* Destructor
*/
~Pass() override {}
};
} // End of namespace Actions
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,101 @@
/* 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 SHARED_CONF_CONF_SERIALIZER_H
#define SHARED_CONF_CONF_SERIALIZER_H
#include "common/config-manager.h"
namespace Ultima {
namespace Shared {
/**
* A simplified serializer class for reading/writing stuff from ConfMan
*/
class ConfSerializer {
private:
bool _isSaving;
public:
/**
* Constructor
*/
ConfSerializer(bool saving) : _isSaving(saving) {}
/**
* Destructor
*/
~ConfSerializer() {
if (_isSaving)
ConfMan.flushToDisk();
}
/**
* Returns true if saving
*/
bool isSaving() const {
return _isSaving;
}
/**
* Returns true if loading
*/
bool isLoading() const {
return !_isSaving;
}
/**
* Syncs a string
*/
void syncAsString(const Common::String &key, Common::String &value,
const char *defaultValue = nullptr) {
if (_isSaving)
ConfMan.set(key, value);
else
value = ConfMan.hasKey(key) ? ConfMan.get(key) : Common::String(defaultValue);
}
/**
* Syncs a boolean
*/
void syncAsBool(const Common::String &key, bool &value,
bool defaultValue = false) {
if (_isSaving)
ConfMan.setBool(key, value);
else
value = ConfMan.hasKey(key) ? ConfMan.getBool(key) : defaultValue;
}
/**
* Syncs an integer
*/
template<typename T>
void syncAsInt(const Common::String &key, T &value, T defaultValue = 0) {
if (_isSaving)
ConfMan.setInt(key, value);
else
value = ConfMan.hasKey(key) ? ConfMan.getInt(key) : defaultValue;
}
};
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,550 @@
/* 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/shared/conf/xml_node.h"
#include "ultima/shared/conf/xml_tree.h"
#include "common/file.h"
namespace Ultima {
namespace Shared {
XMLNode::~XMLNode() {
for (auto *node : _nodeList) {
delete node;
}
}
const Common::String &XMLNode::reference(const Common::String &h, bool &exists) {
if (h.find('/') == Common::String::npos) {
// Must refer to me.
if (_id == h) {
exists = true;
return _text;
}
} else {
// Otherwise we want to split the Common::String at the first /
// then locate the branch to walk, and pass the rest
// down.
Common::String k;
k = h.substr(h.find('/') + 1);
Common::String k2 = k.substr(0, k.find('/'));
for (auto *node : _nodeList) {
if (node->_id == k2)
return node->reference(k, exists);
}
}
exists = false;
return _emptyString;
}
const XMLNode *XMLNode::subtree(const Common::String &h) const {
if (h.find('/') == Common::String::npos) {
// Must refer to me.
if (_id.equalsIgnoreCase(h))
return this;
} else {
// Otherwise we want to split the Common::String at the first /
// then locate the branch to walk, and pass the rest
// down.
Common::String k;
k = h.substr(h.find('/') + 1);
Common::String k2 = k.substr(0, k.find('/'));
for (auto *node : _nodeList) {
if (node->_id.equalsIgnoreCase(k2)) {
return node->subtree(k);
}
}
}
return nullptr;
}
Common::String XMLNode::dump(int depth) {
Common::String s;
for (int i = 0; i < depth; ++i)
s += ' ';
s += "<";
s += _id;
s += ">";
if (_id[_id.size() - 1] != '/') {
if (_nodeList.empty() == false)
s += "\n";
for (auto *node : _nodeList) {
s += node->dump(depth + 1);
}
if (!_text.empty()) {
//s += Common::String(depth,' ');
s += encodeEntity(_text);
}
if (_id[0] == '?') {
return s;
}
//if(_content.size())
// s += "\n";
if (!_noClose) {
if (_text.empty()) {
for (int i = 0; i < depth; ++i)
s += ' ';
}
s += "</";
s += closeTag(_id);
s += ">\n";
}
}
return s;
}
void XMLNode::xmlAssign(const Common::String &key, const Common::String &value) {
if (key.find('/') == Common::String::npos) {
// Must refer to me.
if (_id == key)
_text = value;
else
error("Walking the XML tree failed to create a final node.");
return;
}
Common::String k;
k = key.substr(key.find('/') + 1);
Common::String k2 = k.substr(0, k.find('/'));
for (auto *node : _nodeList) {
if (node->_id == k2) {
node->xmlAssign(k, value);
return;
}
}
// No match, so create a new node and do recursion
XMLNode *t = new XMLNode(_tree);
t->_parent = this;
t->_id = k2;
_nodeList.push_back(t);
(*t).xmlAssign(k, value);
}
void XMLNode::listKeys(const Common::String &key, Common::Array<Common::String> &vs,
bool longformat) const {
Common::String s(key);
s += "/";
for (auto *node : _nodeList) {
if (!longformat)
vs.push_back(node->_id);
else
vs.push_back(s + node->_id);
}
}
Common::String XMLNode::encodeEntity(const Common::String &s) {
Common::String ret;
for (const auto &c : s) {
switch (c) {
case '<':
ret += "&lt;";
break;
case '>':
ret += "&gt;";
break;
case '"':
ret += "&quot;";
break;
case '\'':
ret += "&apos;";
break;
case '&':
ret += "&amp;";
break;
default:
ret += c;
}
}
return ret;
}
static Common::String decode_entity(const Common::String &s, size_t &pos) {
// size_t old_pos = pos;
size_t entityNameLen = s.findFirstOf("; \t\r\n", pos) - pos - 1;
/* Call me paranoid... but I don't think having an end-of-line or similar
inside a &...; expression is 'good', valid though it may be. */
assert(s[pos + entityNameLen + 1] == ';');
Common::String entity_name = s.substr(pos + 1, entityNameLen);
pos += entityNameLen + 2;
// Std::cout << "DECODE: " << entity_name << endl;
if (entity_name == "amp")
return Common::String("&");
else if (entity_name == "apos")
return Common::String("'");
else if (entity_name == "quot")
return Common::String("\"");
else if (entity_name == "lt")
return Common::String("<");
else if (entity_name == "gt")
return Common::String(">");
else if (entity_name.hasPrefix("#")) {
entity_name.deleteChar(0);
if (entity_name.hasPrefix("x")) {
uint tmp = 0;
int read = sscanf(entity_name.c_str() + 1, "%xh", &tmp);
if (read < 1)
error("strToInt failed on string \"%s\"", entity_name.c_str());
return Common::String((char)tmp);
} else {
uint tmp = atol(entity_name.c_str());
return Common::String((char)tmp);
}
} else {
error("Invalid xml encoded entity - %s", entity_name.c_str());
}
}
XMLNode *XMLNode::xmlParseDoc(XMLTree *tree, const Common::String &s) {
Common::String sbuf(s);
size_t nn = 0;
bool parsedXmlElement = false, parsedDocType = false;
XMLNode *node = nullptr, *child = nullptr;
for (;;) {
while (nn < s.size() && Common::isSpace(s[nn]))
++nn;
if (nn >= s.size())
return node;
if (s[nn] != '<') {
warning("expected '<' while reading config file, found %c\n", s[nn]);
return nullptr;
}
++nn;
if (nn < s.size() && s[nn] == '?') {
assert(!parsedXmlElement);
parsedXmlElement = true;
nn = s.findFirstOf('>', nn);
} else if (nn < s.size() && s.substr(nn, 8).equalsIgnoreCase("!doctype")) {
assert(!parsedDocType);
parsedDocType = true;
parseDocTypeElement(s, nn);
} else {
--nn;
child = xmlParse(tree, sbuf, nn);
if (child) {
if (node)
error("Invalid multiple xml nodes at same level");
node = child;
}
continue;
}
// If this point was reached, we just skipped ?xml or doctype element
++nn;
}
return node;
}
void XMLNode::parseDocTypeElement(const Common::String &s, size_t &nn) {
nn = s.findFirstOf(">[", nn);
if (nn == Common::String::npos)
// No ending tag
return;
if (s[nn] == '[') {
// Square bracketed area
nn = s.findFirstOf(']', nn) + 1;
}
if (nn >= s.size() || s[nn] != '>')
nn = Common::String::npos;
}
XMLNode *XMLNode::xmlParse(XMLTree *tree, const Common::String &s, size_t &pos) {
bool inTag = false, isSelfEnding = false;
XMLNode *node = nullptr, *child = nullptr;
Common::String nodeText, plainText;
while (pos < s.size()) {
if (inTag && nodeText.hasPrefix("!--") && (s[pos] != '>' || !nodeText.hasSuffix("--"))) {
// It's a > within the comment, but not the terminator
nodeText += s[pos];
++pos;
continue;
}
switch (s[pos]) {
case '<':
// Start of tag
assert(!inTag);
trim(plainText);
if (!plainText.empty()) {
// Plain text, return it
child = new XMLNode(tree);
child->_text = plainText;
return child;
}
// New tag?
if (s[pos + 1] == '/') {
// No. It's a close tag. Move beyond it
while (s[pos] != '>')
pos++;
++pos;
// Return nullptr as indication that the end was reached
return nullptr;
}
inTag = true;
++pos;
break;
case '>':
// End of tag
isSelfEnding = nodeText.hasSuffix("/");
++pos;
if (isSelfEnding) {
nodeText.deleteLastChar();
} else if (nodeText.hasPrefix("!--")) {
// Comment element that can be ignored
inTag = false;
nodeText.clear();
plainText.clear();
break;
}
// Create a node for the tag, and parse it's attributes, if any
node = new XMLNode(tree);
node->parseNodeText(nodeText);
if (!isSelfEnding) {
// Iterate through parsing and adding sub-elements
while ((child = xmlParse(tree, s, pos)) != nullptr) {
child->_parent = node;
node->_nodeList.push_back(child);
}
} else if (node->_id.equalsIgnoreCase("xi:include")) {
// Element is a placeholder for inclusion of a secondary XML file
Common::String fname = node->_attributes["href"];
delete node;
node = xmlParseFile(tree, Common::Path(fname, '/'));
}
return node;
case '&':
if (inTag)
nodeText += decode_entity(s, pos);
else
plainText += decode_entity(s, pos);
break;
default:
if (inTag)
nodeText += s[pos++];
else
plainText += s[pos++];
break;
}
}
return node;
}
void XMLNode::parseNodeText(const Common::String &nodeText) {
size_t firstSpace = nodeText.findFirstOf(' ');
if (firstSpace == Common::String::npos) {
// The entire text is the id
_id = nodeText;
return;
}
// Set the Id and get out the remaining attributes section, if any
_id = Common::String(nodeText.c_str(), firstSpace);
Common::String attr(nodeText.c_str() + firstSpace);
for (;;) {
// Skip any spaces
while (!attr.empty() && Common::isSpace(attr[0]))
attr.deleteChar(0);
if (attr.empty())
return;
// Find the equals after the attribute name
size_t equalsPos = attr.findFirstOf('=');
if (equalsPos == Common::String::npos)
return;
// Get the name, and find the quotes start
Common::String name = Common::String(attr.c_str(), equalsPos);
++equalsPos;
while (equalsPos < attr.size() && Common::isSpace(attr[equalsPos]))
++equalsPos;
if (attr[equalsPos] == '\'' && attr[equalsPos] != '"')
return;
// Find the end of the attribute
size_t attrEnd = attr.findFirstOf(attr[equalsPos], equalsPos + 1);
if (attrEnd == Common::String::npos)
return;
// Add the parsed attribute
_attributes[name] = Common::String(attr.c_str() + equalsPos + 1, attr.c_str() + attrEnd);
// Remove the parsed attribute
attr = Common::String(attr.c_str() + attrEnd + 1);
}
}
XMLNode *XMLNode::xmlParseFile(XMLTree *tree, const Common::Path &fname) {
const Common::Path rootFile = tree->_filename;
Common::Path filename = rootFile.getParent().join(fname);
Common::File f;
if (!f.open(filename))
error("Could not open xml file - %s", filename.toString().c_str());
// Read in the file contents
char *buf = new char[f.size() + 1];
f.read(buf, f.size());
buf[f.size()] = '\0';
Common::String text(buf, buf + f.size());
delete[] buf;
f.close();
// Parse the sub-xml
XMLNode *result = xmlParseDoc(tree, text);
if (!result)
error("Error passing xml - %s", fname.toString().c_str());
return result;
}
bool XMLNode::searchPairs(KeyTypeList &ktl, const Common::String &basekey,
const Common::String &currkey, const unsigned int pos) {
/* If our 'current key' is longer then the key we're serching for
we've obviously gone too deep in this branch, and we won't find
it here. */
if ((currkey.size() <= basekey.size()) && (_id[0] != '!')) {
/* If we've found it, return every key->value pair under this key,
then return true, since we've found the key we were looking for.*/
if (basekey == currkey + _id) {
for (auto *node : _nodeList) {
if (node->_id[0] != '!')
node->selectPairs(ktl, "");
}
return true;
}
/* Else, keep searching for the key under it's subnodes */
else {
for (auto *node : _nodeList) {
if (node->searchPairs(ktl, basekey, currkey + _id + '/', pos))
return true;
}
}
}
return false;
}
/* Just adds every key->value pair under the this node to the ktl */
void XMLNode::selectPairs(KeyTypeList &ktl, const Common::String &currkey) {
ktl.push_back(KeyType(currkey + _id, currkey));
for (auto *node : _nodeList) {
node->selectPairs(ktl, currkey + _id + '/');
}
}
XMLNode *XMLNode::getPrior() const {
const Common::Array<XMLNode *> &siblings = _parent->_nodeList;
for (uint idx = 0; idx < siblings.size(); ++idx) {
if (siblings[idx] == this)
return (idx > 0) ? siblings[idx - 1] : nullptr;
}
return nullptr;
}
XMLNode *XMLNode::getNext() const {
const Common::Array<XMLNode *> &siblings = _parent->_nodeList;
for (uint idx = 0; idx < siblings.size(); ++idx) {
if (siblings[idx] == this)
return (idx < (siblings.size() - 1)) ? siblings[idx + 1] : nullptr;
}
return nullptr;
}
void XMLNode::freeDoc() {
delete _tree;
}
void XMLNode::trim(Common::String &s) {
// Convert any CRLF to just LF
size_t pos;
while ((pos = s.find("\r\n")) != Common::String::npos)
s.deleteChar(pos);
// Then check if the string is entirely whitespace
bool hasContent = false;
for (uint idx = 0; idx < s.size() && !hasContent; ++idx)
hasContent = !Common::isSpace(s[idx]);
if (!hasContent) {
s = "";
return;
}
// Remove any spaces from the very start of the string and following
// any linefeeds. This handles any indented text within the xml
for (size_t startPos = 0; startPos != Common::String::npos;
startPos = s.findFirstOf('\n', startPos + 1)) {
pos = (startPos == 0) ? 0 : startPos + 1;
while (pos < s.size() && s[pos] == ' ')
s.deleteChar(pos);
}
}
Common::String XMLNode::closeTag(const Common::String &s) {
if (s.find(" ") == Common::String::npos)
return s;
return s.substr(0, s.find(" "));
}
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,166 @@
/* 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 SHARED_CONF_XML_NODE_H
#define SHARED_CONF_XML_NODE_H
#include "common/array.h"
#include "common/hash-str.h"
#include "common/path.h"
#include "common/str.h"
#include "common/util.h"
namespace Ultima {
namespace Shared {
class XMLTree;
class XMLNode {
private:
XMLTree *_tree;
XMLNode *_parent;
Common::String _id;
Common::String _text;
Common::Array<XMLNode *> _nodeList;
Common::StringMap _attributes;
bool _noClose;
Common::String _emptyString;
private:
static void parseDocTypeElement(const Common::String &s, size_t &nn);
void parseNodeText(const Common::String &nodeText);
/**
* Trim down any whitespaces in the passed text
*/
static void trim(Common::String &s);
/**
* Parses a specified file and returns the root node for it
*/
static XMLNode *xmlParseFile(XMLTree *tree, const Common::Path &fname);
static Common::String closeTag(const Common::String &s);
static Common::String encodeEntity(const Common::String &s);
public:
XMLNode(XMLTree *tree, XMLNode *parent = nullptr) : _tree(tree), _parent(parent), _noClose(false) {}
XMLNode(const XMLNode &n) : _tree(n._tree), _parent(n._parent), _id(n._id),
_text(n._text), _nodeList(n._nodeList), _noClose(false) {}
~XMLNode();
XMLNode &operator=(const XMLNode &n) {
_id = n._id;
_text = n._text;
_nodeList = n._nodeList;
_noClose = n._noClose;
return *this;
}
const Common::String &reference(const Common::String &, bool &);
const XMLNode *subtree(const Common::String &) const;
const Common::String &id() const {
return _id;
}
const Common::String &text(void) const {
return _text;
}
bool nodeIsText() const {
return !_text.empty();
}
XMLNode *getParent() const {
return _parent;
}
bool hasChildren() const {
return !_nodeList.empty();
}
XMLNode *firstChild() const {
return _nodeList.empty() ? nullptr : _nodeList[0];
}
const Common::StringMap &attributes() const {
return _attributes;
}
bool hasProperty(const Common::String &attrName) const {
return _attributes.contains(attrName);
}
Common::String getProperty(const Common::String &attrName) const {
return _attributes.contains(attrName) ? _attributes[attrName] : "";
}
int getPropertyInt(const Common::String &attrName) const {
return _attributes.contains(attrName) ? atol(_attributes[attrName].c_str()) : 0;
}
bool getPropertyBool(const Common::String &attrName) const {
if (_attributes.contains(attrName)) {
Common::String str = _attributes[attrName];
return toupper(str[0]) == 'T' || str == "1";
} else {
return false;
}
}
Common::String operator[](const Common::String &attrName) const {
return getProperty(attrName);
}
const Common::Array<XMLNode *> &children() const {
return _nodeList;
}
typedef Common::Pair<Common::String, Common::String> KeyType;
typedef Common::Array<KeyType> KeyTypeList;
/**
* Returns a list of key->value pairs that are found under the provided 'basekey'.
* Ignores comments (<!-- ... --> and doesn't return them.
* Returns true if search is 'finished'
*/
bool searchPairs(KeyTypeList &ktl, const Common::String &basekey,
const Common::String &currkey, const unsigned int pos);
void selectPairs(KeyTypeList &ktl, const Common::String &currkey);
Common::String dump(int depth = 0);
void xmlAssign(const Common::String &key, const Common::String &value);
static XMLNode *xmlParseDoc(XMLTree *tree, const Common::String &s);
static XMLNode *xmlParse(XMLTree *tree, const Common::String &s, size_t &pos);
void listKeys(const Common::String &, Common::Array<Common::String> &,
bool longformat = true) const;
/**
* Deletes the entire tree this node belongs to, including itself
*/
void freeDoc();
/**
* Gets the prior sibling to this one
*/
XMLNode *getPrior() const;
/**
* Gets the following sibling to this one
*/
XMLNode *getNext() const;
};
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,196 @@
/* 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/shared/conf/xml_tree.h"
#include "ultima/shared/conf/xml_node.h"
#include "common/algorithm.h"
#include "common/file.h"
namespace Ultima {
namespace Shared {
XMLTree::XMLTree() : _tree(nullptr), _isFile(false),
_readOnly(false) {
}
XMLTree::XMLTree(const Common::Path &fname) : _tree(nullptr), _isFile(true),
_readOnly(false) {
readConfigFile(fname);
}
XMLTree::XMLTree(Common::SeekableReadStream *stream)
: _tree(nullptr), _isFile(true), _readOnly(false) {
readConfigStream(stream);
}
XMLTree::~XMLTree() {
delete _tree;
}
void XMLTree::clear() {
delete _tree;
_tree = nullptr;
_isFile = false;
_readOnly = false;
}
bool XMLTree::readConfigFile(const Common::Path &fname) {
Common::File f;
_filename = fname;
if (!f.open(fname)) {
warning("Error opening config file");
return false;
}
bool result = readConfigStream(&f);
f.close();
_filename = fname;
return result;
}
bool XMLTree::readConfigStream(Common::SeekableReadStream *stream) {
// Read in the stream contents
char *buf = new char[stream->size() + 1];
stream->read(buf, stream->size());
buf[stream->size()] = '\0';
Common::String text(buf, buf + stream->size());
if (!readConfigString(buf))
return false;
delete[] buf;
_isFile = true; // readConfigString sets _isFile = false
return true;
}
bool XMLTree::readConfigString(const Common::String &s) {
_tree = _tree->xmlParseDoc(this, s);
_isFile = false;
_filename.clear();
return _tree != nullptr;
}
Common::String XMLTree::dump() {
return _tree->dump();
}
void XMLTree::write() {
if (!_isFile || _readOnly)
return;
Common::DumpFile df;
if (df.open(_filename)) {
Common::String content = dump();
df.write(content.c_str(), content.size());
df.close();
}
}
const XMLNode *XMLTree::getNode(const Common::String &key) const {
return _tree->subtree(key);
}
bool XMLTree::hasNode(const Common::String &key) const {
const XMLNode *sub = _tree->subtree(key);
if (sub)
return true;
else
return false;
}
bool XMLTree::checkRoot(const Common::String &key) const {
Common::String k = key.substr(0, key.find('/'));
return _tree && k == _tree->id();
}
void XMLTree::value(const Common::String &key, Common::String &ret,
const char *defaultvalue) const {
const XMLNode *sub = _tree->subtree(key);
if (sub) {
ret = sub->text();
if (ret.empty())
if (sub->firstChild())
ret = sub->firstChild()->text();
}
else
ret = defaultvalue;
}
void XMLTree::value(const Common::String &key, int &ret,
int defaultvalue) const {
const XMLNode *sub = _tree->subtree(key);
if (sub)
ret = strtol(sub->text().c_str(), 0, 0);
else
ret = defaultvalue;
}
void XMLTree::value(const Common::String &key, bool &ret,
bool defaultvalue) const {
const XMLNode *sub = _tree->subtree(key);
if (sub)
ret = sub->text().equalsIgnoreCase("YES");
else
ret = defaultvalue;
}
void XMLTree::set(const Common::String &key, const Common::String &value) {
_tree->xmlAssign(key, value);
}
void XMLTree::set(const Common::String &key, const char *value) {
_tree->xmlAssign(key, value);
}
void XMLTree::set(const Common::String &key, int value) {
char buf[32];
snprintf(buf, 32, "%d", value);
set(key, buf);
}
void XMLTree::set(const Common::String &key, bool value) {
if (value)
set(key, "yes");
else
set(key, "no");
}
Common::Array<Common::String> XMLTree::listKeys(const Common::String &key, bool longformat) {
Common::Array<Common::String> keys;
const XMLNode *sub = _tree->subtree(key);
if (sub)
sub->listKeys(key, keys, longformat);
return keys;
}
void XMLTree::getSubkeys(KeyTypeList &ktl, const Common::String &basekey) {
_tree->searchPairs(ktl, basekey, Common::String(), 0);
}
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,95 @@
/* 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 SHARED_CONF_XML_TREE_H
#define SHARED_CONF_XML_TREE_H
#include "common/array.h"
#include "common/path.h"
#include "common/str.h"
#include "common/stream.h"
#include "common/util.h"
namespace Ultima {
namespace Shared {
class XMLNode;
class XMLTree {
friend class XMLNode;
private:
XMLNode *_tree;
Common::Path _filename;
bool _isFile;
bool _readOnly;
public:
XMLTree();
XMLTree(const Common::Path &fname);
XMLTree(Common::SeekableReadStream *stream);
~XMLTree();
bool readConfigFile(const Common::Path &fname);
bool readConfigStream(Common::SeekableReadStream *stream);
bool readConfigString(const Common::String &s);
void clear();
Common::String dump();
void write();
void setReadonly() {
_readOnly = true;
}
bool isReadonly() const {
return _readOnly;
}
XMLNode *getTree() const {
return _tree;
}
const XMLNode *getNode(const Common::String &key) const;
bool hasNode(const Common::String &key) const;
bool checkRoot(const Common::String &key) const;
// get value
void value(const Common::String &key, Common::String &ret,
const char *defaultvalue = "") const;
void value(const Common::String &key, int &ret, int defaultvalue = 0) const;
void value(const Common::String &key, bool &ret, bool defaultvalue = false) const;
// set value
void set(const Common::String &key, const Common::String &value);
void set(const Common::String &key, const char *value);
void set(const Common::String &key, int value);
void set(const Common::String &key, bool value);
Common::Array<Common::String> listKeys(const Common::String &key, bool longformat = false);
typedef Common::Pair<Common::String, Common::String> KeyType;
typedef Common::Array<KeyType> KeyTypeList;
void getSubkeys(KeyTypeList &ktl, const Common::String &basekey);
};
} // End of namespace Shared
} // End of namespace Ultima
#endif

View 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/>.
*
*/
#include "ultima/shared/core/base_object.h"
#include "ultima/shared/core/tree_item.h"
#include "ultima/shared/core/named_item.h"
namespace Ultima {
namespace Shared {
ClassDef BaseObject::type() {
return ClassDef("BaseObject", nullptr);
}
bool BaseObject::isInstanceOf(const ClassDef &classDef) const {
ClassDef def = getType();
for (;;) {
if (def == classDef)
return true;
if (!def.hasParent())
break;
def = def.parent();
}
return false;
}
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,88 @@
/* 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 ULTIMA_SHARED_CORE_BASE_OBJECT_H
#define ULTIMA_SHARED_CORE_BASE_OBJECT_H
#include "common/scummsys.h"
#include "common/array.h"
#include "common/hash-str.h"
#include "common/list.h"
#include "ultima/shared/core/file.h"
namespace Ultima {
namespace Shared {
class BaseObject;
class ClassDef;
typedef ClassDef(*ClassDefFn)();
/**
* Encapsulation of a class definition. Used as part of the message dispatch system
* to identify classes that implement particular messages
*/
class ClassDef {
private:
ClassDefFn _parentFn;
public:
const char *_className;
public:
ClassDef(const char *className, const ClassDefFn parentFn) :
_className(className), _parentFn(parentFn) {
}
bool hasParent() const {
return _parentFn != nullptr;
}
ClassDef parent() const {
return (*_parentFn)();
}
bool operator==(const ClassDef &right) const {
return !strcmp(_className, right._className);
}
};
#define CLASSDEF \
static ::Ultima::Shared::ClassDef type(); \
::Ultima::Shared::ClassDef getType() const override { return type(); }
/**
* Defines the most basic root of the engine's object hierarchy.
*/
class BaseObject {
public:
static ::Ultima::Shared::ClassDef type();
virtual ::Ultima::Shared::ClassDef getType() const { return type(); }
virtual ~BaseObject() {
}
/**
* Returns true if a given object is of the type defined by the class definition,
* or one of it's descendants
*/
bool isInstanceOf(const ClassDef &classDef) const;
};
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,63 @@
/* 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/shared/core/party.h"
namespace Ultima {
namespace Shared {
template<typename T>
void syncArray(Common::Array<T *> &items, Common::Serializer &s) {
uint count = items.size();
s.syncAsByte(count);
if (s.isLoading())
assert(count == items.size());
for (uint idx = 0; idx < items.size(); ++idx)
items[idx]->synchronize(s);
}
void Character::synchronize(Common::Serializer &s) {
s.syncString(_name);
s.syncAsByte(_race);
s.syncAsByte(_sex);
s.syncAsByte(_class);
s.syncAsUint16LE(_strength);
s.syncAsUint16LE(_agility);
s.syncAsUint16LE(_stamina);
s.syncAsUint16LE(_charisma);
s.syncAsUint16LE(_wisdom);
s.syncAsUint16LE(_intelligence);
s.syncAsUint32LE(_hitPoints);
s.syncAsUint32LE(_experience);
s.syncAsUint32LE(_food);
s.syncAsUint32LE(_coins);
s.syncAsSByte(_equippedWeapon);
s.syncAsSByte(_equippedArmour);
s.syncAsSByte(_equippedSpell);
syncArray<Weapon>(_weapons, s);
syncArray<Armour>(_armour, s);
syncArray<Spell>(_spells, s);
}
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,231 @@
/* 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 ULTIMA_SHARED_CORE_CHARACTER_H
#define ULTIMA_SHARED_CORE_CHARACTER_H
#include "common/array.h"
#include "common/str.h"
#include "common/serializer.h"
#include "ultima/shared/core/named_item.h"
namespace Ultima {
namespace Shared {
enum Sex { SEX_MALE = 0, SEX_FEMALE = 1, SEX_OTHER = 2, SEX_YES_PLEASE = 2 };
/**
* Base class for class types that have a quantity
*/
class Itemized {
public:
uint _quantity;
public:
/**
* Constructor
*/
Itemized() : _quantity(0) {}
/**
* Destructor
*/
virtual ~Itemized() {}
/**
* Synchronize data
*/
void synchronize(Common::Serializer &s) {
s.syncAsUint16LE(_quantity);
}
/**
* Change the quantity by a given amount
*/
virtual void changeQuantity(int delta) {
_quantity = (uint)CLIP((int)_quantity + delta, 0, 9999);
}
/**
* Increase the quantity by 1
*/
void incrQuantity() { changeQuantity(1); }
/**
* Returns if the itemized is empty
*/
bool empty() const { return _quantity == 0; }
/**
* Decrease the quantity by 1
*/
bool decrQuantity() {
changeQuantity(-1);
return empty();
}
};
/**
* Weapon entry
*/
class Weapon : public Itemized {
public:
Common::String _shortName, _longName;
uint _distance;
public:
/**
* Constructor
*/
Weapon() : Itemized(), _distance(0) {}
};
/**
* Armour entry
*/
class Armour : public Itemized {
public:
Common::String _name;
};
/**
* Spell entry
*/
class Spell : public Itemized, public NamedItem {
};
template<class T>
class ItemArray : public Common::Array<T> {
public:
/**
* Returns the number of distinct types of items in the array, not counting
* the slot 0 "nothing" slot
*/
size_t itemsCount() const {
uint total = 0;
for (uint idx = 1; idx < this->size(); ++idx) {
if (!(*this)[idx]->empty())
++total;
}
return total;
}
/**
* Returns true if the character has no items
*/
bool hasNothing() const {
return itemsCount() == 0;
}
};
/**
* Implements the data for a playable character within the game
*/
class Character {
public:
Common::String _name;
uint _race;
Sex _sex;
uint _class;
uint _strength;
uint _agility;
uint _stamina;
uint _charisma;
uint _wisdom;
uint _intelligence;
uint _hitPoints;
uint _experience;
uint _food;
uint _coins;
int _equippedWeapon;
int _equippedArmour;
int _equippedSpell;
ItemArray<Weapon *> _weapons;
ItemArray<Armour *> _armour;
ItemArray<Spell *> _spells;
public:
/**
* Constructor
*/
Character() : _strength(0), _agility(0), _stamina(0), _charisma(0), _wisdom(0), _intelligence(0),
_hitPoints(0), _experience(0), _food(0), _coins(0), _equippedWeapon(0), _equippedArmour(0), _equippedSpell(0),
_race(0), _sex(SEX_MALE), _class(0) {}
/**
* Handles loading and saving games
*/
void synchronize(Common::Serializer &s);
/**
* Returns true if a weapon is equipped
*/
bool isWeaponEquipped() const { return _equippedWeapon != 0; }
/**
* Returns true if armor is equipped
*/
bool isArmourEquipped() const { return _equippedArmour != 0; }
/**
* Returns true if a spell is equipped
*/
bool isSpellEquipped() const { return _equippedSpell != 0; }
/**
* Return the equipped weapon
*/
Weapon *equippedWeapon() const { return _weapons[_equippedWeapon]; }
/**
* Return the equipped armor
*/
Armour *equippedArmour() const { return _armour[_equippedArmour]; }
/**
* Return the equipped spell
*/
Spell *equippedSpell() const { return _spells[_equippedSpell]; }
/**
* Removes any equipped weapon
*/
void removeWeapon() { _equippedWeapon = 0; }
/**
* Removes any eqipped armor
*/
void removeArmour() { _equippedArmour = 0; }
/**
* Remove any equipped spell
*/
void removeSpell() { _equippedSpell = 0; }
/**
* Gets the character's experience level
*/
uint getLevel() const { return (_experience / 1000) + 1; }
};
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,85 @@
/* 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 "common/util.h"
#include "ultima/shared/core/file.h"
#include "ultima/shared/early/ultima_early.h"
namespace Ultima {
namespace Shared {
#define ERROR error("Could not open file - %s", name.c_str())
#define PATH_ERROR error("Could not open file - %s", name.toString(Common::Path::kNativeSeparator).c_str())
File::File(const Common::Path &name) : Common::File(), _filesize(-1) {
close();
if (!Common::File::open(name))
PATH_ERROR;
}
bool File::open(const Common::Path &name) {
close();
if (!Common::File::open(name))
PATH_ERROR;
return true;
}
bool File::open(const Common::Path &name, Common::Archive &archive) {
close();
if (!Common::File::open(name, archive))
PATH_ERROR;
return true;
}
bool File::open(const Common::FSNode &node) {
close();
Common::String name = node.getName();
if (!Common::File::open(node))
ERROR;
return true;
}
bool File::open(SeekableReadStream *stream, const Common::String &name) {
close();
if (!Common::File::open(stream, name))
ERROR;
return true;
}
void File::close() {
_filesize = -1;
Common::File::close();
}
bool File::eof() {
if (_filesize == -1)
_filesize = size();
return pos() >= _filesize;
}
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,81 @@
/* 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 ULTIMA_SHARED_CORE_FILE_H
#define ULTIMA_SHARED_CORE_FILE_H
#include "common/file.h"
#include "common/str.h"
namespace Ultima {
namespace Shared {
/**
* Simple ScummVM File descendent that throws a wobbly if the file it tries to open isn't present
*/
class File : public Common::File {
private:
int32 _filesize;
public:
File() : Common::File(), _filesize(-1) {}
File(const Common::Path &name);
/**
* Open the file with the given filename, by searching SearchMan.
* @param name the name of the file to open
*/
bool open(const Common::Path &name) override;
/**
* Open the file with the given filename from within the given archive.
* @param name the name of the file to open
* @param archive the archive in which to search for the file
*/
bool open(const Common::Path &name, Common::Archive &archive) override;
/**
* Open the file corresponding to the give node.
* @param node the node to consider.
*/
bool open(const Common::FSNode &node) override;
/**
* 'Open' the given stream. That is, we just wrap around it
* @param stream a pointer to a SeekableReadStream, or 0
* @param name a string describing the 'file' corresponding to stream
*/
bool open(SeekableReadStream *stream, const Common::String &name) override;
/**
* Close the currently open file
*/
void close() override;
/**
* Differing eof that returns true when pos == size as well as beyond
*/
bool eof();
};
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,112 @@
/* 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 ULTIMA_SHARED_CORE_GAME_STATE_H
#define ULTIMA_SHARED_CORE_GAME_STATE_H
#include "ultima/shared/core/rect.h"
#include "ultima/shared/core/character.h"
#include "ultima/shared/core/map.h"
namespace Ultima {
namespace Shared {
class Game;
enum VideoMode {
UNSET = -1, CGA = 0, EGA = 1, TGA = 2, VGA_ENHANCED = 3
};
class GameState {
protected:
Game *_game;
public:
/**
* Position in the world map. This is stored separately from the map so that the same point can
* be returned to when leaving locations
*/
Point _worldMapPos;
/**
* Characters in the party. In the earlier Ultima games, this is a single character
*/
CharacterArray _characters;
/**
* Currently active character. In earlier Ultima games, this is the single party member
*/
Character *_currentCharacter;
/**
* Pointer to the map manager for the game
*/
Map *_map;
/**
* Game type Id
*/
uint _gameId;
/**
* Video mode
*/
VideoMode _videoMode;
/**
* The number of hit points to generate when a dungeon is left
*/
uint _dungeonExitHitPoints;
/**
* Stores the base random seed used for generating deterministic dungeon levels
*/
uint32 _randomSeed;
public:
/**
* Constructor
*/
GameState(Game *game);
/**
* Destructor
*/
virtual ~GameState();
/**
* Setup the initial game state
*/
virtual void setup() {}
/**
* Returns true if the party is dead
*/
bool isPartyDead() const;
/**
* Returns true if the party has no food
*/
bool isPartyFoodless() const;
};
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,135 @@
/* 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 "common/endian.h"
#include "common/util.h"
#include "ultima/shared/core/lzw.h"
namespace Ultima {
namespace Shared {
void LZW::decompress(Common::ReadStream *source, Common::WriteStream *dest) {
int32 destSize = source->readUint32LE();
_source = source;
_currentByte = source->readByte();
byte litByte = 0;
uint16 oldCode = 0;
uint16 copyLength, maxCodeValue, code, nextCode, lastCode;
byte *copyBuf = new byte[8192];
struct {
uint16 code; byte value;
} codeTable[8192];
memset(codeTable, 0, sizeof(codeTable));
_codeLength = 9;
nextCode = 258;
maxCodeValue = 512;
copyLength = 0;
_sourceBitsLeft = 8;
for (;;) {
code = getCode();
if (code == 257)
break;
if (code == 256) {
_codeLength = 9;
nextCode = 258;
maxCodeValue = 512;
lastCode = getCode();
oldCode = lastCode;
litByte = lastCode;
dest->writeByte(litByte);
} else {
lastCode = code;
if (code >= nextCode) {
lastCode = oldCode;
copyBuf[copyLength++] = litByte;
}
while (lastCode > 255) {
copyBuf[copyLength++] = codeTable[lastCode].value;
lastCode = codeTable[lastCode].code;
}
litByte = lastCode;
copyBuf[copyLength++] = lastCode;
while (copyLength > 0)
dest->writeByte(copyBuf[--copyLength]);
codeTable[nextCode].value = lastCode;
codeTable[nextCode].code = oldCode;
nextCode++;
oldCode = code;
if (nextCode >= maxCodeValue && _codeLength <= 12) {
_codeLength++;
maxCodeValue <<= 1;
}
}
}
delete[] copyBuf;
assert(dest->pos() == destSize);
}
uint16 LZW::getCode() {
const byte bitMasks[9] = {
0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0x0FF
};
byte resultBitsLeft = _codeLength;
byte resultBitsPos = 0;
uint16 result = 0;
byte currentByte = _currentByte;
byte currentBits = 0;
// Get bits of current byte
while (resultBitsLeft) {
if (resultBitsLeft < _sourceBitsLeft) {
// we need less than we have left
currentBits = (currentByte >> (8 - _sourceBitsLeft)) &bitMasks[resultBitsLeft];
result |= (currentBits << resultBitsPos);
_sourceBitsLeft -= resultBitsLeft;
resultBitsLeft = 0;
} else {
// we need as much as we have left or more
resultBitsLeft -= _sourceBitsLeft;
currentBits = currentByte >> (8 - _sourceBitsLeft);
result |= (currentBits << resultBitsPos);
resultBitsPos += _sourceBitsLeft;
// Go to next byte
_currentByte = _source->readByte();
_sourceBitsLeft = 8;
if (resultBitsLeft) {
currentByte = _currentByte;
}
}
}
return result;
}
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,49 @@
/* 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 ULTIMA_LZW_H
#define ULTIMA_LZW_H
#include "common/stream.h"
#include "common/memstream.h"
namespace Ultima {
namespace Shared {
class LZW {
private:
Common::ReadStream *_source;
byte _sourceBitsLeft;
byte _codeLength;
byte _currentByte;
private:
uint16 getCode();
public:
/**
* Decompresses data
*/
void decompress(Common::ReadStream *source, Common::WriteStream *dest);
};
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,295 @@
/* 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/shared/core/map.h"
#include "ultima/shared/early/game.h"
#include "ultima/shared/gfx/visual_item.h"
namespace Ultima {
namespace Shared {
void MapTile::clear() {
_tileId = _tileNum = -1;
_widgetNum = -1;
_widget = nullptr;
_itemNum = -1;
_isDoor = _isSecretDoor = false;
_isLadderUp = _isLadderDown = false;
_isWall = _isHallway = _isBeams = false;
}
/*-------------------------------------------------------------------*/
void Map::MapBase::clear() {
_mapId = 0;
_data.clear();
_widgets.clear();
}
void Map::MapBase::load(MapId mapId) {
_mapId = mapId;
}
void Map::MapBase::synchronize(Common::Serializer &s) {
_viewportPos.synchronize(s);
uint size;
int transportIndex = -1;
Common::String name;
if (s.isSaving()) {
// Save widgets
size = 0;
for (uint idx = 0; idx < _widgets.size(); ++idx) {
if (_widgets[idx]->getClassName())
++size;
if (_playerWidget == _widgets[idx].get())
transportIndex = (int)idx;
}
assert(transportIndex >= 0);
s.syncAsUint16LE(size);
for (uint idx = 0; idx < _widgets.size(); ++idx) {
name = _widgets[idx]->getClassName();
if (!name.empty()) {
s.syncString(name);
_widgets[idx]->synchronize(s);
}
}
s.syncAsUint16LE(transportIndex);
} else {
// Load widgets
s.syncAsUint16LE(size);
_widgets.clear();
for (uint idx = 0; idx < size; ++idx) {
s.syncString(name);
MapWidget *w = _map->createWidget(this, name);
w->synchronize(s);
addWidget(w);
}
s.syncAsUint16LE(transportIndex);
_playerWidget = _widgets[transportIndex].get();
}
}
void Map::MapBase::setDimensions(const Point &size) {
_data.resize(size.y);
for (int y = 0; y < size.y; ++y)
_data[y]._data.resize(size.x);
_size = size;
}
Point Map::MapBase::getDirectionDelta() const {
switch (_playerWidget->_direction) {
case DIR_LEFT:
return Point(-1, 0);
case DIR_RIGHT:
return Point(1, 0);
case DIR_UP:
return Point(0, -1);
default:
return Point(0, 1);
}
}
Point Map::MapBase::getDeltaPosition(const Point &delta) {
return _playerWidget->_position + delta;
}
void Map::MapBase::resetViewport() {
// Reset the viewport, so it's position will get recalculated
_viewportPos.reset();
}
Point Map::MapBase::getViewportPosition(const Point &viewportSize) {
Point &topLeft = _viewportPos._topLeft;
if (!_viewportPos.isValid() || _viewportPos._size != viewportSize) {
// Calculate the new position
topLeft.x = _playerWidget->_position.x - (viewportSize.x - 1) / 2;
topLeft.y = _playerWidget->_position.y - (viewportSize.y - 1) / 2;
// Fixed maps, so constrain top left corner so the map fills the viewport.
// This will accommodate future renderings with more tiles, or greater tile size
topLeft.x = CLIP((int)topLeft.x, 0, (int)(width() - viewportSize.x));
topLeft.y = CLIP((int)topLeft.y, 0, (int)(height() - viewportSize.y));
}
return topLeft;
}
void Map::MapBase::shiftViewport(const Point &delta) {
Point &topLeft = _viewportPos._topLeft;
topLeft += delta;
// Shift the viewport, but constraining the map to fill up the screen
topLeft.x = CLIP(topLeft.x, (int16)0, (int16)(width() - _viewportPos._size.x));
topLeft.y = CLIP(topLeft.y, (int16)0, (int16)(height() - _viewportPos._size.y));
}
void Map::MapBase::addWidget(MapWidget *widget) {
_widgets.push_back(MapWidgetPtr(widget));
}
void Map::MapBase::removeWidget(MapWidget *widget) {
for (uint idx = 0; idx < _widgets.size(); ++idx) {
if (_widgets[idx].get() == widget) {
_widgets.remove_at(idx);
break;
}
}
}
void Map::MapBase::getTileAt(const Point &pt, MapTile *tile) {
tile->clear();
// Get the base tile
tile->_tileNum = tile->_tileId = _data[pt.y][pt.x];
// Check for any widget on that map tile
for (int idx = (int)_widgets.size() - 1; idx >= 0; --idx) {
MapWidget *widget = _widgets[idx].get();
if (widget->_position == pt) {
tile->_widgetNum = idx;
tile->_widget = widget;
break;
}
}
}
void Map::MapBase::update() {
// Call the update method of each widget, to allow for things like npc movement, etc.
for (uint idx = 0; idx < _widgets.size(); ++idx)
_widgets[idx].get()->update(true);
// Call the update method of each widget, to allow for things like npc movement, etc.
for (uint idx = 0; idx < _widgets.size(); ++idx)
_widgets[idx].get()->update(false);
}
Point Map::MapBase::getPosition() const {
return _playerWidget->_position;
}
void Map::MapBase::setPosition(const Point &pt) {
_playerWidget->_position = pt;
}
Direction Map::MapBase::getDirection() const {
return _playerWidget->_direction;
}
void Map::MapBase::setDirection(Direction dir) {
_playerWidget->_direction = dir;
}
/*------------------------------------------------------------------------*/
void MapWidget::synchronize(Common::Serializer &s) {
s.syncAsUint16LE(_position.x);
s.syncAsSint16LE(_position.y);
s.syncAsByte(_direction);
s.syncString(_name);
}
void MapWidget::addInfoMsg(const Common::String &text, bool newLine) {
CInfoMsg msg(text, newLine);
msg.execute(_game->getView());
}
MapWidget::CanMove MapWidget::canMoveTo(const Point &destPos) {
if (destPos.x < 0 || destPos.y < 0 || destPos.x >= (int)_map->width() || destPos.y >= (int)_map->height()) {
// If the map is fixed, allow moving beyond it's edges so it can be left
if (!_map->isMapWrapped())
return YES;
}
// Get the details of the position
MapTile destTile;
_map->getTileAt(destPos, &destTile);
// If there's a widget blocking the tile, return false
if (destTile._widget && destTile._widget->isBlocking())
return NO;
return UNSET;
}
void MapWidget::moveTo(const Point &destPos, Direction dir) {
// If no direction is specified, we'll need to figure it out relative to the old position
if (dir == DIR_NONE) {
Point delta = destPos - _position;
if (ABS(delta.x) > ABS(delta.y))
_direction = delta.x > 0 ? DIR_EAST : DIR_WEST;
else if (delta.y != 0)
_direction = delta.y > 0 ? DIR_SOUTH : DIR_NORTH;
} else {
_direction = dir;
}
// Set new location
_position = destPos;
// Handle wrap around if need be on maps that wrap
if (_map->isMapWrapped()) {
if (_position.x < 0)
_position.x += _map->width();
else if (_position.x >= (int)_map->width())
_position.x -= _map->width();
if (_position.y < 0)
_position.y += _map->height();
else if (_position.y >= (int)_map->height())
_position.y -= _map->height();
}
}
/*-------------------------------------------------------------------*/
void Map::clear() {
if (_mapArea)
_mapArea->clear();
_mapArea = nullptr;
}
void Map::load(MapId mapId) {
_mapArea = nullptr;
}
void Map::synchronize(Common::Serializer &s) {
int mapId;
if (s.isSaving()) {
// Saving
mapId = _mapArea->getMapId();
s.syncAsUint16LE(mapId);
} else {
// Loading
s.syncAsUint16LE(mapId);
load(mapId);
}
_mapArea->synchronize(s);
}
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,562 @@
/* 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 ULTIMA_SHARED_CORE_MAP_H
#define ULTIMA_SHARED_CORE_MAP_H
#include "common/array.h"
#include "common/ptr.h"
#include "common/serializer.h"
#include "ultima/shared/core/rect.h"
#include "ultima/shared/gfx/dungeon_surface.h"
namespace Ultima {
namespace Shared {
#define REGISTER_WIDGET(NAME) if (name == #NAME) return new Widgets::NAME(_game, (Ultima1Map::MapBase *)map)
#define DECLARE_WIDGET(NAME) const char *getClassName() const override { return #NAME; }
enum Direction {
DIR_NONE = 0,
DIR_LEFT = 1, DIR_RIGHT = 2, DIR_UP = 3, DIR_DOWN = 4,
DIR_WEST = 1, DIR_EAST = 2, DIR_NORTH = 3, DIR_SOUTH = 4
};
typedef byte MapCell;
typedef int MapId;
class Game;
class MapWidget;
typedef Common::SharedPtr<MapWidget> MapWidgetPtr;
/**
* Contains data about a given position within the map
*/
class MapTile {
public:
int _tileId; // Tile Id
int _tileNum; // Tile number to display. Normally equals Tile Id, but can differ in rare cases
int _widgetNum; // Widget number, if any
MapWidget *_widget; // Widget pointer
int _itemNum; // Item number, if any
// Dungeon tile flags
bool _isDoor, _isSecretDoor;
bool _isLadderUp, _isLadderDown;
bool _isWall, _isHallway, _isBeams;
public:
/**
* Constructor
*/
MapTile() : _tileNum(-1), _tileId(-1), _widgetNum(-1), _widget(nullptr), _itemNum(-1),
_isDoor(false), _isSecretDoor(false), _isLadderUp(false), _isLadderDown(false), _isWall(false),
_isHallway(false), _isBeams(false) {}
/**
* Destructor
*/
virtual ~MapTile() {}
/**
* Clears the map tile information
*/
virtual void clear();
/**
* Returns true if the tile is a door in a dungeon
*/
bool isDoor() const { return _isDoor; }
/**
* Returns true if the tile is a wall or secret door in a dungeon
*/
bool isWallOrSecretDoor() const { return _isWall || _isSecretDoor; }
/**
* Returns true if the tile in a dungeon is a type that has walls on it: walls, doors, or secret doors
*/
bool isWallOrDoorway() const { return _isWall || _isDoor || _isSecretDoor; }
/**
* Returns true if a tile is a solid type within a dungeon
*/
bool isSolid() const { return !(_isHallway || _isLadderUp || _isLadderDown || _isBeams); }
};
/**
* Base class for managing maps within the game
*/
class Map {
/**
* Stores state about the current viewport being displayed. It's kept as part of the Map class
* as a convenience to be alongside the current party position
*/
struct ViewportPosition {
Point _topLeft; // Top, left tile position for viewport
Point _size; // Size of the viewport. Just in case we ever allow it to change
MapId _mapId; // Maze the viewport is for. Used to detect when the map changes
/**
* Constructor
*/
ViewportPosition() : _topLeft(-1, -1), _mapId(-1) {}
/**
* Returns true if the viewport is in a valid state
*/
bool isValid() const { return _mapId != -1; }
/**
* Handles loading and saving viewport
*/
void synchronize(Common::Serializer &s) {
s.syncAsUint16LE(_topLeft.x);
s.syncAsUint16LE(_topLeft.y);
}
/**
* Resets the viewport position, so it'll get recalculated the next call to getViewportPosition
*/
void reset() { _mapId = -1; }
};
/**
* Internal class used for storing the data for a row
*/
struct MapCellsRow {
public:
Common::Array<MapCell> _data;
public:
byte &operator[](int idx) { return _data[idx]; }
byte operator[](int idx) const { return _data[idx]; }
};
public:
/**
* Base class for specific map types
*/
class MapBase {
private:
Map *_map; // Map manager reference
protected:
MapId _mapId; // The map Id
uint _mapIndex; // Index of map within the group of same maps
uint _mapStyle; // Map style category for towns & castles
ViewportPosition _viewportPos; // Viewport position
protected:
/**
* Set the size of the map
*/
void setDimensions(const Point &size);
public:
Point _size; // X, Y size of the map
Point _tilesPerOrigTile; // For enhanced modes, number of tiles per original game tile
Common::String _name; // Name of map, if applicable
MapWidget *_playerWidget; // Current means of transport, even if on foot
Common::Array<MapWidgetPtr> _widgets; // Party, monsteres, transports, etc.
Common::Array<MapCellsRow> _data; // Data for the map
public:
/**
* Constructor
*/
MapBase(Game *game, Map *map) : _map(map), _playerWidget(nullptr), _mapId(0), _mapIndex(0),
_mapStyle(0) {}
/**
* Destructor
*/
virtual ~MapBase() {}
/**
* Handles loading and saving the map's data
*/
virtual void synchronize(Common::Serializer &s);
/**
* Adds a widget to the map
*/
void addWidget(MapWidget *widget);
/**
* Removes a widget from the map
*/
void removeWidget(MapWidget *widget);
/**
* Clears all map data
*/
virtual void clear();
/**
* Gets a tile at a given position
*/
virtual void getTileAt(const Point &pt, MapTile *tile);
/**
* Resets the viewport when the viewport changes
*/
void resetViewport();
/**
* Get the viewport position
*/
virtual Point getViewportPosition(const Point &viewportSize);
/**
* Load the map
*/
virtual void load(MapId mapId);
/**
* Changes the level. Only applicable to dungeon maps which have levels
* @param delta Delta to change dungeon level by
* @returns False if dungeon left, true if still within dungeon
*/
virtual bool changeLevel(int delta) { return true; }
/**
* Get the current map level
*/
virtual uint getLevel() const { return 0; }
/**
* Returns whether the map wraps around to the other side at it's edges (i.e. the overworld)
*/
virtual bool isMapWrapped() const { return false; }
/**
* Returns the width of the map
*/
size_t width() const { return _size.x; }
/**
* Returns the height of the map
*/
size_t height() const { return _size.y; }
/**
* Get the current position
*/
Point getPosition() const;
/**
* Set the current position
*/
void setPosition(const Point &pt);
/**
* Get the current direction
*/
Direction getDirection() const;
/**
* Set the current direction
*/
void setDirection(Direction dir);
/**
* Returns a delta for the cell in front of the player based on the direction they're facing
*/
Point getDirectionDelta() const;
/**
* Gets a point relative to the current position
*/
virtual Point getDeltaPosition(const Point &delta);
/**
* Returns the map Id
*/
MapId getMapId() const { return _mapId; }
/**
* Gets the map Index
*/
uint getMapIndex() const { return _mapIndex; }
/**
* Shifts the viewport by a given delta
*/
virtual void shiftViewport(const Point &delta);
/**
* Updates the map at the end of a turn
*/
virtual void update();
};
protected:
MapBase *_mapArea;
public:
/**
* Constructor
*/
Map() : _mapArea(nullptr) {}
/**
* Destructor
*/
virtual ~Map() {}
/**
* Load a given map
*/
virtual void load(MapId mapId);
/**
* Clears all map data
*/
virtual void clear();
/**
* Handles loading and saving the map's data
*/
virtual void synchronize(Common::Serializer &s);
/**
* Instantiates a widget type by name
*/
virtual MapWidget *createWidget(Map::MapBase *map, const Common::String &name) = 0;
/**
* Gets a tile at a given position
*/
void getTileAt(const Point &pt, MapTile *tile) {
assert(_mapArea);
return _mapArea->getTileAt(pt, tile);
}
/**
* Get the viewport position
*/
Point getViewportPosition(const Point &viewportSize) {
assert(_mapArea);
return _mapArea->getViewportPosition(viewportSize);
}
/**
* Return the width of the map
*/
size_t width() const {
assert(_mapArea);
return _mapArea->width();
}
/**
* Return the height of the map
*/
size_t height() const {
assert(_mapArea);
return _mapArea->height();
}
/**
* Return the current position
*/
Point getPosition() const {
assert(_mapArea);
return _mapArea->getPosition();
}
/**
* Set the position
*/
void setPosition(const Point &pt) {
assert(_mapArea);
_mapArea->setPosition(pt);
}
/**
* Get the current direction
*/
Direction getDirection() const {
assert(_mapArea);
return _mapArea->getDirection();
}
/**
* Set the current direction
*/
void setDirection(Direction dir) {
assert(_mapArea);
_mapArea->setDirection(dir);
}
/**
* Returns a delta for the cell in front of the player based on the direction they're facing
*/
Point getDirectionDelta() const {
assert(_mapArea);
return _mapArea->getDirectionDelta();
}
/**
* Gets a point relative to the current position
*/
Point getDeltaPosition(const Point &delta) {
assert(_mapArea);
return _mapArea->getDeltaPosition(delta);
}
/**
* Shifts the viewport by a given delta
*/
void shiftViewport(const Point &delta) {
assert(_mapArea);
_mapArea->shiftViewport(delta);
}
/**
* Returns the number of tiles in the map there are for each tile in the original game.
* This allows for more detailed maps in the enhanced game modes
*/
Point getTilesPerOrigTile() const {
assert(_mapArea);
return _mapArea->_tilesPerOrigTile;
}
/**
* Return the name of the map
*/
Common::String getName() const {
assert(_mapArea);
return _mapArea->_name;
}
/**
* Returns the currently active widget that the player is controlling
*/
MapWidget *getPlayerWidget() const {
assert(_mapArea);
return _mapArea->_playerWidget;
}
/**
* @param delta Delta to change dungeon level by
* @returns False if dungeon left, true if still within dungeon
*/
bool changeLevel(int delta) {
assert(_mapArea);
return _mapArea->changeLevel(delta);
}
/**
* Get the current map level
*/
uint getLevel() const {
assert(_mapArea);
return _mapArea->getLevel();
}
/**
* Returns whether the map wraps around to the other side at it's edges (i.e. the overworld)
*/
bool isMapWrapped() const {
assert(_mapArea);
return _mapArea->isMapWrapped();
}
/**
* Updates the map at the end of a turn
*/
void update() {
assert(_mapArea);
return _mapArea->update();
}
};
/**
* Base class for things that appear within a map, such as monsters, transports, or people
*/
class MapWidget {
protected:
Game *_game; // Game reference
Map::MapBase *_map; // Map reference
public:
Point _position; // Position within the map
Direction _direction; // Direction
Common::String _name; // Name of widget
public:
/**
* Constructor
*/
MapWidget(Game *game, Map::MapBase *map) : _game(game), _map(map) {}
MapWidget(Game *game, Map::MapBase *map, const Point &pt, Direction dir = DIR_NONE) : _game(game), _map(map), _position(pt), _direction(dir) {}
MapWidget(Game *game, Map::MapBase *map, const Common::String &name, const Point &pt, Direction dir = DIR_NONE) :
_game(game), _map(map), _name(name), _position(pt), _direction(dir) {}
/**
* Destructor
*/
virtual ~MapWidget() {}
/**
* Return a name for a widget class if it can be synchronized to savegames
*/
virtual const char *getClassName() const { return nullptr; }
/**
* Handles loading and saving games
*/
virtual void synchronize(Common::Serializer &s);
/**
* Adds a text string to the info area
* @param text Text to add
* @param newLine Whether to apply a newline at the end
*/
void addInfoMsg(const Common::String &text, bool newLine = true);
/**
* Get the tile for the widget
*/
virtual uint getTileNum() const { return 0; }
/**
* Returns true if the player can move onto a tile the widget occupies
*/
virtual bool isBlocking() const { return false; }
/**
* Called to update the widget at the end of a turn
* @param isPreUpdate Update is called twice in succession during the end of turn update.
* Once with true for all widgets, then with it false
*/
virtual void update(bool isPreUpdate) {}
enum CanMove { UNSET = 0, YES = 1, NO = 2 };
/**
* Returns true if the given widget can move to a given position on the map
*/
virtual CanMove canMoveTo(const Point &destPos);
/**
* Moves the widget to a given position
* @param destPos Specified new position
* @param dir Optional explicit direction to set. If not specified,
* the direction will be set relative to the position moved from
*/
virtual void moveTo(const Point &destPos, Direction dir = DIR_NONE);
};
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,45 @@
/* 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/shared/core/message_target.h"
namespace Ultima {
namespace Shared {
ClassDef MessageTarget::type() {
return ClassDef("MessageTarget", &BaseObject::type);
}
const MSGMAP *MessageTarget::getMessageMap() const {
return getThisMessageMap();
}
const MSGMAP *MessageTarget::getThisMessageMap() {
static const MSGMAP_ENTRY _messageEntries[] = {
{ (PMSG)nullptr, nullptr }
};
static const MSGMAP messageMap = { nullptr, &_messageEntries[0] };
return &messageMap;
}
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,106 @@
/* 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 ULTIMA_SHARED_CORE_MESSAGE_TARGET_H
#define ULTIMA_SHARED_CORE_MESSAGE_TARGET_H
#include "ultima/shared/core/base_object.h"
namespace Ultima {
namespace Shared {
class MessageTarget;
class CMessage;
typedef bool (MessageTarget:: *PMSG)(CMessage *msg);
struct MSGMAP_ENTRY {
PMSG _fn;
ClassDefFn _classDef;
};
struct MSGMAP {
const MSGMAP *(*pFnGetBaseMap)();
const MSGMAP_ENTRY *lpEntries;
};
#define DECLARE_MESSAGE_MAP \
protected: \
static const Ultima::Shared::MSGMAP *getThisMessageMap(); \
const Ultima::Shared::MSGMAP *getMessageMap() const override
#define DECLARE_MESSAGE_MAP_BASE \
protected: \
static const Ultima::Shared::MSGMAP *getThisMessageMap(); \
virtual const Ultima::Shared::MSGMAP *getMessageMap() const
#define BEGIN_MESSAGE_MAP(theClass, baseClass) \
Ultima::Shared::ClassDef theClass::type() { return Ultima::Shared::ClassDef(#theClass, &baseClass::type); } \
const Ultima::Shared::MSGMAP *theClass::getMessageMap() const \
{ return getThisMessageMap(); } \
const Ultima::Shared::MSGMAP *theClass::getThisMessageMap() \
{ \
typedef theClass ThisClass; \
typedef baseClass TheBaseClass; \
typedef bool (theClass::*FNPTR)(Ultima::Shared::CMessage *msg); \
static const Ultima::Shared::MSGMAP_ENTRY _messageEntries[] = {
#define ON_MESSAGE(msgClass) \
{ static_cast<Ultima::Shared::PMSG>((FNPTR)&ThisClass::msgClass), &C##msgClass::type },
#define END_MESSAGE_MAP() \
{ (Ultima::Shared::PMSG)nullptr, nullptr } \
}; \
static const Ultima::Shared::MSGMAP messageMap = \
{ &TheBaseClass::getThisMessageMap, &_messageEntries[0] }; \
return &messageMap; \
}
#define EMPTY_MESSAGE_MAP(theClass, baseClass) \
Ultima::Shared::ClassDef theClass::type() { return Ultima::Shared::ClassDef(#theClass, &baseClass::type); } \
const Ultima::Shared::MSGMAP *theClass::getMessageMap() const \
{ return getThisMessageMap(); } \
const Ultima::Shared::MSGMAP *theClass::getThisMessageMap() \
{ \
typedef baseClass TheBaseClass; \
static const Ultima::Shared::MSGMAP_ENTRY _messageEntries[] = { \
{ (Ultima::Shared::PMSG)nullptr, nullptr } \
}; \
static const Ultima::Shared::MSGMAP messageMap = \
{ &TheBaseClass::getThisMessageMap, &_messageEntries[0] }; \
return &messageMap; \
} \
enum { DUMMY##theClass }
/**
* The immediate descendant of the base object, this implements the base class for objects
* that can receive messages
*/
class MessageTarget: public BaseObject {
DECLARE_MESSAGE_MAP_BASE;
public:
CLASSDEF;
};
} // End of namespace Shared
} // End of namespace Ultima
#endif

View 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/>.
*
*/
#include "graphics/cursorman.h"
#include "graphics/managed_surface.h"
#include "ultima/shared/core/mouse_cursor.h"
#include "ultima/shared/core/file.h"
#include "ultima/shared/early/ultima_early.h"
namespace Ultima {
namespace Shared {
void MouseCursor::MouseCursorData::load(Common::SeekableReadStream &s) {
_hotspot.x = s.readSint16LE();
_hotspot.y = s.readSint16LE();
for (int idx = 0; idx < 16; ++idx)
_pixels[idx] = s.readUint16LE();
for (int idx = 0; idx < 16; ++idx)
_mask[idx] = s.readUint16LE();
}
/*-------------------------------------------------------------------*/
MouseCursor::MouseCursor() : _cursorId(-1) {
/*
loadCursors();
_cursorId = -1;
setCursor(0);
*/
}
void MouseCursor::loadCursors() {
_cursors.clear();
File f("TODO");
while (f.pos() < f.size()) {
_cursors.push_back(MouseCursorData());
MouseCursorData &mc = _cursors.back();
mc._hotspot.x = f.readSint16LE();
mc._hotspot.y = f.readSint16LE();
for (int idx = 0; idx < 16; ++idx)
mc._mask[idx] = f.readUint16LE();
for (int idx = 0; idx < 16; ++idx)
mc._pixels[idx] = f.readUint16LE();
}
}
void MouseCursor::setCursor(int cursorId) {
// No need to do anything if we're already showing the desired cursor
if (cursorId == _cursorId)
return;
_cursorId = cursorId;
// Set up a temporary surface for rendering the cursor onto
Graphics::ManagedSurface s(16, 16);
s.fillRect(s.getBounds(), 0xff);
const MouseCursorData &data = _cursors[cursorId];
const uint16 *pixelsP = data._pixels, *maskP = data._mask;
// Iterate trhough the lines to build up the cursor
for (int y = 0; y < CURSOR_HEIGHT; ++y) {
uint16 pixVal = *pixelsP++, maskVal = *maskP++;
int bitMask = 0x8000;
byte *destP = (byte *)s.getBasePtr(0, y);
for (int x = 0; x < CURSOR_WIDTH; ++x, ++destP, bitMask >>= 1) {
if (pixVal & bitMask)
*destP = 15;
else if (!(maskVal & bitMask))
*destP = 0;
}
}
// Pass the generated surface onto the ScummVM cursor manager
CursorMan.replaceCursor(s, data._hotspot.x, data._hotspot.y, 0xff);
}
void MouseCursor::show() {
CursorMan.showMouse(true);
}
void MouseCursor::hide() {
CursorMan.showMouse(false);
}
} // End of namespace Shared
} // End of namespace Ultima

View 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/>.
*
*/
#ifndef ULTIMA_SHARED_CORE_MOUSE_CURSOR_H
#define ULTIMA_SHARED_CORE_MOUSE_CURSOR_H
#include "common/scummsys.h"
#include "ultima/shared/core/rect.h"
#include "common/stream.h"
namespace Ultima {
namespace Shared {
#define CURSOR_WIDTH 16
#define CURSOR_HEIGHT 16
/*
namespace Early {
enum CursorId {
CURSOR_ARROW = 0
};
} // End of namespace Early
namespace Later {
namespace Xanth {
enum CursorId {
CURSOR_BIG_ARROW = 0,
CURSOR_SMALL_ARROW = 1,
CURSOR_TICK = 2,
CURSOR_HOURGLASS = 3
};
} // End of namespace Xanth
} // End of namespace Later
*/
/**
* Handles the dislay and management of the on-screen mouse cursor
*/
class MouseCursor {
struct MouseCursorData {
Point _hotspot;
uint16 _pixels[16];
uint16 _mask[16];
void load(Common::SeekableReadStream &s);
};
private:
Common::Array<MouseCursorData> _cursors;
int _cursorId;
private:
/**
* Loads the mouse cursors
*/
void loadCursors();
public:
MouseCursor();
/**
* Sets the active cursor
*/
void setCursor(int cursorId);
/**
* Returns the curent cursor
*/
int getCursor() const { return _cursorId; }
/**
* Make the mouse cursor visible
*/
void show();
/**
* Hide the mouse cursor
*/
void hide();
};
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,30 @@
/* 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/shared/core/named_item.h"
namespace Ultima {
namespace Shared {
EMPTY_MESSAGE_MAP(NamedItem, TreeItem);
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,51 @@
/* 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 ULTIMA_SHARED_CORE_NAMED_ITEM_H
#define ULTIMA_SHARED_CORE_NAMED_ITEM_H
#include "ultima/shared/core/tree_item.h"
namespace Ultima {
namespace Shared {
/**
* Derived tree item class that adds a name that can be used to direct messages to later
*/
class NamedItem: public TreeItem {
DECLARE_MESSAGE_MAP;
public:
Common::String _name;
public:
CLASSDEF;
NamedItem() {}
NamedItem(const Common::String &name) : _name(name) {}
/**
* Gets the name of the item, if any
*/
const Common::String getName() const override { return _name; }
};
} // End of namespace Shared
} // End of namespace Ultima
#endif

View 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/>.
*
*/
#include "ultima/shared/core/party.h"
namespace Ultima {
namespace Shared {
Party::~Party() {
for (uint idx = 0; idx < _characters.size(); ++idx)
delete _characters[idx];
}
void Party::add(Character *c) {
_characters.push_back(c);
}
void Party::synchronize(Common::Serializer &s) {
uint partyCount = _characters.size();
s.syncAsByte(partyCount);
if (s.isLoading())
assert(partyCount == _characters.size());
// Iterate through the characters of the party
for (uint idx = 0; idx < _characters.size(); ++idx)
_characters[idx]->synchronize(s);
}
bool Party::isDead() const {
for (uint idx = 0; idx < _characters.size(); ++idx) {
if ((*this)[idx]._hitPoints > 0)
return false;
}
return true;
}
bool Party::isFoodless() const {
for (uint idx = 0; idx < _characters.size(); ++idx) {
if ((*this)[idx]._food > 0)
return false;
}
return true;
}
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,76 @@
/* 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 ULTIMA_SHARED_CORE_PARTY_H
#define ULTIMA_SHARED_CORE_PARTY_H
#include "common/array.h"
#include "common/str.h"
#include "common/serializer.h"
#include "ultima/shared/core/character.h"
namespace Ultima {
namespace Shared {
/**
* Base class for the player's party
*/
class Party {
protected:
Common::Array<Character *> _characters;
public:
~Party();
/**
* Add a character to the party
*/
void add(Character *c);
/**
* Casting operator for convenient access to the first character
*/
operator Character &() const { return *_characters.front(); }
/**
* Casting operator for convenient access to the first character
*/
operator Character *() const { return _characters.front(); }
/**
* Synchronize data
*/
void synchronize(Common::Serializer &s);
/**
* Returns true if the party is dead
*/
bool isDead() const;
/**
* Returns true if the party has no food
*/
bool isFoodless() const;
};
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,63 @@
/* 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 ULTIMA_SHARED_CORE_RECT_H
#define ULTIMA_SHARED_CORE_RECT_H
#include "common/rect.h"
namespace Ultima {
namespace Shared {
class TextPoint;
typedef Common::Rect Rect;
typedef Common::Point Point;
/**
* Simple derived point class that converts text coordinates to graphic screen coordinates
*/
class TextPoint : public Common::Point {
public:
TextPoint() : Common::Point() {}
TextPoint(int16 x1, int16 y1) : Common::Point(x1 * 8, y1 * 8) {}
};
/**
* Simple derived rect class that converts text coordinates to graphic screen coordinates
*/
class TextRect : public Common::Rect {
public:
TextRect() : Common::Rect() {}
TextRect(int16 x1, int16 y1, int16 x2, int16 y2) : Common::Rect(x1 * 8, y1 * 8, (x2 + 1) * 8, (y2 + 1) * 8) {}
};
} // End of namespace Shared
using Shared::Rect;
using Shared::Point;
using Shared::TextPoint;
using Shared::TextRect;
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,66 @@
/* 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/shared/core/str.h"
namespace Ultima {
namespace Shared {
int String::indexOf(char c) const {
const char *s = strchr(c_str(), c);
return s ? s - c_str() : -1;
}
int String::indexOf(const String &chars) const {
uint minIndex = size();
for (uint idx = 0; idx < chars.size(); ++idx) {
int charIndex = indexOf(chars[idx]);
if (charIndex != -1 && charIndex < (int)minIndex)
minIndex = charIndex;
}
return minIndex == size() ? -1 : minIndex;
}
StringArray String::split(char c) const {
return split(String(c));
}
StringArray String::split(const String &chars) const {
StringArray results;
String temp = *this;
int idx;
// Iterate through the text
while ((idx = temp.indexOf(chars)) != -1) {
results.push_back(String(temp.c_str(), temp.c_str() + idx));
temp = String(temp.c_str() + idx + 1);
}
if (!empty() && !temp.empty())
results.push_back(temp);
return results;
}
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,76 @@
/* 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 ULTIMA_STR_H
#define ULTIMA_STR_H
#include "common/str.h"
#include "common/array.h"
namespace Ultima {
namespace Shared {
class String;
typedef Common::Array<String> StringArray;
/**
* Derived string class
*/
class String : public Common::String {
public:
String() : Common::String() {}
String(const char *str) : Common::String(str) {}
String(const char *str, uint32 len) : Common::String(str, len) {}
String(const char *beginP, const char *endP) : Common::String(beginP, endP) {}
String(const String &str) : Common::String(str) {}
String(const Common::String &str) : Common::String(str) {}
explicit String(char c) : Common::String(c) {}
String& operator=(const String &str) { this->Common::String::operator=(str); return *this; }
/**
* Returns the index of a given character, or -1 if not present
*/
int indexOf(char c) const;
/**
* Returns the earliest index of any character in a passed set of characters, or -1 if not present
*/
int indexOf(const String &chars) const;
/**
* Splits up a text string by a given character
*/
StringArray split(char c) const;
/**
* Splits up a text string by any of the characters in the passed string
*/
StringArray split(const String &chars) const;
};
} // End of namespace Shared
using Shared::String;
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,221 @@
/* 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/shared/core/tree_item.h"
#include "ultima/shared/core/named_item.h"
#include "ultima/shared/early/game.h"
#include "ultima/shared/early/game_base.h"
namespace Ultima {
namespace Shared {
EMPTY_MESSAGE_MAP(TreeItem, MessageTarget);
TreeItem::TreeItem() : _parent(nullptr), _firstChild(nullptr),
_nextSibling(nullptr), _priorSibling(nullptr),
_disposeAfterUse(DisposeAfterUse::NO) {
}
Game *TreeItem::getGame() {
TreeItem *treeItem = this;
while (treeItem->getParent()) {
treeItem = treeItem->getParent();
}
return dynamic_cast<Game *>(treeItem);
}
const Game *TreeItem::getGame() const {
const TreeItem *treeItem = this;
while (treeItem->getParent()) {
treeItem = treeItem->getParent();
}
return dynamic_cast<const Game *>(treeItem);
}
TreeItem *TreeItem::getLastSibling() {
TreeItem *item = this;
while (item->getNextSibling())
item = item->getNextSibling();
return item;
}
Gfx::VisualItem *TreeItem::getView() {
return getGame()->getView();
}
TreeItem *TreeItem::getLastChild() const {
if (!_firstChild)
return nullptr;
return _firstChild->getLastSibling();
}
TreeItem *TreeItem::scan(TreeItem *item) const {
if (_firstChild)
return _firstChild;
const TreeItem *treeItem = this;
while (treeItem != item) {
if (treeItem->_nextSibling)
return treeItem->_nextSibling;
treeItem = treeItem->_parent;
if (!treeItem)
break;
}
return nullptr;
}
TreeItem *TreeItem::findChildInstanceOf(const ClassDef &classDef) const {
for (TreeItem *treeItem = _firstChild; treeItem; treeItem = treeItem->getNextSibling()) {
if (treeItem->isInstanceOf(classDef))
return treeItem;
}
return nullptr;
}
TreeItem *TreeItem::findNextInstanceOf(const ClassDef &classDef, TreeItem *startItem) const {
TreeItem *treeItem = startItem ? startItem->getNextSibling() : getFirstChild();
for (; treeItem; treeItem = treeItem->getNextSibling()) {
if (treeItem->isInstanceOf(classDef))
return treeItem;
}
return nullptr;
}
void TreeItem::addUnder(TreeItem *newParent) {
if (newParent->_firstChild)
addSibling(newParent->_firstChild->getLastSibling());
else
setParent(newParent);
}
void TreeItem::addChild(TreeItem *child) {
child->addUnder(this);
}
void TreeItem::setParent(TreeItem *newParent) {
_parent = newParent;
_priorSibling = nullptr;
_nextSibling = newParent->_firstChild;
if (newParent->_firstChild)
newParent->_firstChild->_priorSibling = this;
newParent->_firstChild = this;
}
void TreeItem::addSibling(TreeItem *item) {
_priorSibling = item;
_nextSibling = item->_nextSibling;
_parent = item->_parent;
if (item->_nextSibling)
item->_nextSibling->_priorSibling = this;
item->_nextSibling = this;
}
void TreeItem::moveUnder(TreeItem *newParent) {
if (newParent) {
detach();
addUnder(newParent);
}
}
void TreeItem::destroyAll() {
destroyChildren();
detach();
if (_disposeAfterUse == DisposeAfterUse::YES)
delete this;
}
int TreeItem::destroyChildren() {
if (!_firstChild)
return 0;
TreeItem *item = _firstChild, *child, *nextSibling;
int total = 0;
do {
child = item->_firstChild;
nextSibling = item->_nextSibling;
if (child)
total += item->destroyChildren();
item->detach();
if (item->_disposeAfterUse == DisposeAfterUse::YES)
delete item;
++total;
} while ((item = nextSibling) != nullptr);
return total;
}
void TreeItem::detach() {
// Delink this item from any prior and/or next siblings
if (_priorSibling)
_priorSibling->_nextSibling = _nextSibling;
if (_nextSibling)
_nextSibling->_priorSibling = _priorSibling;
if (_parent && _parent->_firstChild == this)
_parent->_firstChild = _nextSibling;
_priorSibling = _nextSibling = _parent = nullptr;
}
void TreeItem::attach(TreeItem *item) {
_nextSibling = item;
_priorSibling = item->_priorSibling;
_parent = item->_parent;
if (item->_priorSibling)
item->_priorSibling->_nextSibling = this;
item->_priorSibling = this;
if (item->_parent && !item->_parent->_firstChild)
item->_parent->_firstChild = this;
}
NamedItem *TreeItem::findByName(const Common::String &name) {
Common::String nameLower = name;
nameLower.toLowercase();
for (TreeItem *treeItem = this; treeItem; treeItem = treeItem->scan(this)) {
Common::String itemName = treeItem->getName();
itemName.toLowercase();
if (!itemName.compareTo(nameLower))
return dynamic_cast<NamedItem *>(treeItem);
}
return nullptr;
}
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,215 @@
/* 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 ULTIMA_SHARED_CORE_TREE_ITEM_H
#define ULTIMA_SHARED_CORE_TREE_ITEM_H
#include "ultima/shared/core/message_target.h"
namespace Ultima {
namespace Shared {
namespace Gfx {
class VisualItem;
} // End of namespace Gfx
namespace Maps {
class Map;
} // End of namespace Maps
class Game;
class GameManager;
class GameState;
class Events;
class Map;
class NamedItem;
class CMessage;
/**
* This implements the base for objects can form a class hierarchy, with parents, children, and siblings
* that messages can be passed around.
*/
class TreeItem: public MessageTarget {
friend class CMessage;
DECLARE_MESSAGE_MAP;
private:
TreeItem *_parent;
TreeItem *_nextSibling;
TreeItem *_priorSibling;
TreeItem *_firstChild;
DisposeAfterUse::Flag _disposeAfterUse;
public:
CLASSDEF;
TreeItem();
/**
* Gets the name of the item, if any
*/
virtual const Common::String getName() const {
return Common::String();
}
/**
* Returns true if the item's name matches a passed name
*/
virtual bool isEquals(const Common::String &name, int maxLen = 0) const {
return false;
}
/**
* Compares the name of the item to a passed name
*/
virtual int compareTo(const Common::String &name, int maxLen = 0) const {
return false;
}
/**
* Called when the view changes
*/
virtual void viewChange() {
}
/**
* Get the parent for the given item
*/
TreeItem *getParent() const {
return _parent;
}
/**
* Jumps up through the parents to find the root game
*/
Game *getGame();
/**
* Jumps up through the parents to find the root game
*/
const Game *getGame() const;
/**
* Returns the currently active game view
*/
Gfx::VisualItem *getView();
/**
* Get the next sibling
*/
TreeItem *getNextSibling() const {
return _nextSibling;
}
/**
* Get the prior sibling
*/
TreeItem *getPriorSibling() const {
return _priorSibling;
}
/**
* Get the last sibling of this sibling
*/
TreeItem *getLastSibling();
/**
* Get the first child of the item, if any
*/
TreeItem *getFirstChild() const {
return _firstChild;
}
/**
* Get the last child of the item, if any
*/
TreeItem *getLastChild() const;
/**
* Given all the recursive children of the tree item, gives the next
* item in sequence to the passed starting item
*/
TreeItem *scan(TreeItem *item) const;
/**
* Find the first child item that is of a given type
*/
TreeItem *findChildInstanceOf(const ClassDef &classDef) const;
/**
* Find the next sibling item that is of the given type
*/
TreeItem *findNextInstanceOf(const ClassDef &classDef, TreeItem *startItem) const;
/**
* Adds the item under another tree item
*/
void addUnder(TreeItem *newParent);
/**
* Adds a new child under this one
*/
void addChild(TreeItem *child);
/**
* Sets the parent for the item
*/
void setParent(TreeItem *newParent);
/**
* Adds the item as a sibling of another item
*/
void addSibling(TreeItem *item);
/**
* Moves the tree item to be under another parent
*/
void moveUnder(TreeItem *newParent);
/**
* Destroys both the item as well as any of it's children
*/
void destroyAll();
/**
* Destroys all child tree items under this one.
* @returns Total number of tree items recursively removed
*/
int destroyChildren();
/**
* Detach the tree item from any other associated tree items
*/
void detach();
/**
* Attaches a tree item to a new node
*/
void attach(TreeItem *item);
/**
* Finds a tree item by name
* @param name Name to find
*/
NamedItem *findByName(const Common::String &name);
};
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,42 @@
/* 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/shared/core/utils.h"
#include "common/scummsys.h"
namespace Ultima {
namespace Shared {
bool isVowel(char c) {
switch (toupper(c)) {
case 'A':
case 'E':
case 'I':
case 'O':
case 'U':
return true;
default:
return false;
}
}
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,35 @@
/* 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 ULTIMA_UTILS_H
#define ULTIMA_UTILS_H
namespace Ultima {
namespace Shared {
#define SGN(v) ((v) > 0 ? 1 : -1)
extern bool isVowel(char c);
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,44 @@
/* 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/shared/core/widgets.h"
#include "ultima/shared/early/game.h"
namespace Ultima {
namespace Shared {
void Creature::synchronize(Common::Serializer &s) {
StandardWidget::synchronize(s);
s.syncAsSint16LE(_hitPoints);
}
void Creature::update(bool isPreUpdate) {
if (isPreUpdate) {
// Check whether creature can attack
movement();
_isAttacking = attackDistance() != 0;
} else if (_isAttacking && !_game->_party->isDead()) {
attack();
}
}
} // End of namespace Ultima1
} // End of namespace Ultima

View File

@@ -0,0 +1,147 @@
/* 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 ULTIMA_SHARED_CORE_WIDGETS_H
#define ULTIMA_SHARED_CORE_WIDGETS_H
#include "ultima/shared/core/map.h"
#include "ultima/shared/gfx/dungeon_surface.h"
namespace Ultima {
namespace Shared {
/**
* Base class for widgets on maps other than the dungeons
*/
class StandardWidget : public MapWidget {
public:
/**
* Constructor
*/
StandardWidget(Game *game, Map::MapBase *map) : MapWidget(game, map) {}
StandardWidget(Game *game, Map::MapBase *map, const Point &pt, Direction dir = DIR_NONE) : MapWidget(game, map, pt, dir) {}
/**
* Destructor
*/
~StandardWidget() override {}
};
class Creature : public StandardWidget {
protected:
int _hitPoints;
bool _isAttacking;
protected:
/**
* Returns either the maximum attack distance for a monster, or 0 if the monster is beyond
* that distance from the player
*/
virtual uint attackDistance() const { return 0; }
/**
* Handles moving creatures
*/
virtual void movement() {}
/**
* Handles attacks
*/
virtual void attack() {}
public:
/**
* Constructor
*/
Creature(Game *game, Map::MapBase *map) : StandardWidget(game, map), _hitPoints(0), _isAttacking(false) {}
Creature(Game *game, Map::MapBase *map, int hitPoints) : StandardWidget(game, map),
_hitPoints(hitPoints), _isAttacking(false) {}
Creature(Game *game, Map::MapBase *map, int hitPoints, const Point &pt, Direction dir = DIR_NONE) :
StandardWidget(game, map, pt, dir), _hitPoints(hitPoints), _isAttacking(false) {}
/**
* Destructor
*/
~Creature() override {}
/**
* Handles loading and saving games
*/
void synchronize(Common::Serializer &s) override;
/**
* Called to update the widget at the end of a turn
* @param isPreUpdate Update is called twice in succession during the end of turn update.
* Once with true for all widgets, then with it false
*/
void update(bool isPreUpdate) override;
/**
* True true if the creature is dead
*/
bool isDead() const { return _hitPoints <= 0; }
};
/**
* Base class for things that appear within the dungeons
*/
class DungeonWidget : public MapWidget {
public:
/**
* Constructor
*/
DungeonWidget(Game *game, Map::MapBase *map) : MapWidget(game, map) {}
DungeonWidget(Game *game, Map::MapBase *map, const Point &pt, Direction dir = DIR_NONE) : MapWidget(game, map, pt, dir) {}
DungeonWidget(Game *game, Map::MapBase *map, const Common::String &name, const Point &pt, Direction dir = DIR_NONE) :
MapWidget(game, map, name, pt, dir) {}
/**
* Destructor
*/
~DungeonWidget() override {}
/**
* Draws an item
*/
virtual void draw(DungeonSurface &s, uint distance) = 0;
};
/**
* Stub class for dungeon creatures
*/
class DungeonCreature {
public:
virtual ~DungeonCreature() {}
/**
* Returns true if a monster blocks the background behind him
*/
virtual bool isBlockingView() const = 0;
/**
* Draw a monster
*/
virtual void draw(DungeonSurface &s, uint distance) = 0;
};
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,313 @@
/* 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/shared/early/font_resources.h"
#include "common/algorithm.h"
namespace Ultima {
namespace Shared {
// 8x8 font copied from DosBox
static const byte INT10_FONT_08[256][8] = {
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e },
{ 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e },
{ 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00 },
{ 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00 },
{ 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c },
{ 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c },
{ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00 },
{ 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff },
{ 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00 },
{ 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff },
{ 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78 },
{ 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18 },
{ 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0 },
{ 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0 },
{ 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99 },
{ 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00 },
{ 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00 },
{ 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18 },
{ 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00 },
{ 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00 },
{ 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78 },
{ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00 },
{ 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff },
{ 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00 },
{ 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00 },
{ 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00 },
{ 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00 },
{ 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00 },
{ 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00 },
{ 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00 },
{ 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00 },
{ 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00 },
{ 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00 },
{ 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00 },
{ 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00 },
{ 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00 },
{ 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00 },
{ 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00 },
{ 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60 },
{ 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00 },
{ 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00 },
{ 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00 },
{ 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00 },
{ 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00 },
{ 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00 },
{ 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00 },
{ 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00 },
{ 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00 },
{ 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00 },
{ 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00 },
{ 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00 },
{ 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00 },
{ 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60 },
{ 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00 },
{ 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00 },
{ 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00 },
{ 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00 },
{ 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00 },
{ 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00 },
{ 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00 },
{ 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00 },
{ 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00 },
{ 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00 },
{ 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00 },
{ 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00 },
{ 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00 },
{ 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00 },
{ 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00 },
{ 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00 },
{ 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00 },
{ 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00 },
{ 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00 },
{ 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00 },
{ 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00 },
{ 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00 },
{ 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00 },
{ 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00 },
{ 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00 },
{ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00 },
{ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00 },
{ 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00 },
{ 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00 },
{ 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00 },
{ 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00 },
{ 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00 },
{ 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00 },
{ 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00 },
{ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff },
{ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00 },
{ 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00 },
{ 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00 },
{ 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00 },
{ 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00 },
{ 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00 },
{ 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8 },
{ 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00 },
{ 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00 },
{ 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78 },
{ 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00 },
{ 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00 },
{ 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00 },
{ 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00 },
{ 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00 },
{ 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0 },
{ 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e },
{ 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00 },
{ 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00 },
{ 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00 },
{ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00 },
{ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00 },
{ 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00 },
{ 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00 },
{ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8 },
{ 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00 },
{ 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00 },
{ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00 },
{ 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00 },
{ 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00 },
{ 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x18, 0x0c, 0x78 },
{ 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00 },
{ 0x1c, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00 },
{ 0x7e, 0xc3, 0x3c, 0x06, 0x3e, 0x66, 0x3f, 0x00 },
{ 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00 },
{ 0xe0, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00 },
{ 0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00 },
{ 0x00, 0x00, 0x78, 0xc0, 0xc0, 0x78, 0x0c, 0x38 },
{ 0x7e, 0xc3, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00 },
{ 0xcc, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00 },
{ 0xe0, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00 },
{ 0xcc, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00 },
{ 0x7c, 0xc6, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00 },
{ 0xe0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00 },
{ 0xc6, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00 },
{ 0x30, 0x30, 0x00, 0x78, 0xcc, 0xfc, 0xcc, 0x00 },
{ 0x1c, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00 },
{ 0x00, 0x00, 0x7f, 0x0c, 0x7f, 0xcc, 0x7f, 0x00 },
{ 0x3e, 0x6c, 0xcc, 0xfe, 0xcc, 0xcc, 0xce, 0x00 },
{ 0x78, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00 },
{ 0x00, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00 },
{ 0x00, 0xe0, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00 },
{ 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00 },
{ 0x00, 0xe0, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00 },
{ 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8 },
{ 0xc3, 0x18, 0x3c, 0x66, 0x66, 0x3c, 0x18, 0x00 },
{ 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00 },
{ 0x18, 0x18, 0x7e, 0xc0, 0xc0, 0x7e, 0x18, 0x18 },
{ 0x38, 0x6c, 0x64, 0xf0, 0x60, 0xe6, 0xfc, 0x00 },
{ 0xcc, 0xcc, 0x78, 0xfc, 0x30, 0xfc, 0x30, 0x30 },
{ 0xf8, 0xcc, 0xcc, 0xfa, 0xc6, 0xcf, 0xc6, 0xc7 },
{ 0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70 },
{ 0x1c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00 },
{ 0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00 },
{ 0x00, 0x1c, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00 },
{ 0x00, 0x1c, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00 },
{ 0x00, 0xf8, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0x00 },
{ 0xfc, 0x00, 0xcc, 0xec, 0xfc, 0xdc, 0xcc, 0x00 },
{ 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00 },
{ 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00 },
{ 0x30, 0x00, 0x30, 0x60, 0xc0, 0xcc, 0x78, 0x00 },
{ 0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00 },
{ 0xc3, 0xc6, 0xcc, 0xde, 0x33, 0x66, 0xcc, 0x0f },
{ 0xc3, 0xc6, 0xcc, 0xdb, 0x37, 0x6f, 0xcf, 0x03 },
{ 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00 },
{ 0x00, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x00, 0x00 },
{ 0x00, 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00 },
{ 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88 },
{ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa },
{ 0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee },
{ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 },
{ 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18 },
{ 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18 },
{ 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36 },
{ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36 },
{ 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18 },
{ 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36 },
{ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 },
{ 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36 },
{ 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00 },
{ 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00 },
{ 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18 },
{ 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00 },
{ 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18 },
{ 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18 },
{ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00 },
{ 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18 },
{ 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18 },
{ 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36 },
{ 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36 },
{ 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36 },
{ 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36 },
{ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00 },
{ 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36 },
{ 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00 },
{ 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18 },
{ 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36 },
{ 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00 },
{ 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18 },
{ 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36 },
{ 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36 },
{ 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18 },
{ 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18 },
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
{ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff },
{ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0 },
{ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f },
{ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x76, 0xdc, 0xc8, 0xdc, 0x76, 0x00 },
{ 0x00, 0x78, 0xcc, 0xf8, 0xcc, 0xf8, 0xc0, 0xc0 },
{ 0x00, 0xfc, 0xcc, 0xc0, 0xc0, 0xc0, 0xc0, 0x00 },
{ 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00 },
{ 0xfc, 0xcc, 0x60, 0x30, 0x60, 0xcc, 0xfc, 0x00 },
{ 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0x70, 0x00 },
{ 0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0xc0 },
{ 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x00 },
{ 0xfc, 0x30, 0x78, 0xcc, 0xcc, 0x78, 0x30, 0xfc },
{ 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x6c, 0x38, 0x00 },
{ 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x6c, 0xee, 0x00 },
{ 0x1c, 0x30, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00 },
{ 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00 },
{ 0x06, 0x0c, 0x7e, 0xdb, 0xdb, 0x7e, 0x60, 0xc0 },
{ 0x38, 0x60, 0xc0, 0xf8, 0xc0, 0x60, 0x38, 0x00 },
{ 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00 },
{ 0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x00 },
{ 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0xfc, 0x00 },
{ 0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xfc, 0x00 },
{ 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xfc, 0x00 },
{ 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18 },
{ 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70 },
{ 0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00 },
{ 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00 },
{ 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00 },
{ 0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c },
{ 0x78, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00 },
{ 0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
};
/*-------------------------------------------------------------------*/
FontResources::FontResources() : LocalResourceFile("COMMON/FONTS") {
}
FontResources::FontResources(Resources *resManager) : LocalResourceFile(resManager, "COMMON/FONTS") {
Common::copy((const byte *)INT10_FONT_08, (const byte *)INT10_FONT_08 + 256 * 8, (byte *)_font8x8);
}
void FontResources::synchronize() {
syncBytes2D((byte *)_font8x8, 256, 8);
// Load in the Ultima VI font if present
Common::File f;
if (f.exists("u6.ch")) {
f.open("u6.ch");
for (int idx = 0; idx < 256; ++idx)
f.read(&_fontU6[idx][0], 8);
} else {
for (int idx = 0; idx < 256; ++idx)
Common::fill(&_fontU6[idx][0], &_fontU6[idx][8], 0);
}
}
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,49 @@
/* 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 ULTIMA_SHARED_EARLY_FONT_RESOURCES_H
#define ULTIMA_SHARED_EARLY_FONT_RESOURCES_H
#include "ultima/shared/engine/resources.h"
#include "ultima/shared/core/file.h"
#include "common/memstream.h"
namespace Ultima {
namespace Shared {
class FontResources : public LocalResourceFile {
protected:
/**
* Synchronize resource data
*/
void synchronize() override;
public:
byte _font8x8[256][8];
byte _fontU6[256][8];
public:
FontResources();
FontResources(Resources *resManager);
};
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,141 @@
/* 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/shared/early/game.h"
#include "ultima/shared/early/font_resources.h"
#include "ultima/shared/maps/map.h"
#include "ultima/shared/early/ultima_early.h"
#include "ultima/shared/gfx/font.h"
#include "ultima/shared/gfx/screen.h"
#include "graphics/palette.h"
namespace Ultima {
namespace Shared {
BEGIN_MESSAGE_MAP(Game, GameBase)
ON_MESSAGE(EndOfTurnMsg)
END_MESSAGE_MAP()
Game::Game() : GameBase(), _randomSeed(0), _gameView(nullptr), _map(nullptr), _party(nullptr),
_edgeColor(0), _borderColor(0), _highlightColor(0), _textColor(0), _color1(0), _bgColor(0), _whiteColor(0) {
_fontResources = new FontResources();
_fontResources->load();
setFont(new Gfx::Font((const byte *)&_fontResources->_font8x8[0][0]));
}
Game::~Game() {
delete _fontResources;
}
void Game::setCGAPalette() {
static const byte PALETTE[4][3] = { { 0, 0, 0 },{ 0xAA, 0xAA, 0 },{ 0xAA, 0, 0xAA },{ 0xAA, 0xAA, 0xAA } };
g_vm->_screen->setPalette(&PALETTE[0][0], 0, 4);
_edgeColor = 3;
_borderColor = 3;
_highlightColor = 1;
_textColor = 3;
_color1 = 6;
_whiteColor = 3;
}
void Game::setEGAPalette() {
static const byte PALETTE[16][3] = {
{ 0, 0, 0 },{ 0x00, 0x00, 0x80 },{ 0x00, 0x80, 0x00 },{ 0x00, 0x80, 0x80 },
{ 0x80, 0x00, 0x00 },{ 0x80, 0x00, 0x80 },{ 0x80, 0x80, 0x00 },{ 0xC0, 0xC0, 0xC0 },
{ 0x80, 0x80, 0x80 },{ 0x00, 0x00, 0xFF },{ 0x00, 0xFF, 0x00 },{ 0x00, 0xFF, 0xFF },
{ 0xFF, 0x40, 0x40 },{ 0xFF, 0x00, 0xFF },{ 0xFF, 0xFF, 0x00 },{ 0xFF, 0xFF, 0xFF }
};
g_vm->_screen->setPalette(&PALETTE[0][0], 0, 16);
_edgeColor = 15;
_borderColor = 1;
_highlightColor = 12;
_textColor = 11;
_color1 = 7;
_bgColor = 0;
_whiteColor = 15;
}
void Game::setEGAPalette(const byte *palette) {
// Build up the EGA palette
byte egaPalette[64 * 3];
byte *p = &egaPalette[0];
for (int i = 0; i < 64; ++i) {
*p++ = (i >> 2 & 1) * 0xaa + (i >> 5 & 1) * 0x55;
*p++ = (i >> 1 & 1) * 0xaa + (i >> 4 & 1) * 0x55;
*p++ = (i & 1) * 0xaa + (i >> 3 & 1) * 0x55;
}
// Loop through setting palette colors based on the passed indexes
for (int idx = 0; idx < 16; ++idx) {
int palIndex = palette[idx];
assert(palIndex < 64);
const byte *pRgb = (const byte *)&egaPalette[palIndex * 3];
g_vm->_screen->setPalette(pRgb, idx, 1);
}
}
void Game::loadU6Palette() {
// Read in the palette
File f("u6pal");
byte palette[Graphics::PALETTE_SIZE];
f.read(palette, Graphics::PALETTE_SIZE);
f.close();
// Adjust the palette values from 0-63 to 0-255, and set the palette
for (int idx = 0; idx < Graphics::PALETTE_SIZE; ++idx)
palette[idx] = PALETTE_6BIT_TO_8BIT(palette[idx]);
g_vm->_screen->setPalette(&palette[0], 0, Graphics::PALETTE_COUNT);
// TODO: Set appropriate indexes
_edgeColor = 15;
_borderColor = 1;
_highlightColor = 12;
_textColor = 72;
_color1 = 7;
_bgColor = 49;
}
void Game::playFX(uint effectId) {
warning("TODO: playFX");
}
void Game::synchronize(Common::Serializer &s) {
_party->synchronize(s);
_map->synchronize(s);
}
bool Game::EndOfTurnMsg(CEndOfTurnMsg *msg) {
// Update things on the map
_map->update();
return false;
}
void Game::endOfTurn() {
CEndOfTurnMsg turnMsg;
turnMsg.execute(this);
}
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,129 @@
/* 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 ULTIMA_SHARED_EARLY_GAME_H
#define ULTIMA_SHARED_EARLY_GAME_H
#include "ultima/shared/early/game_base.h"
#include "ultima/shared/core/party.h"
namespace Ultima {
namespace Shared {
class GameView;
class GameState;
class FontResources;
namespace Maps {
class Map;
}
/**
* More specialized base class for earlier Ultima games
*/
class Game : public GameBase {
DECLARE_MESSAGE_MAP;
bool EndOfTurnMsg(CEndOfTurnMsg *msg);
protected:
GameView *_gameView;
FontResources *_fontResources;
protected:
/**
* Sets up EGA palette
*/
void setEGAPalette();
/**
* Loads the Ultima 6 palette
*/
void loadU6Palette();
public:
byte _edgeColor;
byte _borderColor;
byte _highlightColor;
byte _textColor;
byte _color1;
byte _bgColor;
byte _whiteColor;
/**
* Player party. In the earlier Ultima games, this is a single character
*/
Party *_party;
/**
* Pointer to the map manager for the game
*/
Maps::Map *_map;
/**
* Stores the base random seed used for generating deterministic dungeon levels
*/
uint32 _randomSeed;
public:
CLASSDEF;
/**
* Constructor
*/
Game();
/**
* Destructor
*/
~Game() override;
/**
* Play a sound effect
*/
void playFX(uint effectId);
/**
* Sets an EGA palette based on a 16-byte EGA RGB indexes
*/
void setEGAPalette(const byte *palette);
/**
* Sets up a CGA palette
*/
void setCGAPalette();
/**
* Returns the map
*/
Maps::Map *getMap() const override { return _map; }
/**
* Handles loading and saving games
*/
void synchronize(Common::Serializer &s) override;
/**
* Signal an end of turn
*/
void endOfTurn();
};
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,262 @@
/* 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 "common/config-manager.h"
#include "common/system.h"
#include "ultima/shared/early/ultima_early.h"
#include "ultima/shared/early/game_base.h"
#include "ultima/shared/engine/messages.h"
#include "ultima/shared/core/mouse_cursor.h"
#include "ultima/shared/gfx/font.h"
#include "ultima/shared/gfx/text_cursor.h"
#include "ultima/shared/gfx/text_input.h"
#include "ultima/shared/gfx/visual_container.h"
namespace Ultima {
namespace Shared {
GameBase::GameBase(): _currentView(nullptr), _pendingPopup(nullptr), _font(nullptr), _priorLeftDownTime(0),
_priorMiddleDownTime(0), _priorRightDownTime(0), _inputHandler(this), _inputTranslator(&_inputHandler),
_videoMode(0), _textCursor(nullptr) {
}
GameBase::~GameBase() {
delete _font;
delete _textCursor;
}
int GameBase::getSavegameSlot() {
return 0;
}
void GameBase::mouseChanged() {
}
void GameBase::onIdle() {
// Handle any drawing updates
update();
}
#define HANDLE_MESSAGE(METHOD) \
_inputTranslator.METHOD(g_vm->_events->getSpecialButtons(), mousePos); \
mouseChanged()
void GameBase::mouseMove(const Point &mousePos) {
if (!isMouseControlEnabled())
return;
HANDLE_MESSAGE(mouseMove);
}
void GameBase::leftButtonDown(const Point &mousePos) {
if (!isMouseControlEnabled())
return;
if ((g_vm->_events->getTicksCount() - _priorLeftDownTime) < DOUBLE_CLICK_TIME) {
_priorLeftDownTime = 0;
leftButtonDoubleClick(mousePos);
} else {
_priorLeftDownTime = g_vm->_events->getTicksCount();
HANDLE_MESSAGE(leftButtonDown);
}
}
void GameBase::leftButtonUp(const Point &mousePos) {
if (!isMouseControlEnabled())
return;
HANDLE_MESSAGE(leftButtonUp);
}
void GameBase::leftButtonDoubleClick(const Point &mousePos) {
if (!isMouseControlEnabled())
return;
HANDLE_MESSAGE(leftButtonDoubleClick);
}
void GameBase::middleButtonDown(const Point &mousePos) {
if (!isMouseControlEnabled())
return;
if ((g_vm->_events->getTicksCount() - _priorMiddleDownTime) < DOUBLE_CLICK_TIME) {
_priorMiddleDownTime = 0;
middleButtonDoubleClick(mousePos);
} else {
_priorMiddleDownTime = g_vm->_events->getTicksCount();
HANDLE_MESSAGE(middleButtonDown);
}
}
void GameBase::middleButtonUp(const Point &mousePos) {
if (!isMouseControlEnabled())
return;
HANDLE_MESSAGE(middleButtonUp);
}
void GameBase::middleButtonDoubleClick(const Point &mousePos) {
if (!isMouseControlEnabled())
return;
HANDLE_MESSAGE(middleButtonDoubleClick);
}
void GameBase::rightButtonDown(const Point &mousePos) {
if (!isMouseControlEnabled())
return;
if ((g_vm->_events->getTicksCount() - _priorRightDownTime) < DOUBLE_CLICK_TIME) {
_priorRightDownTime = 0;
rightButtonDoubleClick(mousePos);
} else {
_priorRightDownTime = g_vm->_events->getTicksCount();
HANDLE_MESSAGE(rightButtonDown);
}
}
void GameBase::rightButtonUp(const Point &mousePos) {
if (!isMouseControlEnabled())
return;
HANDLE_MESSAGE(rightButtonUp);
}
void GameBase::mouseWheel(const Point &mousePos, bool wheelUp) {
if (!isMouseControlEnabled())
return;
_inputTranslator.mouseWheel(wheelUp, mousePos);
mouseChanged();
}
void GameBase::rightButtonDoubleClick(const Point &mousePos) {
if (!isMouseControlEnabled())
return;
HANDLE_MESSAGE(rightButtonDoubleClick);
}
void GameBase::keyDown(Common::KeyState keyState) {
_inputTranslator.keyDown(keyState);
}
void GameBase::setView(Gfx::VisualItem *view) {
_currentView = view;
}
void GameBase::setView(const Common::String &viewName) {
Gfx::VisualItem *view = dynamic_cast<Gfx::VisualItem *>(findByName(viewName));
if (view != _currentView) {
_currentView = view;
assert(_currentView);
// Signal the view that it's now active
CShowMsg showMsg;
showMsg.execute(_currentView);
}
}
void GameBase::setPopup(Gfx::Popup *popup) {
assert(!_pendingPopup);
_pendingPopup = popup;
}
void GameBase::update() {
if (_currentView) {
// Signal the next frame
CFrameMsg frameMsg(g_vm->_events->getTicksCount());
frameMsg.execute(_currentView);
// Draw the view
if (_currentView->isDirty()) {
_currentView->draw();
_currentView->clearDirty();
} else if (_pendingPopup) {
// There's a pending popup to display, so make it active
_currentView = _pendingPopup;
_pendingPopup = nullptr;
CShowMsg showMsg;
showMsg.execute(_currentView);
}
// Allow the text cursor to update
_textCursor->update();
}
}
void GameBase::changeView(const Common::String &name) {
Gfx::VisualItem *newView = dynamic_cast<Gfx::VisualItem *>(findByName(name));
assert(newView);
// Hide the current view
CHideMsg hideMsg(_currentView, true);
hideMsg.execute(_currentView, nullptr, MSGFLAG_SCAN);
if (hideMsg._fadeOut) {
// TODO: Fade out
}
// Show the new view
_currentView = newView;
CShowMsg showMsg(_currentView, true);
showMsg.execute(_currentView, nullptr, MSGFLAG_SCAN);
_currentView->draw();
if (showMsg._fadeIn) {
// TODO: Fade in
}
}
void GameBase::setFont(Gfx::Font *font) {
delete _font;
_font = font;
}
uint GameBase::getRandomNumber(uint max) {
return g_vm->getRandomNumber(max);
}
uint GameBase::getRandomNumber(uint min, uint max) {
return g_vm->getRandomNumber(min, max);
}
void GameBase::sleep(uint time) {
g_vm->_events->sleep(time);
}
uint32 GameBase::getMillis() const {
return g_system->getMillis();
}
void GameBase::synchronize(Common::Serializer &s) {
_priorLeftDownTime = 0;
_priorMiddleDownTime = 0;
_priorRightDownTime = 0;
}
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,203 @@
/* 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 ULTIMA_SHARED_EARLY_GAME_BASE_H
#define ULTIMA_SHARED_EARLY_GAME_BASE_H
#include "common/scummsys.h"
#include "common/array.h"
#include "common/serializer.h"
#include "ultima/shared/engine/events.h"
#include "ultima/shared/engine/input_handler.h"
#include "ultima/shared/engine/input_translator.h"
namespace Ultima {
namespace Shared {
class UltimaEngine;
class GameState;
namespace Gfx {
class Font;
class Popup;
class TextCursor;
class TextInput;
class VisualItem;
} // End of namespace Gfx
namespace Maps {
class Map;
} // End of namespace Maps
/**
* Base class for the game implementations
*/
class GameBase : public TreeItem, public EventTarget {
private:
/**
* Checks for the presence of any savegames and, if present,
* lets the user pick one to resume
*/
int getSavegameSlot();
void leftButtonDoubleClick(const Point &mousePos) override;
void middleButtonDoubleClick(const Point &mousePos) override;
void rightButtonDoubleClick(const Point &mousePos);
/**
* Returns true if the player can control the mouse
*/
bool isMouseControlEnabled() const { return true; }
void changeView(const Common::String &name);
protected:
uint32 _priorLeftDownTime;
uint32 _priorMiddleDownTime;
uint32 _priorRightDownTime;
Gfx::VisualItem *_currentView;
Gfx::Popup *_pendingPopup;
InputHandler _inputHandler;
InputTranslator _inputTranslator;
Gfx::Font *_font;
public:
Gfx::TextCursor *_textCursor;
uint _videoMode;
public:
/**
* Constructor
*/
GameBase();
/**
* Destructor
*/
~GameBase() override;
/**
* Called to handle any regular updates the game requires
*/
void onIdle() override;
void mouseMove(const Point &mousePos) override;
void leftButtonDown(const Point &mousePos) override;
void leftButtonUp(const Point &mousePos) override;
void middleButtonDown(const Point &mousePos) override;
void middleButtonUp(const Point &mousePos) override;
void rightButtonDown(const Point &mousePos) override;
void rightButtonUp(const Point &mousePos) override;
void mouseWheel(const Point &mousePos, bool wheelUp) override;
void keyDown(Common::KeyState keyState) override;
/**
* Called when the game starts
*/
virtual void starting(bool isLoading) {}
/**
* Returns true if the current video mode is VGA
*/
virtual bool isVGA() const { return false; }
/**
* Called once every frame to update the game and render the view
*/
void update();
/**
* Called by the event handler when a mouse event has been generated
*/
void mouseChanged();
/**
* Set the currently active view to display
*/
void setView(Gfx::VisualItem *view);
/**
* Set the currently active view to display
*/
void setView(const Common::String &viewName);
/**
* Sets a popup to be shown
*/
void setPopup(Gfx::Popup *popup);
/**
* Returns the current view
*/
Gfx::VisualItem *getView() const { return _currentView; }
/**
* Set a font to use
*/
void setFont(Gfx::Font *font);
/**
* Returns the current font
*/
Gfx::Font *getFont() const { return _font; }
/**
* Returns the map
*/
virtual Maps::Map *getMap() const { return nullptr; }
/**
* Gets a random number
*/
uint getRandomNumber(uint max);
/**
* Gets a random number
*/
uint getRandomNumber(uint min, uint max);
/**
* Wait for a given period of time
*/
void sleep(uint time);
/**
* Return the current time
*/
uint32 getMillis() const;
/**
* Returns true if a savegame can currently be loaded
*/
virtual bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) { return true; }
/**
* Returns true if the game can currently be saved
*/
virtual bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) { return false; }
/**
* Handles loading and saving games
*/
virtual void synchronize(Common::Serializer &s);
};
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,164 @@
/* 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 "common/scummsys.h"
#include "common/config-manager.h"
#include "common/debug-channels.h"
#include "common/system.h"
#include "common/translation.h"
#include "graphics/thumbnail.h"
#include "graphics/scaler.h"
#include "gui/saveload.h"
#include "ultima/shared/early/ultima_early.h"
#include "ultima/shared/early/game.h"
#include "ultima/shared/engine/events.h"
#include "ultima/shared/engine/resources.h"
#include "ultima/shared/core/mouse_cursor.h"
#include "ultima/shared/gfx/screen.h"
#ifndef RELEASE_BUILD
#include "ultima/ultima1/game.h"
#endif
namespace Ultima {
Shared::UltimaEarlyEngine *g_vm;
namespace Shared {
UltimaEarlyEngine::UltimaEarlyEngine(OSystem *syst, const UltimaGameDescription *gameDesc) :
Engine(syst), _gameDescription(gameDesc), _game(nullptr), _randomSource("Ultima") {
g_vm = this;
_mouseCursor = nullptr;
_screen = nullptr;
}
UltimaEarlyEngine::~UltimaEarlyEngine() {
delete _events;
delete _game;
delete _mouseCursor;
delete _screen;
}
bool UltimaEarlyEngine::initialize() {
// Call syncSoundSettings to get default volumes set
syncSoundSettings();
// Set up the resources datafile
Resources *res = new Resources();
if (!res->open()) {
GUIErrorMessage(_("Could not find correct ultima.dat datafile"));
return false;
}
SearchMan.add("ultima", res);
_events = new EventsManager(this);
_screen = new Gfx::Screen();
// Create the game, and signal to it that the game is starting
_game = createGame();
_events->addTarget(_game);
_game->starting(false);
// Load cursors
_mouseCursor = new MouseCursor();
// If requested, load a savegame instead of showing the intro
if (ConfMan.hasKey("save_slot")) {
int saveSlot = ConfMan.getInt("save_slot");
if (saveSlot >= 0 && saveSlot <= 999)
loadGameState(saveSlot);
}
return true;
}
Common::Error UltimaEarlyEngine::run() {
// Initialize the engine and play the game
if (initialize())
playGame();
// Deinitialize and free the engine
deinitialize();
return Common::kNoError;
}
bool UltimaEarlyEngine::hasFeature(EngineFeature f) const {
return
(f == kSupportsReturnToLauncher) ||
(f == kSupportsLoadingDuringRuntime) ||
(f == kSupportsChangingOptionsDuringRuntime) ||
(f == kSupportsSavingDuringRuntime);
}
void UltimaEarlyEngine::playGame() {
while (!shouldQuit()) {
_events->pollEventsAndWait();
}
}
Graphics::Screen *UltimaEarlyEngine::getScreen() const {
return _screen;
}
GameId UltimaEarlyEngine::getGameId() const {
return _gameDescription->gameId;
}
bool UltimaEarlyEngine::isEnhanced() const {
return _gameDescription->features & GF_VGA_ENHANCED;
}
Game *UltimaEarlyEngine::createGame() const {
switch (getGameId()) {
#ifndef RELEASE_BUILD
case GAME_ULTIMA1:
return new Ultima1::Ultima1Game();
#endif
default:
error("Unknown game");
}
}
Common::Error UltimaEarlyEngine::loadGameStream(Common::SeekableReadStream *stream) {
// Read in the game's data
Common::Serializer s(stream, nullptr);
_game->synchronize(s);
return Common::kNoError;
}
Common::Error UltimaEarlyEngine::saveGameStream(Common::WriteStream *stream, bool) {
// Write out the game's data
Common::Serializer s(nullptr, stream);
_game->synchronize(s);
return Common::kNoError;
}
bool UltimaEarlyEngine::canLoadGameStateCurrently(Common::U32String *msg) {
return _game->canLoadGameStateCurrently(msg);
}
bool UltimaEarlyEngine::canSaveGameStateCurrently(Common::U32String *msg) {
return _game->canSaveGameStateCurrently(msg);
}
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,169 @@
/* 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 ULTIMA_SHARED_EARLY_ULTIMA_EARLY_H
#define ULTIMA_SHARED_EARLY_ULTIMA_EARLY_H
#include "common/scummsys.h"
#include "common/array.h"
#include "common/endian.h"
#include "common/hash-str.h"
#include "common/serializer.h"
#include "common/random.h"
#include "common/savefile.h"
#include "common/util.h"
#include "graphics/surface.h"
#include "engines/engine.h"
#include "ultima/detection.h"
#include "ultima/shared/engine/events.h"
namespace Ultima {
struct UltimaGameDescription;
namespace Shared {
struct UltimaSavegameHeader {
uint8 _version;
uint8 _gameId;
uint8 _language;
uint8 _videoMode;
Common::String _saveName;
Graphics::Surface *_thumbnail;
int _year, _month, _day;
int _hour, _minute;
int _totalFrames;
};
class Events;
class Game;
class GameBase;
class MouseCursor;
class Resources;
namespace Gfx {
class Screen;
}
class UltimaEarlyEngine : public Engine, public EventsCallback {
private:
/**
* Initialize the engine
*/
virtual bool initialize();
/**
* Deinitialize the engine
*/
virtual void deinitialize() {}
private:
Common::RandomSource _randomSource;
protected:
const UltimaGameDescription *_gameDescription;
public:
GameBase *_game;
MouseCursor *_mouseCursor;
Gfx::Screen *_screen;
EventsManager *_events;
public:
UltimaEarlyEngine(OSystem *syst, const UltimaGameDescription *gameDesc);
~UltimaEarlyEngine() override;
/**
* Main method for running the game
*/
Common::Error run() override;
/**
* Returns supported engine features
*/
bool hasFeature(EngineFeature f) const override;
/**
* Play the game
*/
void playGame();
/**
* Get a random number
*/
uint getRandomNumber(uint maxVal) { return _randomSource.getRandomNumber(maxVal); }
/**
* Gets a random number
*/
uint getRandomNumber(uint min, uint max) {
return min + _randomSource.getRandomNumber(max - min);
}
/**
* Get the screen
*/
Graphics::Screen *getScreen() const override;
/**
* Indicates whether a game state can be loaded.
* @param isAutosave Flags whether it's an autosave check
*/
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
/**
* Indicates whether a game state can be saved.
* @param isAutosave Flags whether it's an autosave check
*/
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
/**
* Load a savegame
*/
Common::Error loadGameStream(Common::SeekableReadStream *stream) override;
/**
* Save a game state.
*/
Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave = false) override;
/**
* Returns the game type being played
*/
GameId getGameId() const;
/**
* Returns true if the game is running an enhanced version
* as compared to the original game
*/
bool isEnhanced() const;
/*
* Creates a new hierarchy for the game, that contains all the logic for playing that particular game.
*/
Game *createGame() const;
};
} // End of namespace Shared
extern Shared::UltimaEarlyEngine *g_vm;
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,241 @@
/* 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/shared/engine/data_archive.h"
#include "common/config-manager.h"
#include "common/file.h"
#include "common/translation.h"
#include "common/compression/unzip.h"
namespace Ultima {
namespace Shared {
#define DATA_FILENAME "ultima.dat"
class UltimaDataArchiveMember : public Common::ArchiveMember {
private:
Common::SharedPtr<Common::ArchiveMember> _member;
Common::Path _publicFolder;
Common::Path _innerfolder;
public:
UltimaDataArchiveMember(Common::SharedPtr<Common::ArchiveMember> member,
const Common::Path &subfolder) :
_member(member), _publicFolder("data/"), _innerfolder(subfolder) {
}
~UltimaDataArchiveMember() override {}
Common::SeekableReadStream *createReadStream() const override {
return _member->createReadStream();
}
Common::SeekableReadStream *createReadStreamForAltStream(Common::AltStreamType altStreamType) const override {
return _member->createReadStreamForAltStream(altStreamType);
}
Common::Path getPathInArchive() const override {
Common::Path name = _member->getPathInArchive();
assert(name.isRelativeTo(_innerfolder));
return _publicFolder.join(name.relativeTo(_innerfolder));
}
Common::U32String getDisplayName() const override {
return _member->getDisplayName();
}
Common::String getFileName() const override { return _member->getFileName(); }
Common::String getName() const override { return getPathInArchive().toString('/'); }
bool isDirectory() const override { return _member->isDirectory(); }
};
/*-------------------------------------------------------------------*/
bool UltimaDataArchive::load(const Common::Path &subfolder,
int reqMajorVersion, int reqMinorVersion, Common::U32String &errorMsg) {
Common::Archive *dataArchive = nullptr;
Common::File f;
#ifndef RELEASE_BUILD
Common::FSNode folder;
if (ConfMan.hasKey("extrapath")) {
if ((folder = Common::FSNode(ConfMan.getPath("extrapath"))).exists()
&& (folder = folder.getChild("files")).exists()
&& (folder = folder.getChild(subfolder.baseName())).exists()) {
f.open(folder.getChild("version.txt"));
}
}
#endif
if (!f.isOpen()) {
if (!Common::File::exists(DATA_FILENAME) ||
(dataArchive = Common::makeZipArchive(DATA_FILENAME)) == 0 ||
!f.open(subfolder.join("version.txt"), *dataArchive)) {
delete dataArchive;
errorMsg = Common::U32String::format(_("Could not locate engine data %s"), DATA_FILENAME);
return false;
}
}
// Validate the version
char buffer[5];
f.read(buffer, 4);
buffer[4] = '\0';
int major = 0, minor = 0;
if (buffer[1] == '.') {
major = buffer[0] - '0';
minor = atoi(&buffer[2]);
}
if (major != reqMajorVersion || minor != reqMinorVersion) {
delete dataArchive;
errorMsg = Common::U32String::format(_("Out of date engine data. Expected %d.%d, but got version %d.%d"),
reqMajorVersion, reqMinorVersion, major, minor);
return false;
}
// It was all validated correctly
Common::Archive *archive;
#ifndef RELEASE_BUILD
if (!dataArchive)
archive = new UltimaDataArchiveProxy(folder);
else
#endif
archive = new UltimaDataArchive(dataArchive, subfolder);
SearchMan.add("data", archive);
return true;
}
/*-------------------------------------------------------------------*/
bool UltimaDataArchive::hasFile(const Common::Path &path) const {
if (!path.isRelativeTo(_publicFolder))
return false;
Common::Path realFilename = innerToPublic(path);
return _zip->hasFile(realFilename);
}
int UltimaDataArchive::listMatchingMembers(Common::ArchiveMemberList &list, const Common::Path &pattern, bool matchPathComponents) const {
Common::ArchiveMemberList innerList;
int numMatches = 0;
// Test whether we can skip filtering.
bool matchAll = matchPathComponents && pattern == "*";
// First, get all zip members relevant to the current game
_zip->listMatchingMembers(innerList, _innerfolder.appendComponent("*"), true);
// Modify the results to change the filename, then filter with pattern
for (const auto &innerMember : innerList) {
Common::ArchiveMemberPtr member = Common::ArchiveMemberPtr(
new UltimaDataArchiveMember(innerMember, _innerfolder));
if (matchAll || member->getPathInArchive().toString().matchString(pattern.toString(), true, matchPathComponents ? nullptr : "/")) {
list.push_back(member);
++numMatches;
}
}
return numMatches;
}
int UltimaDataArchive::listMembers(Common::ArchiveMemberList &list) const {
return listMatchingMembers(list, "*", true);
}
const Common::ArchiveMemberPtr UltimaDataArchive::getMember(const Common::Path &path) const {
if (!hasFile(path))
return Common::ArchiveMemberPtr();
return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(path, *this));
}
Common::SeekableReadStream *UltimaDataArchive::createReadStreamForMember(const Common::Path &path) const {
if (hasFile(path)) {
Common::Path filename = innerToPublic(path);
return _zip->createReadStreamForMember(filename);
}
return nullptr;
}
bool UltimaDataArchive::isPathDirectory(const Common::Path &path) const {
return _zip->isPathDirectory(innerToPublic(path));
}
/*-------------------------------------------------------------------*/
#ifndef RELEASE_BUILD
const Common::ArchiveMemberPtr UltimaDataArchiveProxy::getMember(const Common::Path &path) const {
if (!hasFile(path))
return Common::ArchiveMemberPtr();
return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(path, *this));
}
Common::SeekableReadStream *UltimaDataArchiveProxy::createReadStreamForMember(const Common::Path &path) const {
if (hasFile(path))
return getNode(path).createReadStream();
return nullptr;
}
Common::FSNode UltimaDataArchiveProxy::getNode(const Common::Path &name) const {
Common::Path remainingName = name.relativeTo(_publicFolder);
Common::FSNode node = _folder;
Common::StringArray components = remainingName.splitComponents();
if (components.empty()) {
return node;
}
for(Common::StringArray::const_iterator it = components.begin(); it != components.end() - 1; it++) {
node = node.getChild(*it);
if (!node.exists())
return node;
}
node = node.getChild(*(components.end() - 1));
return node;
}
int UltimaDataArchiveProxy::listMembers(Common::ArchiveMemberList &list) const {
return listMatchingMembers(list, "*", true);
}
int UltimaDataArchiveProxy::listMatchingMembers(Common::ArchiveMemberList &list,
const Common::Path &pattern, bool matchPathComponents) const {
// Let FSDirectory adjust the filenames for us by using its prefix feature.
// Note: dir is intentionally constructed again on each call to prevent stale entries due to caching:
// Since this proxy class is intended for use during development, picking up modifications while the
// game is running might be useful.
const int maxDepth = 255; // chosen arbitrarily
Common::FSDirectory dir(_publicFolder, _folder, maxDepth, false, false, true);
if (matchPathComponents && pattern == "*")
return dir.listMembers(list);
else
return dir.listMatchingMembers(list, pattern, matchPathComponents);
}
bool UltimaDataArchiveProxy::isPathDirectory(const Common::Path &path) const {
return getNode(path).isDirectory();
}
#endif
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,183 @@
/* 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 ULTIMA_SHARED_ENGINE_DATA_ARCHIVE_H
#define ULTIMA_SHARED_ENGINE_DATA_ARCHIVE_H
#include "common/archive.h"
#include "common/fs.h"
#include "common/path.h"
namespace Ultima {
namespace Shared {
/**
* The data archive class encapsulates access to a specific subfolder within
* the ultima.dat data file for a game. It wraps up the subfolder so it can
* be accessed in each game as a generic "data" subfolder. This allows the
* individual games to simplify their data loading code.
*/
class UltimaDataArchive : public Common::Archive {
private:
Common::Archive *_zip;
Common::Path _publicFolder;
Common::Path _innerfolder;
UltimaDataArchive(Common::Archive *zip, const Common::Path &subfolder) :
_zip(zip), _publicFolder("data/"), _innerfolder(subfolder) {}
Common::Path innerToPublic(const Common::Path &filename) const {
assert(filename.isRelativeTo(_publicFolder));
return _innerfolder.join(filename.relativeTo(_publicFolder));
}
public:
/**
* Creates a data archive wrapper for the ultima.dat datafile.
* Firstly, for debugging purposes, if a "files" folder exists on any path that
* has the given subfolder, it will be used first. This will allow for setting
* the ScummVM Extra Path to the create_ultima folder, and it will give preference
* the files there. Otherwise, it checks for the presence of ultima.dat, and
* if the required data is found, it returns the new archive.
* Otherwise, returns an error message in the errorMsg field
*/
static bool load(const Common::Path &subfolder,
int reqMajorVersion, int reqMinorVersion, Common::U32String &errorMsg);
public:
~UltimaDataArchive() override {
delete _zip;
}
/**
* Check if a member with the given name is present in the Archive.
* Patterns are not allowed, as this is meant to be a quick File::exists()
* replacement.
*/
bool hasFile(const Common::Path &path) const override;
/**
* Add all members of the Archive matching the specified pattern to list.
* Must only append to list, and not remove elements from it.
*
* @return the number of members added to list
*/
int listMatchingMembers(Common::ArchiveMemberList &list,
const Common::Path &pattern, bool matchPathComponents = false) const override;
/**
* Add all members of the Archive to list.
* Must only append to list, and not remove elements from it.
*
* @return the number of names added to list
*/
int listMembers(Common::ArchiveMemberList &list) const override;
/**
* Returns a ArchiveMember representation of the given file.
*/
const Common::ArchiveMemberPtr getMember(const Common::Path &path)
const override;
/**
* Create a stream bound to a member with the specified name in the
* archive. If no member with this name exists, 0 is returned.
* @return the newly created input stream
*/
Common::SeekableReadStream *createReadStreamForMember(
const Common::Path &path) const override;
bool isPathDirectory(const Common::Path &path) const override;
};
#ifndef RELEASE_BUILD
/**
* The data archive proxy class is used for debugging purposes to access engine data
* files when the create_ultima folder is in the search path. It will allow for
* local mucking around with the data files and committing changes without having to
* recreate the ultima.dat file every time a change is made. ultima.dat then just has
* to be recreated prior to a release or when the changes are completed and stable
*/
class UltimaDataArchiveProxy : public Common::Archive {
friend class UltimaDataArchive;
private:
Common::FSNode _folder;
const Common::Path _publicFolder;
UltimaDataArchiveProxy(const Common::FSNode &folder) : _folder(folder), _publicFolder("data/") {}
/**
* Gets a file node from the passed filename
*/
Common::FSNode getNode(const Common::Path &name) const;
public:
~UltimaDataArchiveProxy() override {
}
/**
* Check if a member with the given name is present in the Archive.
* Patterns are not allowed, as this is meant to be a quick File::exists()
* replacement.
*/
bool hasFile(const Common::Path &path) const override {
return path.isRelativeTo(_publicFolder) && getNode(path).exists();
}
/**
* Add all members of the Archive matching the specified pattern to list.
* Must only append to list, and not remove elements from it.
*
* @return the number of members added to list
*/
int listMatchingMembers(Common::ArchiveMemberList &list,
const Common::Path &pattern, bool matchPathComponents = false) const override;
/**
* Add all members of the Archive to list.
* Must only append to list, and not remove elements from it.
*
* @return the number of names added to list
*/
int listMembers(Common::ArchiveMemberList &list) const override;
/**
* Returns a ArchiveMember representation of the given file.
*/
const Common::ArchiveMemberPtr getMember(const Common::Path &path)
const override;
/**
* Create a stream bound to a member with the specified name in the
* archive. If no member with this name exists, 0 is returned.
* @return the newly created input stream
*/
Common::SeekableReadStream *createReadStreamForMember(
const Common::Path &path) const override;
bool isPathDirectory(const Common::Path &path) const override;
};
#endif
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,255 @@
/* 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 "common/scummsys.h"
#include "graphics/cursorman.h"
#include "common/events.h"
#include "common/endian.h"
#include "common/system.h"
#include "engines/util.h"
#include "ultima/shared/engine/events.h"
namespace Ultima {
namespace Shared {
EventsManager::EventsManager(EventsCallback *callback) : _callback(callback), _playTime(0),
_gameCounter(0), _frameCounter(0), _priorFrameCounterTime(0), _buttonsDown(0),
_specialButtons(0), _priorFrameTime(0) {
}
void EventsManager::showCursor() {
CursorMan.showMouse(true);
}
void EventsManager::hideCursor() {
CursorMan.showMouse(false);
}
bool EventsManager::isCursorVisible() {
return CursorMan.isVisible();
}
bool EventsManager::pollEvent(Common::Event &event) {
uint32 timer = g_system->getMillis();
if (timer >= (_priorFrameCounterTime + GAME_FRAME_TIME)) {
// Time to build up next game frame
_priorFrameCounterTime = timer;
nextFrame();
}
// Event handling
if (g_system->getEventManager()->pollEvent(event)) {
if (isMouseDownEvent(event.type)) {
setButtonDown(whichButton(event.type), true);
_mousePos = event.mouse;
} else if (isMouseUpEvent(event.type)) {
setButtonDown(whichButton(event.type), false);
_mousePos = event.mouse;
} else if (event.type == Common::EVENT_MOUSEMOVE) {
_mousePos = event.mouse;
}
switch (event.type) {
case Common::EVENT_KEYDOWN: {
handleKbdSpecial(event.kbd);
break;
}
case Common::EVENT_KEYUP:
handleKbdSpecial(event.kbd);
break;
case Common::EVENT_MOUSEMOVE:
_mousePos = event.mouse;
break;
case Common::EVENT_LBUTTONDOWN:
case Common::EVENT_RBUTTONDOWN:
break;
case Common::EVENT_LBUTTONUP:
case Common::EVENT_RBUTTONUP:
break;
default:
break;
}
return true;
}
return false;
}
void EventsManager::pollEvents() {
Common::Event event;
while (pollEvent(event)) {
switch (event.type) {
case Common::EVENT_MOUSEMOVE:
eventTarget()->mouseMove(_mousePos);
break;
case Common::EVENT_LBUTTONDOWN:
eventTarget()->leftButtonDown(_mousePos);
break;
case Common::EVENT_LBUTTONUP:
eventTarget()->leftButtonUp(_mousePos);
break;
case Common::EVENT_MBUTTONDOWN:
eventTarget()->middleButtonDown(_mousePos);
break;
case Common::EVENT_MBUTTONUP:
eventTarget()->middleButtonUp(_mousePos);
break;
case Common::EVENT_RBUTTONDOWN:
eventTarget()->rightButtonDown(_mousePos);
break;
case Common::EVENT_RBUTTONUP:
eventTarget()->rightButtonUp(_mousePos);
break;
case Common::EVENT_WHEELUP:
case Common::EVENT_WHEELDOWN:
eventTarget()->mouseWheel(_mousePos, event.type == Common::EVENT_WHEELUP);
break;
case Common::EVENT_KEYDOWN:
eventTarget()->keyDown(event.kbd);
break;
case Common::EVENT_KEYUP:
eventTarget()->keyUp(event.kbd);
break;
default:
break;
}
}
}
void EventsManager::pollEventsAndWait() {
pollEvents();
g_system->delayMillis(10);
}
void EventsManager::nextFrame() {
++_frameCounter;
++_playTime;
// Handle any idle updates
if (!_eventTargets.empty())
eventTarget()->onIdle();
// Render anything pending for the screen
Graphics::Screen *screen = _callback->getScreen();
if (screen)
screen->update();
}
void EventsManager::setButtonDown(MouseButton button, bool isDown) {
assert(button != BUTTON_NONE);
byte mask = 0;
switch (button) {
case BUTTON_LEFT:
mask = MK_LBUTTON;
break;
case BUTTON_RIGHT:
mask = MK_RBUTTON;
break;
case BUTTON_MIDDLE:
mask = MK_MBUTTON;
break;
default:
break;
}
if (isDown) {
_buttonsDown |= BUTTON_MASK(button);
_specialButtons |= mask;
} else {
_buttonsDown &= ~BUTTON_MASK(button);
_specialButtons &= ~mask;
}
}
uint32 EventsManager::getTicksCount() const {
return _frameCounter * GAME_FRAME_TIME;
}
void EventsManager::sleep(uint time) {
uint32 delayEnd = g_system->getMillis() + time;
while (!g_engine->shouldQuit() && g_system->getMillis() < delayEnd)
pollEventsAndWait();
}
bool EventsManager::waitForPress(uint expiry) {
uint32 delayEnd = g_system->getMillis() + expiry;
CPressTarget pressTarget;
addTarget(&pressTarget);
while (!g_engine->shouldQuit() && g_system->getMillis() < delayEnd && !pressTarget._pressed) {
pollEventsAndWait();
}
removeTarget();
return pressTarget._pressed;
}
void EventsManager::setMousePos(const Point &pt) {
g_system->warpMouse(pt.x, pt.y);
_mousePos = pt;
eventTarget()->mouseMove(_mousePos);
}
void EventsManager::handleKbdSpecial(Common::KeyState keyState) {
if (keyState.flags & Common::KBD_CTRL)
_specialButtons |= MK_CONTROL;
else
_specialButtons &= ~MK_CONTROL;
if (keyState.flags & Common::KBD_SHIFT)
_specialButtons |= MK_SHIFT;
else
_specialButtons &= ~MK_SHIFT;
}
bool shouldQuit() {
return g_engine->shouldQuit();
}
bool isMouseDownEvent(Common::EventType type) {
return type == Common::EVENT_LBUTTONDOWN || type == Common::EVENT_RBUTTONDOWN
|| type == Common::EVENT_MBUTTONDOWN;
}
bool isMouseUpEvent(Common::EventType type) {
return type == Common::EVENT_LBUTTONUP || type == Common::EVENT_RBUTTONUP
|| type == Common::EVENT_MBUTTONUP;
}
MouseButton whichButton(Common::EventType type) {
if (type == Common::EVENT_LBUTTONDOWN || type == Common::EVENT_LBUTTONUP)
return BUTTON_LEFT;
else if (type == Common::EVENT_RBUTTONDOWN || type == Common::EVENT_RBUTTONUP)
return BUTTON_RIGHT;
else if (type == Common::EVENT_MBUTTONDOWN || type == Common::EVENT_MBUTTONUP)
return BUTTON_MIDDLE;
else
return BUTTON_NONE;
}
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,338 @@
/* 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 ULTIMA_SHARED_ENGINE_EVENTS_H
#define ULTIMA_SHARED_ENGINE_EVENTS_H
#include "common/scummsys.h"
#include "common/events.h"
#include "common/stack.h"
#include "gui/debugger.h"
#include "graphics/screen.h"
#include "ultima/shared/core/rect.h"
namespace Ultima {
namespace Shared {
#define GAME_FRAME_RATE (1000 / 50)
#define GAME_FRAME_TIME 50
#define SCREEN_UPDATE_TIME 10
#define BUTTON_MASK(MB) (1 << ((int)(MB) - 1))
#define DOUBLE_CLICK_TIME 100
enum MouseButton {
BUTTON_NONE = 0,
BUTTON_LEFT = 1,
BUTTON_RIGHT = 2,
BUTTON_MIDDLE = 3,
MOUSE_LAST
};
enum SpecialButtons {
MK_LBUTTON = 1, MK_RBUTTON = 2, MK_MBUTTON = 4, MK_SHIFT = 8, MK_CONTROL = 0x10
};
/**
* A base class for windows that can receive event messages
*/
class EventTarget {
public:
virtual ~EventTarget() {
}
/**
* Called to handle any regular updates the game requires
*/
virtual void onIdle() {
}
/**
* Mouse/key event handlers
*/
virtual void mouseMove(const Common::Point &mousePos) {
}
virtual void leftButtonDown(const Common::Point &mousePos) {
}
virtual void leftButtonUp(const Common::Point &mousePos) {
}
virtual void leftButtonDoubleClick(const Common::Point &mousePos) {
}
virtual void middleButtonDown(const Common::Point &mousePos) {
}
virtual void middleButtonUp(const Common::Point &mousePos) {
}
virtual void middleButtonDoubleClick(const Common::Point &mousePos) {
}
virtual void rightButtonDown(const Common::Point &mousePos) {
}
virtual void rightButtonUp(const Common::Point &mousePos) {
}
virtual void mouseWheel(const Common::Point &mousePos, bool wheelUp) {
}
virtual void keyDown(Common::KeyState keyState) {
}
virtual void keyUp(Common::KeyState keyState) {
}
};
/**
* An eent target used for waiting for a mouse or keypress
*/
class CPressTarget : public EventTarget {
public:
bool _pressed;
public:
CPressTarget() : _pressed(false) {
}
~CPressTarget() override {
}
void leftButtonDown(const Common::Point &mousePos) override {
_pressed = true;
}
void middleButtonDown(const Common::Point &mousePos) override {
_pressed = true;
}
void rightButtonDown(const Common::Point &mousePos) override {
_pressed = true;
}
void keyDown(Common::KeyState keyState) override {
_pressed = true;
}
};
/**
* Abstract interface for engine functionality the events manager needs to access
*/
class EventsCallback {
public:
/**
* Destructor
*/
virtual ~EventsCallback() {}
/**
* Get the screen
*/
virtual Graphics::Screen *getScreen() const {
return nullptr;
}
};
class EventsManager {
private:
EventsCallback *_callback;
Common::Stack<EventTarget *> _eventTargets;
uint32 _frameCounter;
uint32 _priorFrameTime;
uint32 _priorFrameCounterTime;
uint32 _gameCounter;
uint32 _playTime;
Point _mousePos;
uint _specialButtons;
uint8 _buttonsDown;
/**
* Check whether it's time to display the next screen frame
*/
bool checkForNextFrameCounter();
/**
* Return the currently active event target
*/
EventTarget *eventTarget() const {
return _eventTargets.top();
}
/**
* Handles setting/resettings special buttons on key up/down
*/
void handleKbdSpecial(Common::KeyState keyState);
/**
* Sets whether a given button is depressed
*/
void setButtonDown(MouseButton button, bool isDown);
protected:
/**
* Handles moving to the next game frame
*/
virtual void nextFrame();
public:
EventsManager(EventsCallback *callback);
virtual ~EventsManager() {}
/**
* Adds a new event target to the top of the list. It will get
* all events generated until such time as another is pushed on
* top of it, or the removeTarget method is called
*/
void addTarget(EventTarget *target) {
_eventTargets.push(target);
}
/**
* Removes the currently active event target
*/
void removeTarget() {
_eventTargets.pop();
}
/**
* Polls the ScummVM backend for any pending events, passing out the event, if any
*/
virtual bool pollEvent(Common::Event &event);
/**
* Checks for any pending events. This differs from pollEvent, in that the event manager will dispatch
* all pending events to the currently registered active event target, rather than simply returning a
* single event like pollEvent does
*/
void pollEvents();
/**
* Poll for events and introduce a small delay, to allow the system to
* yield to other running programs
*/
void pollEventsAndWait();
/**
* Return the current game frame number
*/
uint32 getFrameCounter() const {
return _frameCounter;
}
/**
* Get the elapsed playtime
*/
uint32 getTicksCount() const;
/**
* Sleep for a specified period of time
*/
void sleep(uint time);
/**
* Wait for a mouse or keypress
*/
bool waitForPress(uint expiry);
/**
* Sets the mouse position
*/
void setMousePos(const Point &pt);
/*
* Return whether a given special key is currently pressed
*/
bool isSpecialPressed(SpecialButtons btn) const {
return (_specialButtons & btn) != 0;
}
/**
* Returns the bitset of the currently pressed special buttons
*/
uint getSpecialButtons() const {
return _specialButtons;
}
/*
* Set the cursor
*/
virtual void setCursor(int cursorId) {
}
/**
* Show the mouse cursor
*/
void showCursor();
/**
* Hide the mouse cursor
*/
void hideCursor();
/**
* Returns if the mouse cursor is visible
*/
bool isCursorVisible();
/**
* Gets the current total ticks
*/
uint32 getTicks() {
return _frameCounter;
}
/**
* Gets the total overall play time
*/
uint32 playTime() const {
return _playTime;
}
/**
* Sets the current play time
*/
void setPlayTime(uint32 time) {
_playTime = time;
}
/**
* Returns true if a given mouse button is pressed
*/
inline bool isButtonDown(MouseButton button) const {
return (_buttonsDown & BUTTON_MASK(button)) != 0;
}
/**
* Returns true if any mouse button is pressed
*/
bool isButtonDown() const {
return isButtonDown(BUTTON_LEFT) || isButtonDown(BUTTON_RIGHT) || isButtonDown(BUTTON_MIDDLE);
}
/**
* Returns the mouse buttons states
*/
byte getButtonState() const {
return _buttonsDown;
}
/**
* Return the mouse position
*/
Common::Point getMousePos() const {
return _mousePos;
}
};
extern bool isMouseDownEvent(Common::EventType type);
extern bool isMouseUpEvent(Common::EventType type);
extern MouseButton whichButton(Common::EventType type);
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,118 @@
/* 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/shared/engine/input_handler.h"
#include "ultima/shared/engine/events.h"
#include "ultima/shared/early/game_base.h"
#include "ultima/shared/engine/messages.h"
#include "ultima/shared/gfx/visual_item.h"
namespace Ultima {
namespace Shared {
InputHandler::InputHandler(GameBase *game) : _game(game), _inputTranslator(nullptr), _dragging(false),
_buttonDown(false), _lockCount(0), _abortMessage(false) {
}
InputHandler::~InputHandler() {
}
void InputHandler::setTranslator(InputTranslator *translator) {
_inputTranslator = translator;
}
void InputHandler::incLockCount() {
++_lockCount;
}
void InputHandler::decLockCount() {
--_lockCount;
assert(_lockCount >= 0);
if (_lockCount == 0 && _inputTranslator) {
if (_dragging && !_inputTranslator->isMousePressed()) {
CMouseButtonUpMsg upMsg(_mousePos, MK_LBUTTON);
handleMessage(upMsg);
}
_buttonDown = _inputTranslator->isMousePressed();
_abortMessage = true;
}
}
void InputHandler::handleMessage(CMessage &msg, bool respectLock) {
if (!respectLock || _lockCount <= 0) {
processMessage(&msg);
}
}
void InputHandler::processMessage(CMessage *msg) {
const CMouseMsg *mouseMsg = dynamic_cast<const CMouseMsg *>(msg);
_abortMessage = false;
dispatchMessage(msg);
if (_abortMessage) {
_abortMessage = false;
} else if (mouseMsg) {
// Keep the game state mouse position up to date
if (_mousePos != mouseMsg->_mousePos) {
_mousePos = mouseMsg->_mousePos;
}
// Set flag for whether a mouse button is currently being pressed
if (mouseMsg->isButtonDownMsg())
_buttonDown = true;
else if (mouseMsg->isButtonUpMsg())
_buttonDown = false;
// Drag events generation
if (_dragging) {
if (mouseMsg->isMouseMoveMsg()) {
CMouseDragMsg moveMsg(_mousePos, mouseMsg->_buttons);
dispatchMessage(&moveMsg);
} else if (mouseMsg->isButtonUpMsg()) {
_dragging = false;
}
} else if (_buttonDown) {
if (!mouseMsg->isMouseMoveMsg()) {
// Save where the drag movement started from
_dragStartPos = _mousePos;
} else {
Point delta = _mousePos - _dragStartPos;
int distance = (int)sqrt(double(delta.x * delta.x + delta.y * delta.y));
if (distance > 4) {
// A drag has started
_dragging = true;
}
}
}
}
}
void InputHandler::dispatchMessage(CMessage *msg) {
Gfx::VisualItem *view = _game->getView();
if (view)
msg->execute(view);
}
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,78 @@
/* 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 ULTIMA_SHARED_ENGINE_INPUT_HANDLER_H
#define ULTIMA_SHARED_ENGINE_INPUT_HANDLER_H
#include "ultima/shared/engine/input_translator.h"
#include "ultima/shared/core/tree_item.h"
namespace Ultima {
namespace Shared {
class GameBase;
class InputHandler {
private:
/**
* Process and dispatch a passed message
*/
void processMessage(CMessage *msg);
/**
* Dispatches a message to the project
*/
void dispatchMessage(CMessage *msg);
public:
GameBase *_game;
InputTranslator *_inputTranslator;
bool _dragging;
bool _buttonDown;
Point _mousePos;
Point _dragStartPos;
int _lockCount;
bool _abortMessage;
public:
InputHandler(GameBase *game);
~InputHandler();
void setTranslator(InputTranslator *translator);
/**
* Increment the lock count
*/
void incLockCount();
/**
* Decrement the lock count on the input handler
*/
void decLockCount();
/**
* Handles a genereated mouse message
*/
void handleMessage(CMessage &msg, bool respectLock = true);
};
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,123 @@
/* 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/shared/engine/input_handler.h"
#include "ultima/shared/engine/input_translator.h"
#include "ultima/shared/engine/events.h"
#include "ultima/shared/engine/messages.h"
#include "ultima/shared/early/ultima_early.h"
namespace Ultima {
namespace Shared {
InputTranslator::InputTranslator(InputHandler *inputHandler) :
_inputHandler(inputHandler) {
inputHandler->setTranslator(this);
}
int InputTranslator::getButtons(int special) const {
int buttons = 0;
if (special & MK_LBUTTON)
buttons |= MB_LEFT;
if (special & MK_MBUTTON)
buttons |= MB_MIDDLE;
if (special & MK_RBUTTON)
buttons |= MB_RIGHT;
return buttons;
}
void InputTranslator::mouseMove(int special, const Point &pt) {
CMouseMoveMsg msg(pt, getButtons(special));
_inputHandler->handleMessage(msg);
}
void InputTranslator::mouseDrag(int special, const Point &pt) {
CMouseDragMsg msg(pt, getButtons(special));
_inputHandler->handleMessage(msg);
}
void InputTranslator::leftButtonDown(int special, const Point &pt) {
CMouseButtonDownMsg msg(pt, MB_LEFT);
_inputHandler->handleMessage(msg);
}
void InputTranslator::leftButtonUp(int special, const Point &pt) {
CMouseButtonUpMsg msg(pt, MB_LEFT);
_inputHandler->handleMessage(msg);
}
void InputTranslator::leftButtonDoubleClick(int special, const Point &pt) {
CMouseDoubleClickMsg msg(pt, MB_LEFT);
_inputHandler->handleMessage(msg);
}
void InputTranslator::middleButtonDown(int special, const Point &pt) {
CMouseButtonDownMsg msg(pt, MB_MIDDLE);
_inputHandler->handleMessage(msg);
}
void InputTranslator::middleButtonUp(int special, const Point &pt) {
CMouseButtonUpMsg msg(pt, MB_MIDDLE);
_inputHandler->handleMessage(msg);
}
void InputTranslator::middleButtonDoubleClick(int special, const Point &pt) {
CMouseDoubleClickMsg msg(pt, MB_MIDDLE);
_inputHandler->handleMessage(msg);
}
void InputTranslator::rightButtonDown(int special, const Point &pt) {
CMouseButtonDownMsg msg(pt, MB_RIGHT);
_inputHandler->handleMessage(msg);
}
void InputTranslator::rightButtonUp(int special, const Point &pt) {
CMouseButtonUpMsg msg(pt, MB_RIGHT);
_inputHandler->handleMessage(msg);
}
void InputTranslator::mouseWheel(bool wheelUp, const Point &pt) {
CMouseWheelMsg msg(pt, wheelUp);
_inputHandler->handleMessage(msg);
}
void InputTranslator::rightButtonDoubleClick(int special, const Point &pt) {
CMouseDoubleClickMsg msg(pt, MB_RIGHT);
_inputHandler->handleMessage(msg);
}
void InputTranslator::keyDown(const Common::KeyState &keyState) {
CKeypressMsg pressMsg(keyState);
_inputHandler->handleMessage(pressMsg);
if (keyState.ascii >= 32 && keyState.ascii <= 127) {
CKeyCharMsg charMsg(keyState.ascii);
_inputHandler->handleMessage(charMsg);
}
}
bool InputTranslator::isMousePressed() const {
return g_vm->_events->getSpecialButtons() & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON);
}
} // End of namespace Shared
} // End of namespace Ultima

View 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 ULTIMA_SHARED_ENGINE_INPUT_TRANSLATOR_H
#define ULTIMA_SHARED_ENGINE_INPUT_TRANSLATOR_H
#include "common/keyboard.h"
#include "ultima/shared/engine/messages.h"
namespace Ultima {
namespace Shared {
class InputHandler;
class InputTranslator {
private:
/**
* Converts the special buttons bitset into a buttons bitset
*/
int getButtons(int special) const;
public:
InputHandler *_inputHandler;
public:
InputTranslator(InputHandler *inputHandler);
void mouseMove(int special, const Point &pt);
void mouseDrag(int special, const Point &pt);
void leftButtonDown(int special, const Point &pt);
void leftButtonUp(int special, const Point &pt);
void leftButtonDoubleClick(int special, const Point &pt);
void middleButtonDown(int special, const Point &pt);
void middleButtonUp(int special, const Point &pt);
void middleButtonDoubleClick(int special, const Point &pt);
void rightButtonDown(int special, const Point &pt);
void rightButtonUp(int special, const Point &pt);
void mouseWheel(bool wheelUp, const Point &pt);
void rightButtonDoubleClick(int special, const Point &pt);
void keyDown(const Common::KeyState &keyState);
/**
* Returns true if any mouse button is currently pressed
*/
bool isMousePressed() const;
};
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,121 @@
/* 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/shared/engine/messages.h"
#include "ultima/shared/early/ultima_early.h"
#include "ultima/shared/early/game_base.h"
#include "ultima/shared/gfx/screen.h"
#include "ultima/shared/early/game.h"
namespace Ultima {
namespace Shared {
CMessage::CMessage() : BaseObject() {
}
bool CMessage::execute(TreeItem *target, const ClassDef *classDef, int flags) {
// If no target was specified, then there's nothing to do
if (!target)
return false;
bool result = false;
TreeItem *item = target;
TreeItem *nextItem = nullptr;
do {
if (flags & MSGFLAG_SCAN)
nextItem = item->scan(target);
if (!classDef || item->isInstanceOf(*classDef)) {
bool handled = perform(item);
if (handled) {
result = true;
if (flags & MSGFLAG_BREAK_IF_HANDLED)
return true;
}
}
item = nextItem;
} while (nextItem);
return result;
}
bool CMessage::execute(const Common::String &target, const ClassDef *classDef, int flags) {
// Scan for the target by name
GameBase *game = g_vm->_game;
for (TreeItem *treeItem = game; treeItem; treeItem = treeItem->scan(game)) {
if (!treeItem->getName().compareToIgnoreCase(target))
return execute(treeItem, classDef, flags);
}
return false;
}
const MSGMAP_ENTRY *CMessage::findMapEntry(const TreeItem *treeItem, const ClassDef &classDef) {
// Iterate through the class and any parent classes
for (const MSGMAP *msgMap = treeItem->getMessageMap(); msgMap->pFnGetBaseMap;
msgMap = msgMap->pFnGetBaseMap()) {
// Iterate through the map entries for this class
for (const MSGMAP_ENTRY *entry = msgMap->lpEntries;
entry->_classDef != nullptr; ++entry) {
// Check if the class or any of it's ancesotrs is handled by this entry
for (ClassDef def = (*entry->_classDef)(); def.hasParent(); def = def.parent()) {
if (def == classDef)
return entry;
}
}
}
return nullptr;
}
bool CMessage::perform(TreeItem *treeItem) {
const MSGMAP_ENTRY *entry = findMapEntry(treeItem, getType());
return entry && (*treeItem.*(entry->_fn))(this);
}
bool CMessage::supports(const TreeItem *treeItem, const ClassDef &classDef) {
return findMapEntry(treeItem, classDef) != nullptr;
}
bool CMessage::isMouseMsg() const {
return dynamic_cast<const CMouseMsg *>(this) != nullptr;
}
bool CMessage::isButtonDownMsg() const {
return dynamic_cast<const CMouseButtonDownMsg *>(this) != nullptr;
}
bool CMessage::isButtonUpMsg() const {
return dynamic_cast<const CMouseButtonUpMsg *>(this) != nullptr;
}
bool CMessage::isMouseMoveMsg() const {
return dynamic_cast<const CMouseMoveMsg *>(this) != nullptr;
}
bool CMessage::isDoubleClickMsg() const {
return dynamic_cast<const CMouseDoubleClickMsg *>(this) != nullptr;
}
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,407 @@
/* 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 ULTIMA_SHARED_ENGINE_MESSAGES_H
#define ULTIMA_SHARED_ENGINE_MESSAGES_H
#include "common/keyboard.h"
#include "common/events.h"
#include "ultima/shared/core/rect.h"
#include "ultima/shared/core/base_object.h"
#include "ultima/shared/core/tree_item.h"
namespace Ultima {
namespace Shared {
enum MessageFlag {
MSGFLAG_SCAN = 1,
MSGFLAG_BREAK_IF_HANDLED = 2,
MSGFLAG_CLASS_DEF = 4
};
class CMessage;
namespace Gfx {
class VisualItem;
class TextInput;
class Popup;
}
#define MESSAGEDEF(theClass) \
static ClassDef type() { return ClassDef(#theClass, &CMessage::type); } \
virtual ClassDef getType() const { return type(); }
#define MESSAGEDEFP(theClass, baseClass) \
static ClassDef type() { return ClassDef(#theClass, &baseClass::type); } \
virtual ClassDef getType() const { return type(); }
#define MESSAGE0(NAME) \
class NAME: public CMessage { \
public: NAME() : CMessage() {} \
MESSAGEDEF(NAME); \
}
#define MESSAGE1(NAME, F1, N1, V1) \
class NAME: public CMessage { \
public: F1 _##N1; \
NAME(F1 N1 = V1) : CMessage(), _##N1(N1) {} \
MESSAGEDEF(NAME); \
}
#define MESSAGE2(NAME, F1, N1, V1, F2, N2, V2) \
class NAME: public CMessage { \
public: F1 _##N1; F2 _##N2; \
NAME(F1 N1 = V1, F2 N2 = V2) : CMessage(), _##N1(N1), _##N2(N2) {} \
MESSAGEDEF(NAME); \
}
#define MESSAGE3(NAME, F1, N1, V1, F2, N2, V2, F3, N3, V3) \
class NAME: public CMessage { \
public: F1 _##N1; F2 _##N2; F3 _##N3; \
NAME(F1 N1 = V1, F2 N2 = V2, F3 N3 = V3) : CMessage(), _##N1(N1), _##N2(N2), _##N3(N3) {} \
MESSAGEDEF(NAME); \
}
#define MESSAGE4(NAME, F1, N1, V1, F2, N2, V2, F3, N3, V3, F4, N4, V4) \
class NAME: public CMessage { \
public: F1 _##N1; F2 _##N2; F3 _##N3; F4 _##N4; \
NAME(F1 N1 = V1, F2 N2 = V2, F3 N3 = V3, F4 N4 = V4) : CMessage(), _##N1(N1), _##N2(N2), _##N3(N3), _##N4(N4) {} \
MESSAGEDEF(NAME); \
}
/**
* Base class for all messages
*/
class CMessage : public BaseObject {
private:
/**
* Find a map entry that supports the given class
*/
static const MSGMAP_ENTRY *findMapEntry(const TreeItem *treeItem, const ClassDef &classDef);
public:
MESSAGEDEFP(CMessage, BaseObject);
CMessage();
/**
* Executes the message, passing it on to the designated target,
* and optionally it's children
*/
bool execute(TreeItem *target, const ClassDef *classDef = nullptr,
int flags = MSGFLAG_SCAN | MSGFLAG_BREAK_IF_HANDLED);
/**
* Executes the message, passing it on to the designated target,
* and optionally it's children
*/
bool execute(const Common::String &target, const ClassDef *classDef = nullptr,
int flags = MSGFLAG_SCAN | MSGFLAG_BREAK_IF_HANDLED);
/**
* Makes the passed item execute the message
*/
virtual bool perform(TreeItem *treeItem);
/**
* Returns true if the passed item supports the specified message class
*/
static bool supports(const TreeItem *treeItem, const ClassDef &classDef);
virtual bool isMouseMsg() const;
virtual bool isButtonDownMsg() const;
virtual bool isButtonUpMsg() const;
virtual bool isMouseMoveMsg() const;
virtual bool isDoubleClickMsg() const;
};
enum CMouseButton {
MB_LEFT = 1, MB_MIDDLE = 2, MB_RIGHT = 4
};
/**
* Base class for the different mouse notifications
*/
class CMouseMsg : public CMessage {
public:
int _buttons;
Point _mousePos;
public:
MESSAGEDEF(CMouseMsg);
CMouseMsg() : _buttons(0) {}
CMouseMsg(const Point &pt, int buttons) :
_mousePos(pt), _buttons(buttons) {}
};
/**
* Notifies a mouse movement
*
*/
class CMouseMoveMsg : public CMouseMsg {
public:
MESSAGEDEFP(CMouseMoveMsg, CMouseMsg);
CMouseMoveMsg() : CMouseMsg() {}
CMouseMoveMsg(const Point &pt, int buttons) : CMouseMsg(pt, buttons) {}
};
/**
* Notifies of a mouse drag operation
*/
class CMouseDragMsg : public CMouseMoveMsg {
public:
MESSAGEDEFP(CMouseDragMsg, CMouseMoveMsg);
CMouseDragMsg() : CMouseMoveMsg() {}
CMouseDragMsg(const Point &pt, int buttons) : CMouseMoveMsg(pt, buttons) {}
};
/**
* Base class for mouse button notifications
*/
class CMouseButtonMsg : public CMouseMsg {
public:
MESSAGEDEFP(CMouseButtonMsg, CMouseMsg);
CMouseButtonMsg() : CMouseMsg() {}
CMouseButtonMsg(const Point &pt, int buttons) : CMouseMsg(pt, buttons) {}
};
/**
* Notifies a mouse button down
*/
class CMouseButtonDownMsg : public CMouseButtonMsg {
public:
MESSAGEDEFP(CMouseButtonDownMsg, CMouseButtonMsg);
CMouseButtonDownMsg() : CMouseButtonMsg() {}
CMouseButtonDownMsg(const Point &pt, int buttons) : CMouseButtonMsg(pt, buttons) {}
};
/**
* Notifies a mouse button release
*/
class CMouseButtonUpMsg : public CMouseButtonMsg {
public:
MESSAGEDEFP(CMouseButtonUpMsg, CMouseButtonMsg);
CMouseButtonUpMsg() : CMouseButtonMsg() {}
CMouseButtonUpMsg(const Point &pt, int buttons) : CMouseButtonMsg(pt, buttons) {}
};
/**
* Notifies a mouse wheel action
*/
class CMouseWheelMsg : public CMouseMsg {
public:
bool _wheelUp;
public:
MESSAGEDEFP(CMouseWheelMsg, CMouseMsg);
CMouseWheelMsg() : CMouseMsg(), _wheelUp(false) {}
CMouseWheelMsg(const Point &pt, bool wheelUp) :
CMouseMsg(pt, 0), _wheelUp(wheelUp) {}
};
/**
* Notifies a mouse double-click
*/
class CMouseDoubleClickMsg : public CMouseButtonMsg {
public:
MESSAGEDEFP(CMouseDuobleClickMsg, CMouseButtonMsg);
CMouseDoubleClickMsg() : CMouseButtonMsg() {}
CMouseDoubleClickMsg(const Point &pt, int buttons) : CMouseButtonMsg(pt, buttons) {}
};
/**
* Used to notify that a rendering frame has finished, occurring at GAME_FRAME_RATE times every second
*/
MESSAGE1(CFrameMsg, uint, ticks, 0);
/**
* Notifies a game view is being hidden
*/
MESSAGE2(CHideMsg, Gfx::VisualItem *, view, (Gfx::VisualItem *)nullptr, bool, fadeOut, false);
/**
* Show a prompt in the info area, and get a keypress for a command
*/
MESSAGE1(CInfoGetCommandKeypress, TreeItem *, responder, (TreeItem *)nullptr);
/**
* Get a keypress in the info area
*/
MESSAGE1(CInfoGetKeypress, TreeItem *, responder, (TreeItem *)nullptr);
/**
* Get a text input in the input area
*/
MESSAGE3(CInfoGetInput, TreeItem *, responder, (TreeItem *)nullptr, bool, isNumeric, false, size_t, maxCharacters, 10);
/**
* Adds text strings to the info area
*/
MESSAGE3(CInfoMsg, Common::String, text, "", bool, newLine, true, bool, replaceLine, false);
/**
* Signals an unknown/unhandled keypress
*/
MESSAGE0(CHuhMsg);
/**
* Signals a single standard ASCII keypress
*/
MESSAGE1(CKeyCharMsg, int, key, 32);
/**
* Signals a keypress
*/
MESSAGE1(CKeypressMsg, Common::KeyState, keyState, Common::KeyState());
/**
* Called when a popup is finally shown
*/
MESSAGE1(CPopupShownMsg, Gfx::Popup *, view, (Gfx::Popup *)nullptr);
/**
* Called when a popup is hidden
*/
MESSAGE1(CPopupHiddenMsg, Gfx::Popup *, view, (Gfx::Popup *)nullptr);
/**
* Called when a game view is shown
*/
MESSAGE2(CShowMsg, Gfx::VisualItem *, view, (Gfx::VisualItem *)nullptr, bool, fadeIn, false);
/**
* Used when text input is finished, to pass the text back to the owning view
*/
MESSAGE2(CTextInputMsg, Common::String, text, "", bool, escaped, false);
/**
* Used when character input is finished, to pass the text back to the owning view
*/
MESSAGE1(CCharacterInputMsg, Common::KeyState, keyState, Common::KeyState());
/*-------------------------------------------------------------------*/
/**
* Used to trigger a party movement
*/
MESSAGE1(CMoveMsg, int, direction, 0);
/**
* Used to trigger an attack
*/
MESSAGE1(CAttackMsg, int, direction, 0);
/**
* Used to trigger a board action
*/
MESSAGE0(CBoardMsg);
/**
* Used to trigger a cast action
*/
MESSAGE0(CCastMsg);
/**
* Climb up or down
*/
MESSAGE0(CClimbMsg);
/**
* Used to trigger a drop action
*/
MESSAGE0(CDropMsg);
/**
* Used to trigger an Enter action
*/
MESSAGE0(CEnterMsg);
/**
* Used to trigger an exit action
*/
MESSAGE0(CExitTransportMsg);
/**
* Used to trigger a fire action
*/
MESSAGE0(CFireMsg);
/**
* Used to trigger a Get action
*/
MESSAGE0(CGetMsg);
/**
* Used to trigger a HyperJump action
*/
MESSAGE0(CHyperJumpMsg);
/**
* Used to trigger an inform action
*/
MESSAGE0(CInformMsg);
/**
* Used to trigger an open action
*/
MESSAGE0(COpenMsg);
/**
* Pass a turn
*/
MESSAGE0(CPassMsg);
/**
* Used to trigger a quit (save) action
*/
MESSAGE0(CQuitMsg);
/**
* Used to trigger a ready item/weapon/spell action
*/
MESSAGE0(CReadyMsg);
/**
* Used to trigger a stats action
*/
MESSAGE0(CStatsMsg);
/**
* Used to trigger a steal action
*/
MESSAGE0(CStealMsg);
/**
* Used to trigger a Transact action
*/
MESSAGE0(CTransactMsg);
/**
* Used to trigger an Unlock action
*/
MESSAGE0(CUnlockMsg);
/**
* Used to trigger a view change action
*/
MESSAGE0(CViewChangeMsg);
/**
* Used to signal an end of turn
*/
MESSAGE0(CEndOfTurnMsg);
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,265 @@
/* 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/shared/engine/resources.h"
#include "ultima/shared/early/font_resources.h"
#include "common/endian.h"
#ifndef RELEASE_BUILD
#include "ultima/ultima1/core/resources.h"
#endif
namespace Ultima {
namespace Shared {
/*-------------------------------------------------------------------*/
bool Resources::open() {
// Save locally constructred resources to the archive manager for access
Shared::FontResources sharedFonts(this);
sharedFonts.save();
#ifndef RELEASE_BUILD
Ultima1::GameResources u1Data(this);
u1Data.save();
#endif
return true;
}
void Resources::addResource(const Common::Path &name, const byte *data, size_t size) {
// Add a new entry to the local resources list for the passed data
_localResources.push_back(LocalResource());
LocalResource &lr = _localResources[_localResources.size() - 1];
lr._name = name;
lr._data.resize(size);
Common::copy(data, data + size, &lr._data[0]);
}
bool Resources::hasFile(const Common::Path &path) const {
for (uint idx = 0; idx < _localResources.size(); ++idx)
if (_localResources[idx]._name.equalsIgnoreCase(path))
return true;
return false;
}
int Resources::listMembers(Common::ArchiveMemberList &list) const {
for (uint idx = 0; idx < _localResources.size(); ++idx) {
list.push_back(Common::ArchiveMemberPtr(new Common::GenericArchiveMember(_localResources[idx]._name, *this)));
}
return _localResources.size();
}
const Common::ArchiveMemberPtr Resources::getMember(const Common::Path &path) const {
if (!hasFile(path))
return Common::ArchiveMemberPtr();
return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(path, *this));
}
Common::SeekableReadStream *Resources::createReadStreamForMember(const Common::Path &path) const {
for (uint idx = 0; idx < _localResources.size(); ++idx) {
const LocalResource &lr = _localResources[idx];
if (lr._name.equalsIgnoreCase(path))
return new Common::MemoryReadStream(&lr._data[0], lr._data.size());
}
return nullptr;
}
/*-------------------------------------------------------------------*/
void Resources::FileResource::load(File &f) {
_name = f.readString();
_offset = f.readUint32LE();
_size = f.readUint16LE();
}
/*-------------------------------------------------------------------*/
ResourceFile::ResourceFile(const Common::Path &filename) : _filename(filename), _bufferP(_buffer) {
Common::fill(_buffer, _buffer + STRING_BUFFER_SIZE, 0);
}
void ResourceFile::load() {
_file.open(_filename);
synchronize();
_file.close();
}
void ResourceFile::syncString(const char *&str) {
str = _bufferP;
do {
*_bufferP = _file.readByte();
} while (*_bufferP++);
assert(_bufferP < (_buffer + STRING_BUFFER_SIZE));
}
void ResourceFile::syncStrings(const char **str, size_t count) {
uint tag = _file.readUint32LE();
assert(tag == MKTAG(count, 0, 0, 0));
for (size_t idx = 0; idx < count; ++idx)
syncString(str[idx]);
}
void ResourceFile::syncStrings2D(const char **str, size_t count1, size_t count2) {
uint tag = _file.readUint32LE();
assert(tag == MKTAG(count1, count2, 0, 0));
for (size_t idx = 0; idx < count1 * count2; ++idx)
syncString(str[idx]);
}
void ResourceFile::syncNumber(int &val) {
val = _file.readSint32LE();
}
void ResourceFile::syncNumbers(int *vals, size_t count) {
uint tag = _file.readUint32LE();
assert(tag == MKTAG(count, 0, 0, 0));
for (size_t idx = 0; idx < count; ++idx)
vals[idx] = _file.readSint32LE();
}
void ResourceFile::syncNumbers2D(int *vals, size_t count1, size_t count2) {
uint tag = _file.readUint32LE();
assert(tag == MKTAG(count1, count2, 0, 0));
for (size_t idx = 0; idx < count1 * count2; ++idx)
vals[idx] = _file.readSint32LE();
}
void ResourceFile::syncNumbers3D(int *vals, size_t count1, size_t count2, size_t count3) {
uint tag = _file.readUint32LE();
assert(tag == MKTAG(count1, count2, count3, 0));
for (size_t idx = 0; idx < count1 * count2 * count3; ++idx)
vals[idx] = _file.readSint32LE();
}
void ResourceFile::syncBytes(byte *vals, size_t count) {
uint tag = _file.readUint32LE();
assert(tag == MKTAG(count, 0, 0, 0));
_file.read(vals, count);
}
void ResourceFile::syncBytes2D(byte *vals, size_t count1, size_t count2) {
uint tag = _file.readUint32LE();
assert(tag == MKTAG(count1, count2, 0, 0));
_file.read(vals, count1 * count2);
}
/*-------------------------------------------------------------------*/
void LocalResourceFile::save() {
synchronize();
_file.finalize();
_owner->addResource(_filename, _file.getData(), _file.size());
}
void LocalResourceFile::syncString(const char *&str) {
if (!_owner) {
ResourceFile::syncString(str);
} else {
_file.writeString(str);
_file.writeByte('\0');
}
}
void LocalResourceFile::syncStrings(const char **str, size_t count) {
if (!_owner) {
ResourceFile::syncStrings(str, count);
} else {
_file.writeUint32LE(MKTAG(count, 0, 0, 0));
for (size_t idx = 0; idx < count; ++idx)
syncString(str[idx]);
}
}
void LocalResourceFile::syncStrings2D(const char **str, size_t count1, size_t count2) {
if (!_owner) {
ResourceFile::syncStrings2D(str, count1, count2);
} else {
_file.writeUint32LE(MKTAG(count1, count2, 0, 0));
for (size_t idx = 0; idx < count1 * count2; ++idx)
syncString(str[idx]);
}
}
void LocalResourceFile::syncNumber(int &val) {
if (!_owner)
ResourceFile::syncNumber(val);
else
_file.writeUint32LE(val);
}
void LocalResourceFile::syncNumbers(int *vals, size_t count) {
if (!_owner) {
ResourceFile::syncNumbers(vals, count);
} else {
_file.writeUint32LE(MKTAG(count, 0, 0, 0));
for (size_t idx = 0; idx < count; ++idx)
_file.writeUint32LE(vals[idx]);
}
}
void LocalResourceFile::syncNumbers2D(int *vals, size_t count1, size_t count2) {
if (!_owner) {
ResourceFile::syncNumbers2D(vals, count1, count2);
} else {
_file.writeUint32LE(MKTAG(count1, count2, 0, 0));
for (size_t idx = 0; idx < count1 * count2; ++idx)
_file.writeUint32LE(vals[idx]);
}
}
void LocalResourceFile::syncNumbers3D(int *vals, size_t count1, size_t count2, size_t count3) {
if (!_owner) {
ResourceFile::syncNumbers3D(vals, count1, count2, count3);
} else {
_file.writeUint32LE(MKTAG(count1, count2, count3, 0));
for (size_t idx = 0; idx < count1 * count2 * count3; ++idx)
_file.writeUint32LE(vals[idx]);
}
}
void LocalResourceFile::syncBytes(byte *vals, size_t count) {
if (!_owner) {
ResourceFile::syncBytes(vals, count);
} else {
_file.writeUint32LE(MKTAG(count, 0, 0, 0));
_file.write(vals, count);
}
}
void LocalResourceFile::syncBytes2D(byte *vals, size_t count1, size_t count2) {
if (!_owner) {
ResourceFile::syncBytes2D(vals, count1, count2);
} else {
_file.writeUint32LE(MKTAG(count1, count2, 0, 0));
_file.write(vals, count1 * count2);
}
}
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,196 @@
/* 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 ULTIMA_SHARED_ENGINE_RESOURCES_H
#define ULTIMA_SHARED_ENGINE_RESOURCES_H
#include "common/algorithm.h"
#include "common/archive.h"
#include "common/array.h"
#include "common/memstream.h"
#include "common/str.h"
#include "common/serializer.h"
#include "ultima/shared/core/file.h"
#define STRING_BUFFER_SIZE 32768
namespace Ultima {
namespace Shared {
class Resources;
/**
* Base class for classes that exposes a set of strings, arrays, and other data from a resource
*/
class ResourceFile {
private:
File _file;
char _buffer[STRING_BUFFER_SIZE];
char *_bufferP;
protected:
Common::Path _filename;
protected:
/**
* Constructor
*/
ResourceFile(const Common::Path &filename);
/**
* Destructor
*/
virtual ~ResourceFile() {
}
/**
* Synchronizes the data for the resource
*/
virtual void synchronize() = 0;
virtual void syncString(const char *&str);
virtual void syncStrings(const char **str, size_t count);
virtual void syncStrings2D(const char **str, size_t count1, size_t count2);
virtual void syncNumber(int &val);
virtual void syncNumbers(int *vals, size_t count);
virtual void syncNumbers2D(int *vals, size_t count1, size_t count2);
virtual void syncNumbers3D(int *vals, size_t count1, size_t count2, size_t count3);
virtual void syncBytes(byte *vals, size_t count);
virtual void syncBytes2D(byte *vals, size_t count1, size_t count2);
public:
/**
* Loads in a resource
*/
void load();
};
/**
* Derived base class for resources that have their contents within the executable rather than a data file.
* This will allow the data for a particular Ultima game to be gradually built up without repeatedly
* regenerating a data file. Once a game has been properly tested, then it can be moved out.
*/
class LocalResourceFile : public ResourceFile {
private:
Common::MemoryWriteStreamDynamic _file;
Resources *_owner;
protected:
/**
* Constructor
*/
LocalResourceFile(const Common::Path &filename) : ResourceFile(filename), _owner(nullptr), _file(DisposeAfterUse::YES) {}
/**
* Constructor
*/
LocalResourceFile(Resources *owner, const Common::Path &filename) : ResourceFile(filename),
_owner(owner), _file(DisposeAfterUse::YES) {}
/**
* Return true if in saving mode
*/
bool isSaving() const { return _owner != nullptr; }
void syncString(const char *&str) override;
void syncStrings(const char **str, size_t count) override;
void syncStrings2D(const char **str, size_t count1, size_t count2) override;
void syncNumber(int &val) override;
void syncNumbers(int *vals, size_t count) override;
void syncNumbers2D(int *vals, size_t count1, size_t count2) override;
void syncNumbers3D(int *vals, size_t count1, size_t count2, size_t count3) override;
void syncBytes(byte *vals, size_t count) override;
void syncBytes2D(byte *vals, size_t count1, size_t count2) override;
public:
/**
* Write out the resource to the in-memory resource store
*/
void save();
};
/**
* Resources manager
*/
class Resources : public Common::Archive {
struct LocalResource {
Common::Path _name;
Common::Array<byte> _data;
};
struct FileResource {
Common::Path _name;
size_t _offset, _size;
/**
* Load an index entry from the datafile
*/
void load(File &f);
};
private:
Common::Array<LocalResource> _localResources;
public:
/**
* Constructor
*/
Resources() {
}
/**
* Sets up the resources for the engine
* @returns False if setup failed
*/
bool open();
/**
* Adds a resource created in memory to the ScummVM archive manager, so that it can be
* later opened like a normal file. Just as it will when eventually shifted to the
* data file for the engine
*/
void addResource(const Common::Path &name, const byte *data, size_t size);
// Archive implementation
/**
* Check if a member with the given name is present in the Archive.
* Patterns are not allowed, as this is meant to be a quick File::exists()
* replacement.
*/
bool hasFile(const Common::Path &path) const override;
/**
* Add all members of the Archive to list.
* Must only append to list, and not remove elements from it.
*
* @return the number of names added to list
*/
int listMembers(Common::ArchiveMemberList &list) const override;
/**
* Returns a ArchiveMember representation of the given file.
*/
const Common::ArchiveMemberPtr getMember(const Common::Path &path) const override;
/**
* Create a stream bound to a member with the specified name in the
* archive. If no member with this name exists, 0 is returned.
* @return the newly created input stream
*/
Common::SeekableReadStream *createReadStreamForMember(const Common::Path &path) const override;
};
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,66 @@
/* 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/shared/gfx/bitmap.h"
#include "ultima/shared/core/file.h"
#include "common/memstream.h"
#include "graphics/managed_surface.h"
namespace Ultima {
namespace Shared {
namespace Gfx {
void Bitmap::load(const Common::Path &filename) {
File srcFile(filename);
Common::MemoryWriteStreamDynamic decompressedFile(DisposeAfterUse::YES);
decompress(&srcFile, &decompressedFile);
// Set the bitmap size
Common::MemoryReadStream f(decompressedFile.getData(), decompressedFile.size());
int16 xs = f.readSint16LE();
int16 ys = f.readSint16LE();
create(xs, ys);
assert(f.size() == (xs * ys + 4));
Graphics::Surface s = getSubArea(Common::Rect(0, 0, xs, ys));
// Read in the lines
for (int y = 0; y < ys; ++y) {
byte *dest = (byte *)s.getBasePtr(0, y);
f.read(dest, xs);
}
}
void Bitmap::flipHorizontally() {
Graphics::Surface s = getSubArea(Common::Rect(0, 0, this->w, this->h));
for (int y = 0; y < h; ++y) {
byte *lineStart = (byte *)s.getBasePtr(0, y);
byte *lineEnd = (byte *)s.getBasePtr(this->w - 1, y);
for (int x = 0; x < (this->w - 1) / 2; ++x, ++lineStart, --lineEnd)
SWAP(*lineStart, *lineEnd);
}
}
} // End of namespace Gfx
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,51 @@
/* 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 ULTIMA_BITMAP_H
#define ULTIMA_BITMAP_H
#include "ultima/shared/core/lzw.h"
#include "common/path.h"
#include "common/stream.h"
#include "graphics/managed_surface.h"
namespace Ultima {
namespace Shared {
namespace Gfx {
class Bitmap : public Graphics::ManagedSurface, public LZW {
public:
/**
* Loads an Ultima 6 bitmap
*/
void load(const Common::Path &filename);
/**
* Flips a bitmap horizontally
*/
void flipHorizontally();
};
} // End of namespace Gfx
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,55 @@
/* 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/shared/gfx/character_input.h"
#include "ultima/shared/gfx/text_cursor.h"
#include "ultima/shared/early/game_base.h"
#include "ultima/shared/engine/messages.h"
namespace Ultima {
namespace Shared {
namespace Gfx {
BEGIN_MESSAGE_MAP(CharacterInput, Popup)
ON_MESSAGE(KeypressMsg)
END_MESSAGE_MAP()
void CharacterInput::show(const Point &pt, byte color, TreeItem *respondTo) {
Popup::show(respondTo);
_color = color;
_bounds = Rect(pt.x, pt.y, pt.x + 8, pt.y + 8);
_game->_textCursor->setPosition(Point(_bounds.left, _bounds.top));
_game->_textCursor->setVisible(true);
}
bool CharacterInput::KeypressMsg(CKeypressMsg *msg) {
hide();
CCharacterInputMsg inputMsg(msg->_keyState);
inputMsg.execute(_respondTo);
return true;
}
} // End of namespace Gfx
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,58 @@
/* 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 ULTIMA_GFX_CHARACTER_INPUT_H
#define ULTIMA_GFX_CHARACTER_INPUT_H
#include "ultima/shared/gfx/popup.h"
namespace Ultima {
namespace Shared {
namespace Gfx {
/**
* Text input control
*/
class CharacterInput : public Popup {
DECLARE_MESSAGE_MAP;
bool KeypressMsg(CKeypressMsg *msg);
private:
byte _color;
public:
CLASSDEF;
CharacterInput(GameBase *game) : Popup(game), _color(0) {
}
/**
* Show the character input
* @param pt Position of the input
* @param color Text color
* @param respondTo Where to send response to
* @remarks Generates a TextInputMsg message with the character when pressed
*/
void show(const Point &pt, byte color, TreeItem *respondTo = nullptr);
};
} // End of namespace Gfx
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,195 @@
/* 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/shared/gfx/dungeon_surface.h"
#include "ultima/shared/maps/map.h"
#include "ultima/shared/early/game.h"
namespace Ultima {
namespace Shared {
const byte ARRAY_X[] = { 0, 72, 108, 126, 135, 144 };
const byte ARRAY_Y[] = { 0, 36, 54, 63, 68, 72 };
DungeonSurface::DungeonSurface(const Graphics::ManagedSurface &src, const Rect &bounds, Game *game, DrawWidgetFn widgetFn) :
Gfx::VisualSurface(src, bounds), _widgetFn(widgetFn) {
_edgeColor = game->_edgeColor;
_highlightColor = game->_highlightColor;
_widgetColor = 0;
}
void DungeonSurface::drawWall(uint distance) {
int offsetX = !distance ? 8 : 0, offsetY = !distance ? 8 : 0;
if (distance <= 5) {
hLine(ARRAY_X[distance] + 16 + offsetX, ARRAY_Y[distance] + 8 + offsetY,
303 - ARRAY_X[distance] - offsetX, _edgeColor);
hLine(ARRAY_X[distance] + 16 + offsetX, 151 - ARRAY_Y[distance] - offsetY,
303 - ARRAY_X[distance] - offsetX, _edgeColor);
}
}
void DungeonSurface::drawDoorway(uint distance) {
int offsetY = !distance ? 8 : 0;
byte color = !distance ? 0 : _edgeColor;
if (distance < 5) {
drawWall(distance);
drawLine(ARRAY_X[distance + 1] + 16, 151 - ARRAY_Y[distance] - offsetY,
ARRAY_X[distance + 1] + 16, ARRAY_Y[distance + 1] + 8, _edgeColor);
drawLineTo(303 - ARRAY_X[distance + 1], ARRAY_Y[distance + 1] + 8, _edgeColor);
drawLineTo(303 - ARRAY_X[distance + 1], 151 - ARRAY_Y[distance] - offsetY, _edgeColor);
drawLineTo(ARRAY_X[distance + 1] + 16, 151 - ARRAY_Y[distance] - offsetY, color);
}
}
void DungeonSurface::drawLeftEdge(uint distance) {
if (distance <= 5) {
vLine(ARRAY_X[distance] + 16, ARRAY_Y[distance] + 8, 151 - ARRAY_Y[distance], _edgeColor);
}
}
void DungeonSurface::drawRightEdge(uint distance) {
if (distance <= 5) {
vLine(303 - ARRAY_X[distance], ARRAY_Y[distance] + 8, 151 - ARRAY_Y[distance], _edgeColor);
}
}
void DungeonSurface::drawWidget(uint widgetId, uint distance, byte color) {
_widgetFn(*this, widgetId, distance, color);
}
void DungeonSurface::drawLadderDownFaceOn(uint distance) {
if (distance <= 5) {
drawWidget(27, distance, _edgeColor);
drawWidget(28, distance, _edgeColor);
}
}
void DungeonSurface::drawLadderDownSideOn(uint distance) {
if (distance <= 5) {
drawWidget(27, distance, _edgeColor);
drawWidget(29, distance, _edgeColor);
}
}
void DungeonSurface::drawLadderUpFaceOn(uint distance) {
if (distance <= 5) {
drawWidget(26, distance, _edgeColor);
drawWidget(28, distance, _edgeColor);
}
}
void DungeonSurface::drawLadderUpSideOn(uint distance) {
if (distance <= 5) {
drawWidget(26, distance, _edgeColor);
drawWidget(29, distance, _edgeColor);
}
}
void DungeonSurface::drawLeftDoor(uint distance) {
if (distance <= 5) {
drawLeftWall(distance);
Point p1(ARRAY_X[distance], ARRAY_Y[distance]),
p2(ARRAY_X[distance - 1], ARRAY_Y[distance - 1]);
Point diff = p1 - p2;
diff.x /= 9;
diff.y /= 5;
drawLine(p2.x + diff.x * 2 + 16, 151 - diff.y - p2.y - 1, p2.x + diff.x * 2 + 16,
p1.y + 8 - diff.y, _edgeColor);
drawLineTo(p2.x + diff.x * 6 + 16, p1.y + diff.y + 8, _edgeColor);
drawLineTo(p2.x + diff.x * 6 + 16, 151 - p1.y + diff.y * 2 - (distance == 1 ? 2 : 0), _edgeColor);
}
}
void DungeonSurface::drawLeftWall(uint distance) {
if (distance <= 5) {
Point p1(ARRAY_X[distance], ARRAY_Y[distance]),
p2(ARRAY_X[distance - 1], ARRAY_Y[distance - 1]);
drawLine(p2.x + 16, p2.y + 8, p1.x + 16, p1.y + 8, _edgeColor);
drawLine(p2.x + 16, 151 - p2.y, p1.x + 16, 151 - p1.y, _edgeColor);
}
}
void DungeonSurface::drawLeftBlank(uint distance) {
if (distance <= 5) {
Point p1(ARRAY_X[distance], ARRAY_Y[distance]),
p2(ARRAY_X[distance - 1], ARRAY_Y[distance - 1]);
drawLine(p2.x + 16, p1.y + 8, p1.x + 16, p1.y + 8, _edgeColor);
drawLine(p2.x + 16, 151 - p1.y, p1.x + 16, 151 - p1.y, _edgeColor);
}
}
void DungeonSurface::drawRightDoor(uint distance) {
if (distance <= 5) {
drawRightWall(distance);
Point p1(ARRAY_X[distance], ARRAY_Y[distance]),
p2(ARRAY_X[distance - 1], ARRAY_Y[distance - 1]);
Point diff = p1 - p2;
diff.x /= 9;
diff.y /= 5;
drawLine(303 - (p2.x + diff.x * 2), 151 - diff.y - p2.y - 1, 303 - (p2.x + diff.x * 2),
p1.y + 8 - diff.y, _edgeColor);
drawLineTo(303 - (diff.x * 6 + p2.x), p1.y + 8 + diff.y, _edgeColor);
drawLineTo(303 - (diff.x * 6 + p2.x), 151 - p1.y + diff.y * 2 - (distance == 1 ? 2 : 0), _edgeColor);
}
}
void DungeonSurface::drawRightWall(uint distance) {
if (distance <= 5) {
Point p1(ARRAY_X[distance], ARRAY_Y[distance]),
p2(ARRAY_X[distance - 1], ARRAY_Y[distance - 1]);
drawLine(303 - p2.x, p2.y + 8, 303 - p1.x, p1.y + 8, _edgeColor);
drawLine(303 - p2.x, 151 - p2.y, 303 - p1.x, 151 - p1.y, _edgeColor);
}
}
void DungeonSurface::drawRightBlank(uint distance) {
if (distance <= 5) {
Point p1(ARRAY_X[distance], ARRAY_Y[distance]),
p2(ARRAY_X[distance - 1], ARRAY_Y[distance - 1]);
drawLine(303 - p2.x, p1.y + 8, 303 - p1.x, p1.y + 8, _edgeColor);
drawLine(303 - p2.x, 151 - p1.y, 303 - p1.x, 151 - p1.y, _edgeColor);
}
}
void DungeonSurface::drawBeams(uint distance) {
if (distance <= 5) {
// Figure out the Y difference between each beam
const int Y_START = ARRAY_Y[distance] + 8;
const int Y_END = 151 - ARRAY_Y[distance];
const int HEIGHT = (Y_END - Y_START) / 4;
for (int beamNum = 0; beamNum < 4; ++beamNum) {
const int YP = Y_START + HEIGHT * beamNum + (distance / 2);
drawLine(ARRAY_X[distance] + 16, YP, 303 - ARRAY_X[distance], YP, _highlightColor);
}
}
}
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,174 @@
/* 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 ULTIMA_SHARED_GFX_DUNGEON_H
#define ULTIMA_SHARED_GFX_DUNGEON_H
#include "ultima/shared/gfx/visual_surface.h"
namespace Ultima {
namespace Shared {
typedef void(*DrawWidgetFn)(Graphics::ManagedSurface &s, uint widgetId, uint distance, byte color);
class Game;
/**
* Acts as a handy container for the drawing methods for rendering the dungeon view
*/
class DungeonSurface : public Gfx::VisualSurface {
private:
Point _penPos;
byte _edgeColor;
byte _highlightColor;
byte _widgetColor;
DrawWidgetFn _widgetFn;
public:
/**
* Constructor
*/
DungeonSurface(const Graphics::ManagedSurface &src, const Rect &bounds, Game *game, DrawWidgetFn widgetFn);
/**
* Draw a line
*/
void drawLine(int x0, int y0, int x1, int y1, uint32 color) {
Gfx::VisualSurface::drawLine(x0 - 8, y0 - 8, x1 - 8, y1 - 8, color);
_penPos = Point(x1, y1);
}
/**
* Draw a line from a prior line ending point to a new destination pos
*/
void drawLineTo(int x, int y, uint32 color) {
Gfx::VisualSurface::drawLine(_penPos.x - 8, _penPos.y - 8, x - 8, y - 8, color);
_penPos = Point(x, y);
}
/**
* Draw a horizontal line.
*/
void hLine(int x, int y, int x2, uint32 color) {
Gfx::VisualSurface::hLine(x - 8, y - 8, x2 - 8, color);
_penPos = Point(x2, y);
}
/**
* Draw a vertical line.
*/
void vLine(int x, int y, int y2, uint32 color) {
Gfx::VisualSurface::vLine(x - 8, y - 8, y2 - 8, color);
_penPos = Point(x, y2);
}
/**
* Draw a frame around a specified rect.
*/
void frameRect(const Common::Rect &r, uint32 color) {
Gfx::VisualSurface::frameRect(Rect(r.left - 8, r.top - 8, r.right - 8, r.bottom - 8), color);
}
/**
* Draws a wall
*/
void drawWall(uint distance);
/**
* Draws a doorway directly in front of the player
*/
void drawDoorway(uint distance);
/**
* Draws a vertical line forming the edge of cells to the left of the player
*/
void drawLeftEdge(uint distance);
/**
* Draws a vertical line forming the edge of cells to the right of the player
*/
void drawRightEdge(uint distance);
/**
* Draws a monster or item at a given distance from the player
*/
void drawWidget(uint widgetId, uint distance, byte color);
/**
* Draw a ladder down face on
*/
void drawLadderDownFaceOn(uint distance);
/**
* Draw a ladder down side on
*/
void drawLadderDownSideOn(uint distance);
/**
* Draw a ladder down face on
*/
void drawLadderUpFaceOn(uint distance);
/**
* Draw a ladder down side on
*/
void drawLadderUpSideOn(uint distance);
/**
* Draw beams
*/
void drawBeams(uint distance);
/**
* Draws a door on the left hand side
*/
void drawLeftDoor(uint distance);
/**
* Draws a wall on the left-hand side
*/
void drawLeftWall(uint distance);
/**
* Draws the partial wall visible at the back of a corridor leading to the left
*/
void drawLeftBlank(uint distance);
/**
* Draws a door on the right hand side
*/
void drawRightDoor(uint distance);
/**
* Draws a wall on the right-hand side
*/
void drawRightWall(uint distance);
/**
* Draws the partial wall visible at the back of a corridor leading to the right
*/
void drawRightBlank(uint distance);
};
} // End of namespace Shared
} // End of namespace Ultima
#endif

View 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/shared/gfx/font.h"
#include "graphics/managed_surface.h"
namespace Ultima {
namespace Shared {
namespace Gfx {
Font::Font(const byte *data, size_t startingChar, size_t charCount) :
_data(data), _startingChar(startingChar), _endingChar(startingChar + charCount - 1) {}
int Font::writeString(Graphics::ManagedSurface &surface, const Common::String &msg, Point &pt,
byte color, byte bgColor) {
int total = 0;
int xs = pt.x;
for (const char *msgP = msg.c_str(); *msgP; ++msgP, total += 8) {
if (*msgP == '\n') {
// Move to next line
pt.x = xs;
pt.y += lineHeight();
} else {
// Write out character
writeChar(surface, (unsigned char)*msgP, pt, color, bgColor);
}
}
return total;
}
void Font::writeChar(Graphics::ManagedSurface &surface, unsigned char c, Point &pt,
byte color, byte bgColor) {
assert(c >= _startingChar && c <= _endingChar);
const byte *charP = _data + (c - _startingChar) * 8;
Graphics::Surface s = surface.getSubArea(Common::Rect(pt.x, pt.y, pt.x + 8, pt.y + 8));
for (int y = 0; y < 8; ++y) {
byte *lineP = (byte *)s.getBasePtr(0, y);
byte lineData = charP[y];
for (int x = 0; x < 8; ++x, lineData <<= 1, ++lineP) {
*lineP = (lineData & 0x80) ? color : bgColor;
}
}
pt.x += charWidth(c);
}
uint Font::charWidth(char c) const {
return 8;
}
uint Font::lineHeight() const {
return 8;
}
uint Font::stringWidth(const Common::String &msg) const {
return msg.size() * 8;
}
} // End of namespace Gfx
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,73 @@
/* 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 ULTIMA_SHARED_GFX_FONT_H
#define ULTIMA_SHARED_GFX_FONT_H
#include "common/array.h"
#include "common/stream.h"
#include "graphics/managed_surface.h"
#include "ultima/shared/core/rect.h"
namespace Ultima {
namespace Shared {
namespace Gfx {
class Font {
private:
const byte *_data;
size_t _startingChar, _endingChar;
public:
Font(const byte *data, size_t startingChar = 0, size_t charCount = 256);
/**
* Write out a string
*/
int writeString(Graphics::ManagedSurface &surface, const Common::String &msg,
Point &pt, byte color, byte bgColor = 0);
/**
* Draw a character
*/
void writeChar(Graphics::ManagedSurface &surface, unsigned char c, Point &pt,
byte color, byte bgColor = 0);
/**
* Return the width of a character
*/
uint charWidth(char c) const;
/**
* Return the width of a string
*/
uint stringWidth(const Common::String &msg) const;
/**
* Returns the height of the font
*/
uint lineHeight() const;
};
} // End of namespace Gfx
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,156 @@
/* 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/shared/gfx/info.h"
#include "ultima/shared/early/game.h"
#include "ultima/shared/gfx/text_cursor.h"
#include "ultima/shared/core/str.h"
namespace Ultima {
namespace Shared {
#define PROMPT_CHAR '\x1'
#define SUGGESTED_CR '\r'
BEGIN_MESSAGE_MAP(Info, Shared::Gfx::VisualItem)
ON_MESSAGE(InfoMsg)
ON_MESSAGE(InfoGetCommandKeypress)
ON_MESSAGE(InfoGetKeypress)
ON_MESSAGE(InfoGetInput)
ON_MESSAGE(KeypressMsg)
END_MESSAGE_MAP()
Info::Info(TreeItem *parent, const Rect &bounds) : Gfx::VisualItem("Info", bounds, parent),
_commandRespondTo(nullptr) {
_characterInput = new Gfx::CharacterInput(getGame());
_textInput = new Gfx::TextInput(getGame());
}
Info::~Info() {
delete _characterInput;
delete _textInput;
}
bool Info::InfoMsg(CInfoMsg *msg) {
// Iterate through text, dealing with lines one at a time
StringArray lines = String(msg->_text).split("\r\n");
if (!_lines.empty() && msg->_replaceLine)
_lines.back() = _lines.back().firstChar();
for (uint idx = 0; idx < lines.size(); ++idx) {
if (_lines.empty() || idx > 0)
_lines.push_back(" ");
_lines.back() += lines[idx];
}
// Add newline if necessary
if (msg->_newLine)
_lines.push_back(" ");
setDirty();
// Adding any text hides any visible cursor
_commandRespondTo = nullptr;
Gfx::TextCursor *textCursor = getGame()->_textCursor;
textCursor->setVisible(false);
return true;
}
bool Info::InfoGetCommandKeypress(CInfoGetCommandKeypress *msg) {
if (_lines.empty() || _lines.back() != " ")
_lines.push_back("");
_lines.back() = PROMPT_CHAR;
Gfx::TextCursor *textCursor = getGame()->_textCursor;
textCursor->setVisible(true);
textCursor->setPosition(Point(8, _bounds.bottom - 8));
_commandRespondTo = msg->_responder;
return true;
}
bool Info::InfoGetKeypress(CInfoGetKeypress *msg) {
Game *game = getGame();
Point pt(_bounds.left + _lines.back().size() * 8, _bounds.bottom - 8);
_characterInput->show(pt, game->_textColor, msg->_responder);
return true;
}
bool Info::InfoGetInput(CInfoGetInput *msg) {
Game *game = getGame();
Point pt(_bounds.left + _lines.back().size() * 8, _bounds.bottom - 8);
_textInput->show(pt, msg->_isNumeric, msg->_maxCharacters, game->_textColor, msg->_responder);
return true;
}
bool Info::KeypressMsg(CKeypressMsg *msg) {
// If waiting for a command, dispatch the key to the respond, and hide the cursor
if (_commandRespondTo) {
TreeItem *target = _commandRespondTo;
_commandRespondTo = nullptr;
getGame()->_textCursor->setVisible(false);
CCharacterInputMsg cMsg(msg->_keyState);
cMsg.execute(target);
return true;
}
return true;
}
void Info::draw() {
// Clear the background
Gfx::VisualSurface s = getSurface();
s.clear();
// Get the number og lines to display
uint lineHeight = s.fontHeight();
uint numLines = (s.h + lineHeight - 1) / lineHeight;
// Discard any stored lines beyond the top of the display
while (_lines.size() > numLines)
_lines.remove_at(0);
// Display the lines
int x = 0, y = s.h - _lines.size() * lineHeight;
for (uint idx = 0; idx < _lines.size(); ++idx, x = 0, y += lineHeight) {
// Handle drawing the prompt character at the start of lines if necessary
Common::String line = _lines[idx];
if (!line.empty() && line[0] == PROMPT_CHAR) {
drawPrompt(s, Point(0, y));
x = 8;
line.deleteChar(0);
}
// Write the remainder of the line
s.writeString(line, Point(x, y));
}
_isDirty = false;
}
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,80 @@
/* 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 ULTIMA_SHARED_GFX_INFO_H
#define ULTIMA_SHARED_GFX_INFO_H
#include "ultima/shared/gfx/visual_item.h"
#include "ultima/shared/gfx/text_input.h"
#include "ultima/shared/gfx/character_input.h"
#include "common/str-array.h"
namespace Ultima {
namespace Shared {
using Shared::CInfoMsg;
using Shared::CInfoGetCommandKeypress;
using Shared::CInfoGetInput;
using Shared::CKeypressMsg;
/**
* Textual info area, showing what commands area done, and any responses to them
*/
class Info : public Gfx::VisualItem {
DECLARE_MESSAGE_MAP;
bool InfoMsg(CInfoMsg *msg);
bool InfoGetCommandKeypress(CInfoGetCommandKeypress *msg);
bool InfoGetKeypress(CInfoGetKeypress *msg);
bool InfoGetInput(CInfoGetInput *msg);
bool KeypressMsg(CKeypressMsg *msg);
private:
Common::StringArray _lines;
Gfx::TextInput *_textInput;
Gfx::CharacterInput *_characterInput;
TreeItem *_commandRespondTo;
protected:
/**
* Draws a prompt character
*/
virtual void drawPrompt(Gfx::VisualSurface &surf, const Point &pt) = 0;
public:
CLASSDEF;
/**
* Constructor
*/
Info(TreeItem *parent, const Rect &bounds);
/**
* Destructor
*/
~Info() override;
/**
* Draw the contents
*/
void draw() override;
};
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,70 @@
/* 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/shared/gfx/popup.h"
#include "ultima/shared/early/game_base.h"
namespace Ultima {
namespace Shared {
namespace Gfx {
BEGIN_MESSAGE_MAP(Popup, VisualItem)
ON_MESSAGE(ShowMsg)
END_MESSAGE_MAP()
Popup::Popup(GameBase *game) : VisualItem(nullptr), _game(game), _respondTo(nullptr), _parentView(nullptr) {
game->addChild(this);
}
Popup::~Popup() {
detach();
}
void Popup::show(TreeItem *respondTo) {
// Save a copy of the view the popup is being shown on, and activate it
_parentView = _game->getView();
_respondTo = respondTo;
if (!_respondTo)
_respondTo = _parentView;
_game->setPopup(this);
setDirty();
}
void Popup::hide() {
CPopupHiddenMsg hiddenMsg(this);
hiddenMsg.execute(_respondTo, nullptr, 0);
// Reset back to the parent view
_game->setView(_parentView);
_parentView->setDirty();
}
bool Popup::ShowMsg(CShowMsg *msg) {
CPopupShownMsg shownMsg(this);
shownMsg.execute(_respondTo, nullptr, 0);
return true;
}
} // End of namespace Gfx
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,75 @@
/* 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 ULTIMA_SHARED_GFX_POPUP_H
#define ULTIMA_SHARED_GFX_POPUP_H
#include "ultima/shared/gfx/visual_item.h"
namespace Ultima {
namespace Shared {
class GameBase;
namespace Gfx {
/**
* Base class for graphic elements that "pop up" on top of existing views. This includes things like
* dialogs, text input, etc.
*/
class Popup : public VisualItem {
DECLARE_MESSAGE_MAP;
bool ShowMsg(CShowMsg *msg);
protected:
GameBase *_game;
VisualItem *_parentView;
TreeItem *_respondTo;
public:
CLASSDEF;
/**
* Constructor
*/
Popup(GameBase *game);
/**
* Destructor
*/
~Popup() override;
/**
* Show the popup
* @param respondTo Element to send any response to when the popup closes.
* If not provided, any response goes to the active view
*/
void show(TreeItem *respondTo = nullptr);
/**
* Hide the popup
*/
virtual void hide();
};
} // End of namespace Gfx
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,61 @@
/* 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 "engines/util.h"
#include "ultima/shared/gfx/screen.h"
namespace Ultima {
namespace Shared {
namespace Gfx {
Screen::Screen(): Graphics::Screen(320, 200), _cursor(nullptr), _drawCursor(false) {
initGraphics(320, 200);
}
void Screen::update() {
_drawCursor = false;
if (_cursor) {
// Check whether the area the cursor occupies will be being updated
Common::Rect cursorBounds = _cursor->getBounds();
for (const auto &r : _dirtyRects) {
if (r.intersects(cursorBounds)) {
addDirtyRect(cursorBounds);
_drawCursor = true;
break;
}
}
}
Graphics::Screen::update();
}
void Screen::updateScreen() {
if (_drawCursor)
_cursor->draw();
Graphics::Screen::updateScreen();
}
} // End of namespace Gfx
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,88 @@
/* 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 ULTIMA_SHARED_GFX_SCREEN_H
#define ULTIMA_SHARED_GFX_SCREEN_H
#include "common/list.h"
#include "ultima/shared/core/rect.h"
#include "graphics/screen.h"
#include "ultima/shared/gfx/font.h"
#include "ultima/shared/engine/messages.h"
namespace Ultima {
namespace Shared {
namespace Gfx {
/**
* Base class for an on-screen cursor. Currently used for text cursor display
*/
class Cursor {
public:
/**
* Destructor
*/
virtual ~Cursor() {}
/**
* Get the bounds of the cursor
*/
virtual Common::Rect getBounds() const = 0;
/**
* Draw the cursor
*/
virtual void draw() = 0;
};
class Screen: public Graphics::Screen {
private:
Cursor *_cursor;
bool _drawCursor;
public:
/**
* Constructor
*/
Screen();
/**
* Updates the screen by copying any affected areas to the system
*/
void update() override;
/**
* Updates the screen at the end of an update call
*/
void updateScreen() override;
/**
* Sets the currently active cursor
*/
void setCursor(Cursor *cursor) { _cursor = cursor; }
};
} // End of namespace Gfx
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,106 @@
/* 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/shared/gfx/sprites.h"
#include "ultima/shared/core/file.h"
namespace Ultima {
namespace Shared {
namespace Gfx {
Sprite::Sprite() {
}
Sprite::Sprite(const Sprite &src) {
_surface.copyFrom(src._surface);
_transSurface.copyFrom(src._transSurface);
}
Sprite::Sprite(const byte *src, uint bpp, uint16 w, uint16 h) {
_surface.create(w, h, Graphics::PixelFormat::createFormatCLUT8());
assert((w % bpp) == 0);
byte v = 0;
for (int y = 0; y < h; ++y) {
byte *destP = (byte *)_surface.getBasePtr(0, y);
for (int x = 0; x < w; ++x, v <<= bpp) {
if ((x % (8 / bpp)) == 0)
v = *src++;
*destP++ = (((uint)v << bpp) & 0xff00) >> 8;
}
}
}
Sprite &Sprite::operator=(const Sprite &src) {
_surface.copyFrom(src._surface);
_transSurface.copyFrom(src._transSurface);
return *this;
}
void Sprite::draw(Graphics::ManagedSurface &dest, const Common::Point &pt) {
// Get area to be drawn on
Graphics::Surface s = dest.getSubArea(Common::Rect(pt.x, pt.y, pt.x + _surface.w, pt.y + _surface.h));
// Draw the sprite
for (uint16 y = 0; y < _surface.h; ++y) {
const byte *srcP = (const byte *)_surface.getBasePtr(0, y);
const byte *transP = (const byte *)_transSurface.getBasePtr(0, y);
byte *destP = (byte *)s.getBasePtr(0, y);
for (uint16 x = 0; x < _surface.w; ++x, ++srcP, ++transP, ++destP) {
if (_transSurface.empty() || *transP)
*destP = *srcP;
}
}
}
/*-------------------------------------------------------------------*/
void Sprites::load(const Common::Path &name, uint bpp, uint16 w, uint16 h) {
_spriteSize = Point(w, h);
// Open the tiles for access
File f(name);
byte *buffer = new byte[w * h];
// Figure out how many tiles the file has
size_t bytesPerTile = (w / (8 / bpp)) * h;
size_t count = f.size() / bytesPerTile;
// Ensure there's enough capacity for the tileset
if (count > size())
_data.resize(count);
// Iterate through loading the tile data and creating sprites for them
for (size_t idx = 0; idx < count; ++idx) {
f.read(buffer, bytesPerTile);
_data[idx] = Sprite(buffer, bpp, w, h);
}
delete[] buffer;
}
} // End of namespace Gfx
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,138 @@
/* 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 ULTIMA_SPRITES_H
#define ULTIMA_SPRITES_H
#include "common/array.h"
#include "common/path.h"
#include "graphics/managed_surface.h"
#include "ultima/shared/core/rect.h"
namespace Ultima {
namespace Shared {
namespace Gfx {
class Sprite {
private:
Graphics::ManagedSurface _surface;
Graphics::ManagedSurface _transSurface;
public:
/**
* Constructor
*/
Sprite();
/**
* Constructor, copying from another sprite
*/
Sprite(const Sprite &src);
/**
* Constructor, loading a sprite from passed data
* @param src Source data
* @param bpp The bits per pixel for tiles in the file
* @param w Width of tiles
* @param h Height of files
*/
Sprite(const byte *src, uint bpp, uint16 w = 16, uint16 h = 16);
/**
* Copy assignment operator
*/
Sprite &operator=(const Sprite &src);
/**
* Draw a tile onto a passed surface
*/
void draw(Graphics::ManagedSurface &dest, const Common::Point &pt);
/**
* Return the width of the sprite
*/
uint16 w() const { return _surface.w; }
/**
* Return the height of the sprite
*/
uint16 h() const { return _surface.h; }
/**
* Get a reference to the sprite surface
*/
byte *getPixels() { return (byte *)_surface.getPixels(); }
/**
* Get a reference to a specified position within the sprite
*/
byte *getBasePtr(int16 x, int16 y) { return (byte *)_surface.getBasePtr(x, y); }
/**
* Get a reference to a specified position within the sprite
*/
const byte *getBasePtr(int16 x, int16 y) const { return (const byte *)_surface.getBasePtr(x, y); }
};
class Sprites {
protected:
Common::Array<Sprite> _data;
Point _spriteSize; // Size of individual sprites
protected:
/**
* Load a raw data file containing sprite pixels
* @param name Filename
* @param bpp The bits per pixel for tiles in the file
* @param w Width of tiles
* @param h Height of files
*/
void load(const Common::Path &name, uint bpp, uint16 w = 16, uint16 h = 16);
public:
/**
* Destructor
*/
virtual ~Sprites() {}
/**
* Return the default dimensions for tiles
*/
Point getSpriteSize() const { return _spriteSize; }
/**
* Return the size of the sprites list
*/
size_t size() const { return _data.size(); }
/**
* Returns true if the sprites list is empty
*/
bool empty() const { return size() == 0; }
/**
* Return a specific sprite
*/
virtual Sprite &operator[](uint idx) { return _data[idx]; }
};
} // End of namespace Gfx
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,35 @@
/* 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/shared/gfx/text_cursor.h"
#include "ultima/shared/early/ultima_early.h"
namespace Ultima {
namespace Shared {
namespace Gfx {
void TextCursor::markAsDirty() {
g_vm->_screen->getSubArea(_bounds);
}
} // End of namespace Gfx
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,95 @@
/* 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 ULTIMA_SHARED_GFX_TEXT_CURSOR_H
#define ULTIMA_SHARED_GFX_TEXT_CURSOR_H
#include "ultima/shared/core/rect.h"
#include "ultima/shared/gfx/screen.h"
namespace Ultima {
namespace Shared {
namespace Gfx {
/**
* Base class for text cursors, and is used by those games that don't have a visible cursor
*/
class TextCursor : public Cursor {
protected:
bool _visible;
Common::Rect _bounds;
protected:
/**
* Marks the area of the screen the cursor covers as dirty
*/
void markAsDirty();
public:
TextCursor() : _visible(false) {
}
~TextCursor() override {
}
/**
* Returns true if the cursor is visible
*/
bool isVisible() const {
return _visible;
}
/**
* Sets the visibility of the cursor
*/
virtual void setVisible(bool isVis) {
_visible = isVis;
markAsDirty();
}
/**
* Get the bounds of the cursor
*/
Common::Rect getBounds() const override { return _bounds; }
/**
* Returns the position of the cursor
*/
Point getPosition() const { return Point(_bounds.left, _bounds.top); }
/**
* Sets the position of the cursor
*/
void setPosition(const Point &pt) {
bool vis = _visible;
setVisible(false);
_bounds.moveTo(pt);
setVisible(vis);
}
/**
* Update the cursor
*/
virtual void update() = 0;
};
} // End of namespace Gfx
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,96 @@
/* 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/shared/gfx/text_input.h"
#include "ultima/shared/gfx/text_cursor.h"
#include "ultima/shared/early/game_base.h"
#include "ultima/shared/engine/messages.h"
namespace Ultima {
namespace Shared {
namespace Gfx {
BEGIN_MESSAGE_MAP(TextInput, Popup)
ON_MESSAGE(KeypressMsg)
END_MESSAGE_MAP()
void TextInput::show(const Point &pt, bool isNumeric, size_t maxCharacters, byte color, TreeItem *respondTo) {
Popup::show(respondTo);
_isNumeric = isNumeric;
_maxCharacters = maxCharacters;
_color = color;
_bounds = Rect(pt.x, pt.y, pt.x + 8 * (maxCharacters + 1), pt.y + 8);
_text = "";
_game->_textCursor->setPosition(Point(_bounds.left, _bounds.top));
_game->_textCursor->setVisible(true);
}
void TextInput::draw() {
Popup::draw();
VisualSurface s = getSurface();
// Ensure the cursor is at the right position
_game->_textCursor->setPosition(Point(_bounds.left + _text.size() * 8, _bounds.top));
// Display the text
Common::String text = _text;
while (text.size() < _maxCharacters)
text += ' ';
s.writeString(text, TextPoint(0, 0), _color);
}
bool TextInput::KeypressMsg(CKeypressMsg *msg) {
uint16 c = msg->_keyState.ascii;
//TreeItem *respondTo = _respondTo;
if (c >= ' ' && c <= 0x7f) {
// Printable character
if (_text.size() < _maxCharacters && (!_isNumeric || (c >= '0' && c <= '9'))) {
_text += msg->_keyState.ascii;
setDirty();
}
} else if (msg->_keyState.keycode == Common::KEYCODE_BACKSPACE || msg->_keyState.keycode == Common::KEYCODE_LEFT) {
if (!_text.empty()) {
_text.deleteLastChar();
setDirty();
}
} else if (msg->_keyState.keycode == Common::KEYCODE_RETURN || msg->_keyState.keycode == Common::KEYCODE_KP_ENTER) {
_game->_textCursor->setVisible(false);
hide();
CTextInputMsg inputMsg(_text, false);
inputMsg.execute(_respondTo);
} else if (msg->_keyState.keycode == Common::KEYCODE_ESCAPE) {
_game->_textCursor->setVisible(false);
hide();
CTextInputMsg inputMsg("", true);
inputMsg.execute(_respondTo);
}
return true;
}
} // End of namespace Gfx
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,68 @@
/* 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 ULTIMA_GFX_TEXT_INPUT_H
#define ULTIMA_GFX_TEXT_INPUT_H
#include "ultima/shared/gfx/popup.h"
namespace Ultima {
namespace Shared {
namespace Gfx {
/**
* Text input control
*/
class TextInput : public Popup {
DECLARE_MESSAGE_MAP;
bool KeypressMsg(CKeypressMsg *msg);
private:
bool _isNumeric;
size_t _maxCharacters;
Common::String _text;
byte _color;
public:
CLASSDEF;
TextInput(GameBase *game) : Popup(game), _isNumeric(false), _maxCharacters(0), _color(0) {}
/**
* Draws the visual item on the screen
*/
void draw() override;
/**
* Show the text input
* @param pt Position of the input
* @param maxCharacters Maximum length of input
* @param color Text color
* @param respondTo Element to send any response to when the popup closes.
* If not provided, any response goes to the active view
* @remarks Generates a TextInputMsg message with the text when Enter or escape is pressed
*/
void show(const Point &pt, bool isNumeric, size_t maxCharacters, byte color,
TreeItem *respondTo = nullptr);
};
} // End of namespace Gfx
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,267 @@
/* 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/shared/gfx/viewport_dungeon.h"
#include "ultima/shared/maps/dungeon_widget.h"
#include "ultima/shared/maps/dungeon_creature.h"
#include "ultima/shared/maps/map_widget.h"
#include "ultima/shared/maps/map.h"
#include "ultima/shared/early/game.h"
namespace Ultima {
namespace Shared {
EMPTY_MESSAGE_MAP(ViewportDungeon, Shared::Gfx::VisualItem);
void ViewportDungeon::draw() {
// Get a surface reference and clear it's contents
DungeonSurface s = getSurface();
s.clear();
// Get the position delta for the facing direction, and the cells to the left and right of that
Maps::Map *map = getGame()->getMap();
Point delta = map->getDirectionDelta();
Point leftDelta, rightDelta;
switch (map->getDirection()) {
case Maps::DIR_LEFT:
leftDelta.y = 1;
rightDelta.y = -1;
break;
case Maps::DIR_RIGHT:
leftDelta.y = -1;
rightDelta.y = 1;
break;
case Maps::DIR_UP:
leftDelta.x = -1;
rightDelta.x = 1;
break;
case Maps::DIR_DOWN:
leftDelta.x = 1;
rightDelta.x = -1;
break;
default:
break;
}
Maps::MapTile tile, deltaTile, leftTile, rightTile, backTile;
Point currentPos = map->getPosition();
map->getTileAt(currentPos, &tile);
map->getTileAt(currentPos + delta, &deltaTile);
bool isDoor = tile.isDoor();
bool isWall = tile.isWallOrSecretDoor();
int distance = distanceToOccupiedCell(delta);
// If stuck in a wall, draw it and exit
if (isWall) {
s.drawWall(0);
return;
}
Point backDelta(delta.x * distance, delta.y * distance),
currDelta(delta.x * distance, delta.y * distance);
if (isDoor && deltaTile.isWallOrDoorway()) {
s.drawWall(0);
} else {
if (isDoor)
s.drawDoorway(0);
// These are essentially boolean flags with an extra 'initial' state
byte endingLeft = 100, endingRight = 100;
byte leftFlag = 100, rightFlag = 100;
byte priorLeftFlag = 100, priorRightFlag = 100;
for (int index = distance; index; --index) {
currDelta -= delta;
Point pt = currentPos + currDelta;
if (!isDoor || index > 1) {
map->getTileAt(pt + leftDelta, &leftTile);
map->getTileAt(pt + rightDelta, &rightTile);
leftFlag = leftTile.isSolid();
rightFlag = rightTile.isSolid();
if (index == distance) {
endingLeft = leftFlag;
endingRight = rightFlag;
} else {
if (leftFlag != priorLeftFlag)
s.drawLeftEdge(index);
if (rightFlag != priorRightFlag)
s.drawRightEdge(index);
}
drawLeftCell(index, leftTile);
drawRightCell(index, rightTile);
}
drawCell(index, pt + delta);
priorLeftFlag = leftFlag;
priorRightFlag = rightFlag;
}
if (!isDoor)
drawCell(0, currentPos);
map->getTileAt(currentPos + delta, &backTile);
if (distance < 5 && isMonsterBlocking(currentPos + backDelta) && backTile.isDoor()) {
map->getTileAt(currentPos + leftDelta, &leftTile);
map->getTileAt(currentPos + rightDelta, &rightTile);
drawLeftCell(distance + 1, leftTile);
drawRightCell(distance + 1, rightTile);
map->getTileAt(currentPos + leftDelta, &leftTile);
if (!leftTile.isSolid())
s.drawLeftEdge(distance);
if (!rightTile.isSolid())
s.drawRightEdge(distance);
} else {
if (endingLeft)
s.drawLeftEdge(distance);
if (endingRight)
s.drawRightEdge(distance);
}
}
Maps::DungeonWidget *widget = dynamic_cast<Maps::DungeonWidget *>(tile._widget);
if (isDoor && widget) {
widget->draw(s, 0);
}
}
uint ViewportDungeon::distanceToOccupiedCell(const Point &delta) {
Point d = delta;
uint distance;
for (distance = 1; !isCellOccupied(d); ++distance, d.x += delta.x, d.y += delta.y) {}
return MIN(distance, (uint)5);
}
bool ViewportDungeon::isCellOccupied(const Point &delta) {
Maps::Map *map = getGame()->getMap();
Point pt = map->getPosition() + delta;
Maps::MapTile tile;
map->getTileAt(pt, &tile);
if (tile.isWallOrDoorway())
return true;
return isMonsterBlocking(pt);
}
bool ViewportDungeon::isMonsterBlocking(const Point &pt) {
Maps::MapTile tile;
getGame()->getMap()->getTileAt(pt, &tile);
Maps::DungeonCreature *monster = dynamic_cast<Maps::DungeonCreature *>(tile._widget);
return monster != nullptr && monster->isBlockingView();
}
void ViewportDungeon::drawCell(uint distance, const Point &pt) {
Game *game = getGame();
DungeonSurface s = getSurface();
Maps::Map *map = game->getMap();
Maps::MapTile tile;
map->getTileAt(pt, &tile);
// TODO: This currently contains dungeon cell types specific to Ultima 1
Maps::DungeonCreature *monster = dynamic_cast<Maps::DungeonCreature *>(tile._widget);
if (monster) {
// Draw a monster
if (tile.isWallOrDoorway())
s.drawWall(distance);
if (tile._tileId == 7)
// Ladder down
s.drawWidget(27, distance + 1, game->_edgeColor);
if (tile._tileId == 6)
// Ladder up
s.drawWidget(26, distance + 1, game->_edgeColor);
monster->draw(s, distance);
} else {
switch (tile._tileId) {
case 1:
case 2:
// Wall or secret door
s.drawWall(distance);
break;
case 3:
// Doorway
s.drawDoorway(distance);
break;
case 6:
// Ladder down
if (map->getDirection() == Maps::DIR_UP || map->getDirection() == Maps::DIR_DOWN) {
s.drawLadderDownFaceOn(distance + 1);
} else {
s.drawLadderDownSideOn(distance + 1);
}
break;
case 7:
// Ladder up
if (map->getDirection() == Maps::DIR_UP || map->getDirection() == Maps::DIR_DOWN) {
s.drawLadderUpFaceOn(distance + 1);
} else {
s.drawLadderUpSideOn(distance + 1);
}
break;
case 8:
// Beams
s.drawBeams(distance);
break;
default:
break;
}
}
// Draw any item at that distance
Maps::DungeonWidget *widget = dynamic_cast<Maps::DungeonWidget *>(tile._widget);
if (widget)
widget->draw(s, distance);
}
void ViewportDungeon::drawLeftCell(uint distance, const Maps::MapTile &tile) {
DungeonSurface s = getSurface();
if (tile.isDoor())
s.drawLeftDoor(distance);
else if (tile.isWallOrSecretDoor())
s.drawLeftWall(distance);
else
s.drawLeftBlank(distance);
}
void ViewportDungeon::drawRightCell(uint distance, const Maps::MapTile &tile) {
DungeonSurface s = getSurface();
if (tile.isDoor())
s.drawRightDoor(distance);
else if (tile.isWallOrSecretDoor())
s.drawRightWall(distance);
else
s.drawRightBlank(distance);
}
} // End of namespace Shared
} // End of namespace Ultima

View 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 ULTIMA_SHARED_GFX_VIEWPORT_DUNGEON_H
#define ULTIMA_SHARED_GFX_VIEWPORT_DUNGEON_H
#include "ultima/shared/gfx/visual_item.h"
#include "ultima/shared/gfx/dungeon_surface.h"
#include "ultima/shared/maps/map_tile.h"
namespace Ultima {
namespace Shared {
class ViewportDungeon : public Gfx::VisualItem {
DECLARE_MESSAGE_MAP;
private:
/**
* Returns the distance to an occupied cell, if any
*/
uint distanceToOccupiedCell(const Point &delta);
/**
* Returns if a cell at a given delta to the player is occupied
*/
bool isCellOccupied(const Point &delta);
/**
* Returns true if a monster is at a given position, and it has the blocking attribute
*/
bool isMonsterBlocking(const Point &pt);
/**
* Draw a monster or, failing that, the given tile at a given cell and distance
*/
void drawCell(uint distance, const Point &pt);
/**
* Draw a cell to the left
*/
void drawLeftCell(uint distance, const Maps::MapTile &tile);
/**
* Draw a cell to the left
*/
void drawRightCell(uint distance, const Maps::MapTile &tile);
protected:
/**
* Returns the surface for rendering the dungeon
*/
virtual DungeonSurface getSurface() = 0;
public:
CLASSDEF;
ViewportDungeon(TreeItem *parent) : Gfx::VisualItem("ViewportDungeon", Rect(8, 8, 312, 152), parent) {}
~ViewportDungeon() override {}
/**
* Draws the dungeon
*/
void draw() override;
};
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,62 @@
/* 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/shared/gfx/viewport_map.h"
#include "ultima/shared/maps/map.h"
#include "ultima/shared/early/game.h"
namespace Ultima {
namespace Shared {
EMPTY_MESSAGE_MAP(ViewportMap, Gfx::VisualItem);
void ViewportMap::draw() {
// Get a surface reference and clear it's contents
Gfx::VisualSurface s = getSurface();
s.clear();
// Figure out how many tiles can fit into the display
const Point spriteSize = _sprites->getSpriteSize();
const Point visibleTiles(_bounds.width() / spriteSize.x, _bounds.height() / spriteSize.y);
// Get a reference to the map and get the starting tile position
Maps::Map *map = getGame()->getMap();
const Point topLeft = map->getViewportPosition(visibleTiles);
// Iterate through drawing the map
Maps::MapTile tile;
for (int y = 0; y < visibleTiles.y; ++y) {
for (int x = 0; x < visibleTiles.x; ++x) {
Point drawPos(x * spriteSize.x, y * spriteSize.y);
// Get the next tile to display and draw it
map->getTileAt(Point(topLeft.x + x, topLeft.y + y), &tile);
(*_sprites)[tile._tileDisplayNum].draw(s, drawPos);
// Draw any widgets on the tile
for (uint idx = 0; idx < tile._widgets.size(); ++idx)
(*_sprites)[tile._widgets[idx]->getTileNum()].draw(s, drawPos);
}
}
}
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,57 @@
/* 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 ULTIMA_SHARED_GFX_VIEWPORT_MAP_H
#define ULTIMA_SHARED_GFX_VIEWPORT_MAP_H
#include "ultima/shared/gfx/visual_item.h"
#include "ultima/shared/gfx/sprites.h"
namespace Ultima {
namespace Shared {
class ViewportMap : public Gfx::VisualItem {
DECLARE_MESSAGE_MAP;
protected:
Gfx::Sprites *_sprites;
public:
CLASSDEF;
/**
* Constructor
*/
ViewportMap(TreeItem *parent) : Gfx::VisualItem("ViewportMap", Rect(8, 8, 312, 152), parent), _sprites(nullptr) {}
/**
* Destructor
*/
~ViewportMap() override {}
/**
* Draws the map
*/
void draw() override;
};
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,140 @@
/* 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/shared/gfx/visual_container.h"
namespace Ultima {
namespace Shared {
namespace Gfx {
BEGIN_MESSAGE_MAP(VisualContainer, VisualItem)
ON_MESSAGE(MouseButtonDownMsg)
ON_MESSAGE(MouseButtonUpMsg)
ON_MESSAGE(MouseMoveMsg)
ON_MESSAGE(MouseDoubleClickMsg)
ON_MESSAGE(MouseWheelMsg)
END_MESSAGE_MAP()
bool VisualContainer::MouseButtonDownMsg(CMouseButtonDownMsg *msg) {
if (msg->_buttons & MB_LEFT) {
_mouseFocusItem = handleMouseMsg(msg);
return _mouseFocusItem != nullptr;
}
return false;
}
bool VisualContainer::MouseButtonUpMsg(CMouseButtonUpMsg *msg) {
if (msg->_buttons & MB_LEFT) {
bool result = handleMouseMsg(msg) != nullptr;
_mouseFocusItem = nullptr;
return result;
}
return false;
}
bool VisualContainer::MouseDoubleClickMsg(CMouseDoubleClickMsg *msg) {
if (msg->_buttons & MB_LEFT)
return handleMouseMsg(msg);
return false;
}
bool VisualContainer::MouseWheelMsg(CMouseWheelMsg *msg) {
return handleMouseMsg(msg);
}
bool VisualContainer::MouseMoveMsg(CMouseMoveMsg *msg) {
if (msg->_buttons & MB_LEFT)
return handleMouseMsg(msg);
return false;
}
bool VisualContainer::MouseDragMsg(CMouseDragMsg *msg) {
return handleMouseMsg(msg);
}
VisualItem *VisualContainer::handleMouseMsg(CMouseMsg *msg) {
if (_mouseFocusItem) {
// An item currently has focus, so pass all events directly to
// it, irrespective of whether the mouse is still in it or not
msg->execute(_mouseFocusItem);
return _mouseFocusItem;
} else {
// Iterate through each child and pass the message to the first
// immediate child the mouse position falls within
for (TreeItem *child = getFirstChild(); child; child = child->getNextSibling()) {
VisualItem *item = dynamic_cast<VisualItem *>(child);
if (item && item->getBounds().contains(msg->_mousePos)) {
if (msg->execute(item))
return item;
}
}
return nullptr;
}
}
void VisualContainer::draw() {
// If the overall container is dirty, clear it
if (_isDirty)
getSurface().clear();
// Iterate through each child and draw any dirty visual items
for (TreeItem *child = getFirstChild(); child; child = child->getNextSibling()) {
VisualItem *item = dynamic_cast<VisualItem *>(child);
if (item && item->isDirty())
item->draw();
}
_isDirty = false;
}
void VisualContainer::setDirty(bool dirty) {
for (TreeItem *child = getFirstChild(); child; child = child->getNextSibling()) {
VisualItem *item = dynamic_cast<VisualItem *>(child);
if (item)
item->setDirty(dirty);
}
VisualItem::setDirty(dirty);
}
bool VisualContainer::isDirty() const {
if (_isDirty)
return true;
for (TreeItem *child = getFirstChild(); child; child = child->getNextSibling()) {
VisualItem *item = dynamic_cast<VisualItem *>(child);
if (item && item->isDirty())
return true;
}
return false;
}
} // End of namespace Gfx
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,78 @@
/* 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 ULTIMA_SHARED_GFX_VISUAL_CONTAINER_H
#define ULTIMA_SHARED_GFX_VISUAL_CONTAINER_H
#include "ultima/shared/gfx/visual_item.h"
#include "ultima/shared/core/message_target.h"
namespace Ultima {
namespace Shared {
namespace Gfx {
class VisualContainer : public VisualItem {
DECLARE_MESSAGE_MAP;
bool MouseButtonDownMsg(CMouseButtonDownMsg *msg);
bool MouseButtonUpMsg(CMouseButtonUpMsg *msg);
bool MouseMoveMsg(CMouseMoveMsg *msg);
bool MouseDoubleClickMsg(CMouseDoubleClickMsg *msg);
bool MouseWheelMsg(CMouseWheelMsg *msg);
bool MouseDragMsg(CMouseDragMsg *msg);
private:
VisualItem *_mouseFocusItem;
private:
/**
* Called to handle mouse messagaes on the view
*/
VisualItem *handleMouseMsg(CMouseMsg *msg);
public:
CLASSDEF;
VisualContainer(TreeItem *parent = nullptr) : VisualItem(parent), _mouseFocusItem(nullptr) {}
VisualContainer(const Rect &r, TreeItem *parent = nullptr) :
VisualItem(r, parent), _mouseFocusItem(nullptr) {}
VisualContainer(const Common::String &name, TreeItem *parent = nullptr) :
VisualItem(name, parent), _mouseFocusItem(nullptr) {}
VisualContainer(const Common::String &name, const Rect &r, TreeItem *parent = nullptr) :
VisualItem(name, r, parent), _mouseFocusItem(nullptr) {}
~VisualContainer() override {}
/**
* Draws the container by iterating through each child and letting it draw
*/
void draw() override;
/**
* Flags the item as being changed, requiring a redraw
*/
void setDirty(bool dirty = true) override;
/**
* Returns true if the item is dirty, requiring a redraw
*/
bool isDirty() const override;
};
} // End of namespace Gfx
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,90 @@
/* 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/shared/gfx/visual_item.h"
#include "ultima/shared/early/ultima_early.h"
#include "ultima/shared/early/game.h"
namespace Ultima {
namespace Shared {
namespace Gfx {
BEGIN_MESSAGE_MAP(VisualItem, NamedItem)
ON_MESSAGE(ShowMsg)
ON_MESSAGE(HideMsg)
END_MESSAGE_MAP()
void VisualItem::init(TreeItem *parent) {
_isDirty = true;
if (parent != nullptr)
addUnder(parent);
}
bool VisualItem::ShowMsg(CShowMsg *msg) {
// When a view is shown, mark it to be redrawn
_isDirty = true;
// Font *font = Font::getActiveFont();
// _fontDetails._fontNumber = font ? font->_fontNumber : 1;
return false;
}
bool VisualItem::HideMsg(CHideMsg *msg) {
// When view is hidden, mark it as not dirty
_isDirty = false;
return false;
}
VisualSurface VisualItem::getSurface() {
Graphics::ManagedSurface src(*g_vm->_screen, _bounds);
return VisualSurface(src, _bounds, getGame());
}
void VisualItem::setBounds(const Rect &r) {
_bounds = r;
setDirty();
}
void VisualItem::setPosition(const Point &pt) {
_bounds.moveTo(pt);
setDirty();
}
void VisualItem::setDirty(bool dirty) {
// Flag the item as dirty
_isDirty = dirty;
}
void VisualItem::setView(const Common::String &viewName) {
getGame()->setView(viewName);
}
void VisualItem::setPopup(Gfx::Popup *popup) {
getGame()->setPopup(popup);
}
void VisualItem::setView() {
getGame()->setView(this);
}
} // End of namespace Gfx
} // End of namespace Shaerd
} // End of namespace Ultima

View File

@@ -0,0 +1,128 @@
/* 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 ULTIMA_SHARED_GFX_VISUAL_ITEM_H
#define ULTIMA_SHARED_GFX_VISUAL_ITEM_H
#include "graphics/managed_surface.h"
#include "ultima/shared/core/named_item.h"
#include "ultima/shared/gfx/screen.h"
#include "ultima/shared/gfx/visual_surface.h"
namespace Ultima {
namespace Shared {
namespace Gfx {
class Popup;
/**
* Acts as the base class for all classes that have a visual representation on the screen
*/
class VisualItem : public NamedItem {
friend class VisualSurface;
DECLARE_MESSAGE_MAP;
bool ShowMsg(CShowMsg *msg);
bool HideMsg(CHideMsg *msg);
private:
/**
* Common initialization method used by the constructors
*/
void init(TreeItem *parent = nullptr);
protected:
Rect _bounds;
bool _isDirty;
public:
CLASSDEF;
VisualItem(TreeItem *parent = nullptr) { init(parent); }
VisualItem(const Rect &r, TreeItem *parent = nullptr) : _bounds(r) { init(parent); }
VisualItem(const Common::String &name, TreeItem *parent = nullptr) : NamedItem(name) { init(parent); }
VisualItem(const Common::String &name, const Rect &r, TreeItem *parent = nullptr) : NamedItem(name),
_bounds(r) { init(parent); }
~VisualItem() override {
}
/**
* Draws the visual item on the screen
*/
virtual void draw() {
_isDirty = false;
}
/**
* Gets a managed surface representing the portion of the screen defined by _bounds.
* This allows drawing to be done without worrying about offsets or clipping
*/
VisualSurface getSurface();
/**
* Gets the bounds for the item
*/
const Rect &getBounds() { return _bounds; }
/**
* Sets the bounds for the item
* @remarks Does not erase the item if it's already been drawn
*/
void setBounds(const Rect &r);
/**
* Set the position for the item
* @remarks Does not erase the item if it's already been drawn
*/
void setPosition(const Point &pt);
/**
* Flags the item as being changed, requiring a redraw
*/
virtual void setDirty(bool dirty = true);
/**
* Clears the dirty flag
*/
void clearDirty() { setDirty(false); }
/**
* Returns true if the item is dirty, requiring a redraw
*/
virtual bool isDirty() const { return _isDirty; }
/**
* Helper function to switch to a different visual item
*/
void setView(const Common::String &viewName);
/**
* Helper function to switch to an on-screen popup
*/
void setPopup(Gfx::Popup *popup);
/**
* Helper function to switch the item to be the current view
*/
void setView();
};
} // End of namespace Gfx
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,72 @@
/* 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/shared/gfx/visual_surface.h"
#include "ultima/shared/early/ultima_early.h"
#include "ultima/shared/early/game.h"
#include "ultima/shared/gfx/font.h"
namespace Ultima {
namespace Shared {
namespace Gfx {
VisualSurface::VisualSurface(const Graphics::ManagedSurface &src, const Rect &bounds, GameBase *game) :
_bounds(bounds), _textColor(255), _bgColor(0) {
copyFrom(src);
Shared::Game *sharedGame = dynamic_cast<Shared::Game *>(game);
if (sharedGame) {
_textColor = sharedGame->_textColor;
_bgColor = sharedGame->_bgColor;
}
}
void VisualSurface::drawPoint(const Point &pt, byte color) {
fillRect(Rect(pt.x, pt.y, pt.x + 1, pt.y + 1), color);
}
void VisualSurface::writeString(const Common::String &msg, const Point &pt, int color, int bgColor) {
_textPos = pt;
writeString(msg, color == -1 ? _textColor : color, bgColor == -1 ? _bgColor : bgColor);
}
void VisualSurface::writeString(const Common::String &msg, int color, int bgColor) {
Gfx::Font *font = g_vm->_game->getFont();
font->writeString(*this, msg, _textPos, color == -1 ? _textColor : color, bgColor == -1 ? _bgColor : bgColor);
}
void VisualSurface::writeChar(unsigned char c, const Point &pt, int color, int bgColor) {
_textPos = pt;
writeChar(c, color == -1 ? _textColor : color, bgColor == -1 ? _bgColor : bgColor);
}
void VisualSurface::writeChar(unsigned char c, int color, int bgColor) {
Gfx::Font *font = g_vm->_game->getFont();
font->writeChar(*this, c, _textPos, color == -1 ? _textColor : color, bgColor == -1 ? _bgColor : bgColor);
}
size_t VisualSurface::fontHeight() {
Gfx::Font *font = g_vm->_game->getFont();
return font->lineHeight();
}
} // End of namespace Gfx
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,91 @@
/* 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 ULTIMA_SHARED_GFX_VISUAL_SURFACE_H
#define ULTIMA_SHARED_GFX_VISUAL_SURFACE_H
#include "graphics/managed_surface.h"
#include "ultima/shared/core/named_item.h"
#include "ultima/shared/core/rect.h"
#include "ultima/shared/gfx/screen.h"
namespace Ultima {
namespace Shared {
class GameBase;
namespace Gfx {
class Font;
class VisualSurface : public Graphics::ManagedSurface {
private:
Rect _bounds;
Point _textPos;
byte _textColor;
byte _bgColor;
public:
/**
* Constructor
*/
VisualSurface(const Graphics::ManagedSurface &src, const Rect &bounds, GameBase *game = nullptr);
/**
* Draws a point on the surface
*/
void drawPoint(const Point &pt, byte color);
/**
* Set the position for writing text to
*/
void setTextPos(const Point &pt) { _textPos = pt; }
/**
* Write out a string
*/
void writeString(const Common::String &msg, const Point &pt, int color = -1, int bgColor = -1);
/**
* Write out a string
*/
void writeString(const Common::String &msg, int color = -1, int bgColor = -1);
/**
* Draw a character
*/
void writeChar(unsigned char c, const Point &pt, int color = -1, int bgColor = -1);
/**
* Draw a character
*/
void writeChar(unsigned char c, int color = -1, int bgColor = -1);
/**
* Get the current font height
*/
size_t fontHeight();
};
} // End of namespace Gfx
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,55 @@
/* 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/shared/maps/creature.h"
#include "ultima/shared/early/game.h"
namespace Ultima {
namespace Shared {
namespace Maps {
void Creature::synchronize(Common::Serializer &s) {
s.syncAsSint32LE(_hitPoints);
}
void Creature::update(bool isPreUpdate) {
if (isPreUpdate) {
// Check whether creature can attack
movement();
_isAttacking = attackDistance() != 0;
} else if (_isAttacking && !_gameRef->_party->isDead()) {
attackParty();
}
}
bool Creature::subtractHitPoints(uint amount) {
if ((int)amount >= _hitPoints) {
_hitPoints = 0;
return true;
} else {
_hitPoints -= amount;
return false;
}
}
} // End of namespace Maps
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,105 @@
/* 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 ULTIMA_SHARED_WIDGETS_CREATURE_H
#define ULTIMA_SHARED_WIDGETS_CREATURE_H
#include "ultima/shared/maps/map_widget.h"
#include "ultima/shared/maps/map.h"
#include "common/serializer.h"
namespace Ultima {
namespace Shared {
class Game;
class Map;
namespace Maps {
/**
* Base class for creatures that can be killed
*/
class Creature {
private:
Game *_gameRef;
// MapBase *_mapRef;
protected:
int _hitPoints;
bool _isAttacking;
protected:
/**
* Returns either the maximum attack distance for a monster, or 0 if the monster is beyond
* that distance from the player
*/
virtual uint attackDistance() const { return 0; }
/**
* Handles moving creatures
*/
virtual void movement() {}
/**
* Handles attacking the player
*/
virtual void attackParty() {}
public:
/**
* Constructor
*/
Creature(Game *game, MapBase *) : _gameRef(game), _hitPoints(0), _isAttacking(false) {}
Creature(Game *game, MapBase *, int hitPoints) : _gameRef(game),
_hitPoints(hitPoints), _isAttacking(false) {}
/**
* Destructor
*/
virtual ~Creature() {}
/**
* Handles loading and saving games
*/
void synchronize(Common::Serializer &s);
/**
* Called to update the widget at the end of a turn
* @param isPreUpdate Update is called twice in succession during the end of turn update.
* Once with true for all widgets, then with it false
*/
virtual void update(bool isPreUpdate);
/**
* True true if the creature is dead
*/
bool isDead() const { return _hitPoints <= 0; }
/**
* Removes hit points from a creature
* @param amount Amount to remove
* @returns Returns true if kills the creature
*/
virtual bool subtractHitPoints(uint amount);
};
} // End of namespace Maps
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,66 @@
/* 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 ULTIMA_SHARED_MAPS_DUNGEON_CREATURE_H
#define ULTIMA_SHARED_MAPS_DUNGEON_CREATURE_H
#include "ultima/shared/maps/creature.h"
namespace Ultima {
namespace Shared {
class Game;
class Map;
namespace Maps {
/**
* Stub class for dungeon creatures
*/
class DungeonCreature : public Creature {
public:
/**
* Constructor
*/
DungeonCreature(Game *game, MapBase *map) : Creature(game, map) {}
DungeonCreature(Game *game, MapBase *map, int hitPoints) : Creature(game, map, hitPoints) {}
/**
* Destructor
*/
~DungeonCreature() override {}
/**
* Returns true if a monster blocks the background behind him
*/
virtual bool isBlockingView() const = 0;
/**
* Draw a monster
*/
virtual void draw(DungeonSurface &s, uint distance) = 0;
};
} // End of namespace Maps
} // End of namespace Shared
} // End of namespace Ultima
#endif

View 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 ULTIMA_SHARED_MAPS_DUNGEON_WIDGET_H
#define ULTIMA_SHARED_MAPS_DUNGEON_WIDGET_H
#include "ultima/shared/maps/map_widget.h"
#include "ultima/shared/maps/map.h"
#include "ultima/shared/gfx/dungeon_surface.h"
#include "common/serializer.h"
#include "common/str.h"
namespace Ultima {
namespace Shared {
class Game;
class Map;
namespace Maps {
/**
* Base class for things that appear within the dungeons
*/
class DungeonWidget : public MapWidget {
public:
/**
* Constructor
*/
DungeonWidget(Game *game, Maps::MapBase *map) : MapWidget(game, map) {}
DungeonWidget(Game *game, Maps::MapBase *map, const Point &pt, Direction dir = DIR_NONE) : MapWidget(game, map, pt, dir) {}
DungeonWidget(Game *game, Maps::MapBase *map, const Common::String &name, const Point &pt, Direction dir = DIR_NONE) :
MapWidget(game, map, name, pt, dir) {}
/**
* Destructor
*/
~DungeonWidget() override {}
/**
* Draws an item
*/
virtual void draw(DungeonSurface &s, uint distance) = 0;
};
} // End of namespace Maps
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,58 @@
/* 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/shared/maps/map.h"
#include "ultima/shared/early/game.h"
#include "ultima/shared/gfx/visual_item.h"
namespace Ultima {
namespace Shared {
namespace Maps {
void Map::clear() {
if (_mapArea)
_mapArea->clear();
_mapArea = nullptr;
}
void Map::load(MapId mapId) {
_mapArea = nullptr;
}
void Map::synchronize(Common::Serializer &s) {
int mapId;
if (s.isSaving()) {
// Saving
mapId = _mapArea->getMapId();
s.syncAsUint16LE(mapId);
} else {
// Loading
s.syncAsUint16LE(mapId);
load(mapId);
}
_mapArea->synchronize(s);
}
} // End of namespace Maps
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,250 @@
/* 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 n redistribute it and/or
* 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 ULTIMA_SHARED_MAPS_MAP_H
#define ULTIMA_SHARED_MAPS_MAP_H
#include "common/array.h"
#include "common/serializer.h"
#include "ultima/shared/core/rect.h"
#include "ultima/shared/maps/map_base.h"
#include "ultima/shared/maps/map_widget.h"
#include "ultima/shared/maps/map_tile.h"
namespace Ultima {
namespace Shared {
class Game;
namespace Maps {
#define REGISTER_WIDGET(NAME) if (name == #NAME) return new Widgets::NAME(_game, this)
#define DECLARE_WIDGET(NAME) const char *getClassName() const override { return #NAME; }
/**
* Base class for managing maps within the game
*/
class Map {
protected:
MapBase *_mapArea;
public:
/**
* Constructor
*/
Map() : _mapArea(nullptr) {}
/**
* Destructor
*/
virtual ~Map() {}
/**
* Load a given map
*/
virtual void load(MapId mapId);
/**
* Clears all map data
*/
virtual void clear();
/**
* Handles loading and saving the map's data
*/
virtual void synchronize(Common::Serializer &s);
/**
* Instantiates a widget type by name
*/
MapWidget *createWidget(const Common::String &name) {
assert(_mapArea);
return _mapArea->createWidget(name);
}
/**
* Gets a tile at a given position
*/
void getTileAt(const Point &pt, MapTile *tile, bool includePlayer = true) {
assert(_mapArea);
return _mapArea->getTileAt(pt, tile, includePlayer);
}
/**
* Sets a tile at a given position
*/
void setTileAt(const Point &pt, uint tileId) {
assert(_mapArea);
return _mapArea->setTileAt(pt, tileId);
}
/**
* Get the viewport position
*/
Point getViewportPosition(const Point &viewportSize) {
assert(_mapArea);
return _mapArea->getViewportPosition(viewportSize);
}
/**
* Return the width of the map
*/
size_t width() const {
assert(_mapArea);
return _mapArea->width();
}
/**
* Return the height of the map
*/
size_t height() const {
assert(_mapArea);
return _mapArea->height();
}
/**
* Return the current position
*/
Point getPosition() const {
assert(_mapArea);
return _mapArea->getPosition();
}
/**
* Set the position
*/
void setPosition(const Point &pt) {
assert(_mapArea);
_mapArea->setPosition(pt);
}
/**
* Get the current direction
*/
Direction getDirection() const {
assert(_mapArea);
return _mapArea->getDirection();
}
/**
* Set the current direction
*/
void setDirection(Direction dir) {
assert(_mapArea);
_mapArea->setDirection(dir);
}
/**
* Returns a delta for the cell in front of the player based on the direction they're facing
*/
Point getDirectionDelta() const {
assert(_mapArea);
return _mapArea->getDirectionDelta();
}
/**
* Gets a point relative to the current position
*/
Point getDeltaPosition(const Point &delta) {
assert(_mapArea);
return _mapArea->getDeltaPosition(delta);
}
/**
* Shifts the viewport by a given delta
*/
void shiftViewport(const Point &delta) {
assert(_mapArea);
_mapArea->shiftViewport(delta);
}
/**
* Returns the number of tiles in the map there are for each tile in the original game.
* This allows for more detailed maps in the enhanced game modes
*/
Point getTilesPerOrigTile() const {
assert(_mapArea);
return _mapArea->_tilesPerOrigTile;
}
/**
* Return the name of the map
*/
Common::String getName() const {
assert(_mapArea);
return _mapArea->_name;
}
/**
* Returns the currently active widget that the player is controlling
*/
MapWidget *getPlayerWidget() const {
assert(_mapArea);
return _mapArea->_playerWidget;
}
/**
* @param delta Delta to change dungeon level by
* @returns False if dungeon left, true if still within dungeon
*/
bool changeLevel(int delta) {
assert(_mapArea);
return _mapArea->changeLevel(delta);
}
/**
* Get the current map level
*/
uint getLevel() const {
assert(_mapArea);
return _mapArea->getLevel();
}
/**
* Returns whether the map wraps around to the other side at it's edges (i.e. the overworld)
*/
bool isMapWrapped() const {
assert(_mapArea);
return _mapArea->isMapWrapped();
}
/**
* Updates the map at the end of a turn
*/
void update() {
assert(_mapArea);
return _mapArea->update();
}
/**
* Cast a specific spell
*/
void castSpell(uint spellId) {
assert(_mapArea);
_mapArea->castSpell(spellId);
}
};
} // End of namespace Maps
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,236 @@
/* 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/shared/maps/map_base.h"
#include "ultima/shared/maps/map_widget.h"
#include "ultima/shared/maps/map.h"
#include "ultima/shared/early/game.h"
#include "ultima/shared/gfx/visual_item.h"
namespace Ultima {
namespace Shared {
namespace Maps {
MapWidget *MapBase::WidgetsArray::findByClass(const ClassDef &classDef) const {
for (uint idx = 0; idx < size(); ++idx) {
MapWidget *w = (*this)[idx].get();
if (w->isInstanceOf(classDef))
return w;
}
return nullptr;
}
/*-------------------------------------------------------------------*/
void MapBase::clear() {
_mapId = 0;
_data.clear();
_widgets.clear();
}
void MapBase::load(MapId mapId) {
_mapId = mapId;
}
void MapBase::synchronize(Common::Serializer &s) {
_viewportPos.synchronize(s);
uint size;
int transportIndex = -1;
Common::String name;
// If the map is modified in any way, it gets synchronized as well
s.syncAsByte(_mapModified);
if (_mapModified) {
for (uint y = 0; y < height(); ++y) {
for (uint x = 0; x < width(); ++x)
s.syncAsByte(_data[y][x]);
}
}
if (s.isSaving()) {
// Save widgets
size = 0;
for (uint idx = 0; idx < _widgets.size(); ++idx) {
if (_widgets[idx]->getClassName())
++size;
if (_playerWidget == _widgets[idx].get())
transportIndex = (int)idx;
}
assert(transportIndex >= 0);
s.syncAsUint16LE(size);
for (uint idx = 0; idx < _widgets.size(); ++idx) {
name = _widgets[idx]->getClassName();
if (!name.empty()) {
s.syncString(name);
_widgets[idx]->synchronize(s);
}
}
s.syncAsUint16LE(transportIndex);
} else {
// Load widgets
s.syncAsUint16LE(size);
_widgets.clear();
for (uint idx = 0; idx < size; ++idx) {
s.syncString(name);
MapWidget *w = createWidget(name);
w->synchronize(s);
addWidget(w);
}
s.syncAsUint16LE(transportIndex);
_playerWidget = _widgets[transportIndex].get();
}
}
void MapBase::setDimensions(const Point &size) {
_data.resize(size.y);
for (int y = 0; y < size.y; ++y)
_data[y].resize(size.x);
_size = size;
}
Point MapBase::getDirectionDelta() const {
switch (_playerWidget->_direction) {
case DIR_LEFT:
return Point(-1, 0);
case DIR_RIGHT:
return Point(1, 0);
case DIR_UP:
return Point(0, -1);
default:
return Point(0, 1);
}
}
Point MapBase::getDeltaPosition(const Point &delta) {
return _playerWidget->_position + delta;
}
void MapBase::resetViewport() {
// Reset the viewport, so it's position will get recalculated
_viewportPos.reset();
}
Point MapBase::getViewportPosition(const Point &viewportSize) {
Point &topLeft = _viewportPos._topLeft;
if (!_viewportPos.isValid() || _viewportPos._size != viewportSize) {
// Calculate the new position
topLeft.x = _playerWidget->_position.x - (viewportSize.x - 1) / 2;
topLeft.y = _playerWidget->_position.y - (viewportSize.y - 1) / 2;
// Fixed maps, so constrain top left corner so the map fills the viewport.
// This will accommodate future renderings with more tiles, or greater tile size
topLeft.x = CLIP((int)topLeft.x, 0, (int)(width() - viewportSize.x));
topLeft.y = CLIP((int)topLeft.y, 0, (int)(height() - viewportSize.y));
}
return topLeft;
}
void MapBase::shiftViewport(const Point &delta) {
Point &topLeft = _viewportPos._topLeft;
topLeft += delta;
// Shift the viewport, but constraining the map to fill up the screen
topLeft.x = CLIP(topLeft.x, (int16)0, (int16)(width() - _viewportPos._size.x));
topLeft.y = CLIP(topLeft.y, (int16)0, (int16)(height() - _viewportPos._size.y));
}
void MapBase::addWidget(MapWidget *widget) {
_widgets.push_back(MapWidgetPtr(widget));
}
void MapBase::removeWidget(MapWidget *widget) {
for (uint idx = 0; idx < _widgets.size(); ++idx) {
if (_widgets[idx].get() == widget) {
_widgets.remove_at(idx);
break;
}
}
}
void MapBase::getTileAt(const Point &pt, MapTile *tile, bool includePlayer) {
tile->clear();
// Get the base tile
tile->_tileDisplayNum = tile->_tileId = _data[pt.y][pt.x];
// Check for any widgets on that map tile
tile->_widgets.clear();
tile->_widget = nullptr;
tile->_widgetNum = -1;
for (int idx = (int)_widgets.size() - 1; idx >= 0; --idx) {
MapWidget *widget = _widgets[idx].get();
if (widget->_position == pt && (includePlayer || widget != _playerWidget)) {
tile->_widgets.push_back(widget);
if (!tile->_widget) {
tile->_widgetNum = idx;
tile->_widget = widget;
}
}
}
}
void MapBase::setTileAt(const Point &pt, uint tileId) {
_data[pt.y][pt.x] = tileId;
}
void MapBase::update() {
// Call the update method of each widget, to allow for things like npc movement, etc.
for (uint idx = 0; idx < _widgets.size(); ++idx)
_widgets[idx].get()->update(true);
// Call the update method of each widget, to allow for things like npc movement, etc.
for (uint idx = 0; idx < _widgets.size(); ++idx)
_widgets[idx].get()->update(false);
}
Point MapBase::getPosition() const {
return _playerWidget->_position;
}
void MapBase::setPosition(const Point &pt) {
_playerWidget->_position = pt;
}
Direction MapBase::getDirection() const {
return _playerWidget->_direction;
}
void MapBase::setDirection(Direction dir) {
_playerWidget->_direction = dir;
}
void MapBase::addInfoMsg(const Common::String &text, bool newLine, bool replaceLine) {
CInfoMsg msg(text, newLine, replaceLine);
msg.execute(_game->getView());
}
} // End of namespace Maps
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,291 @@
/* 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 ULTIMA_SHARED_MAPS_MAP_BASE_H
#define ULTIMA_SHARED_MAPS_MAP_BASE_H
#include "common/array.h"
#include "common/serializer.h"
#include "ultima/shared/core/base_object.h"
#include "ultima/shared/core/rect.h"
#include "ultima/shared/maps/map_widget.h"
namespace Ultima {
namespace Shared {
class Game;
namespace Maps {
typedef int MapId;
typedef byte MapCell;
class Map;
class MapTile;
/**
* Base class for specific map types
*/
class MapBase {
/**
* Widgets array
*/
class WidgetsArray : public Common::Array<MapWidgetPtr> {
public:
/**
* Finds a widget by class
*/
MapWidget *findByClass(const ClassDef &classDef) const;
};
/**
* Internal class used for storing the data for a row
*/
struct MapCellsRow {
private:
Common::Array<MapCell> _data;
public:
byte &operator[](int idx) { return _data[idx]; }
byte operator[](int idx) const { return _data[idx]; }
/**
* Resize the row
*/
void resize(size_t newSize) { _data.resize(newSize); }
};
/**
* Stores state about the current viewport being displayed. It's kept as part of the Map class
* as a convenience to be alongside the current party position
*/
struct ViewportPosition {
Point _topLeft; // Top, left tile position for viewport
Point _size; // Size of the viewport. Just in case we ever allow it to change
MapId _mapId; // Maze the viewport is for. Used to detect when the map changes
/**
* Constructor
*/
ViewportPosition() : _topLeft(-1, -1), _mapId(-1) {}
/**
* Returns true if the viewport is in a valid state
*/
bool isValid() const { return _mapId != -1; }
/**
* Handles loading and saving viewport
*/
void synchronize(Common::Serializer &s) {
s.syncAsUint16LE(_topLeft.x);
s.syncAsUint16LE(_topLeft.y);
}
/**
* Resets the viewport position, so it'll get recalculated the next call to getViewportPosition
*/
void reset() { _mapId = -1; }
};
private:
// Map *_map; // Map manager reference
Game *_game; // Game reference
bool _mapModified; // Tiles have been dynamically changed
protected:
MapId _mapId; // The map Id
uint _mapIndex; // Index of map within the group of same maps
uint _mapStyle; // Map style category for towns & castles
ViewportPosition _viewportPos; // Viewport position
Common::Array<MapCellsRow> _data; // Data for the map
protected:
/**
* Set the size of the map
*/
void setDimensions(const Point &size);
/**
* Adds a text string to the info area
* @param text Text to add
* @param newLine Whether to apply a newline at the end
* @param replaceLine If true, replaces the current last line
*/
void addInfoMsg(const Common::String &text, bool newLine = true, bool replaceLine = false);
public:
Point _size; // X, Y size of the map
Point _tilesPerOrigTile; // For enhanced modes, number of tiles per original game tile
Common::String _name; // Name of map, if applicable
MapWidget *_playerWidget; // Current means of transport, even if on foot
WidgetsArray _widgets; // Party, monsteres, transports, etc.
public:
/**
* Constructor
*/
MapBase(Game *game, Map *) : _game(game),_playerWidget(nullptr),
_mapModified(false), _mapId(0), _mapIndex(0), _mapStyle(0) {}
/**
* Destructor
*/
virtual ~MapBase() {}
/**
* Handles loading and saving the map's data
*/
virtual void synchronize(Common::Serializer &s);
/**
* Adds a widget to the map
*/
void addWidget(MapWidget *widget);
/**
* Removes a widget from the map
*/
void removeWidget(MapWidget *widget);
/**
* Clears all map data
*/
virtual void clear();
/**
* Gets a tile at a given position
*/
virtual void getTileAt(const Point &pt, MapTile *tile, bool includePlayer = true);
/**
* Sets a tile at a given position
*/
virtual void setTileAt(const Point &pt, uint tileId);
/**
* Resets the viewport when the viewport changes
*/
void resetViewport();
/**
* Get the viewport position
*/
virtual Point getViewportPosition(const Point &viewportSize);
/**
* Load the map
*/
virtual void load(MapId mapId);
/**
* Changes the level. Only applicable to dungeon maps which have levels
* @param delta Delta to change dungeon level by
* @returns False if dungeon left, true if still within dungeon
*/
virtual bool changeLevel(int delta) { return true; }
/**
* Get the current map level
*/
virtual uint getLevel() const { return 0; }
/**
* Returns whether the map wraps around to the other side at it's edges (i.e. the overworld)
*/
virtual bool isMapWrapped() const { return false; }
/**
* Instantiates a widget type by name
*/
virtual MapWidget *createWidget(const Common::String &name) = 0;
/**
* Returns the width of the map
*/
size_t width() const { return _size.x; }
/**
* Returns the height of the map
*/
size_t height() const { return _size.y; }
/**
* Get the current position
*/
Point getPosition() const;
/**
* Set the current position
*/
void setPosition(const Point &pt);
/**
* Get the current direction
*/
Direction getDirection() const;
/**
* Set the current direction
*/
void setDirection(Direction dir);
/**
* Returns a delta for the cell in front of the player based on the direction they're facing
*/
Point getDirectionDelta() const;
/**
* Gets a point relative to the current position
*/
virtual Point getDeltaPosition(const Point &delta);
/**
* Returns the map Id
*/
MapId getMapId() const { return _mapId; }
/**
* Gets the map Index
*/
uint getMapIndex() const { return _mapIndex; }
/**
* Gets the map style
*/
uint getMapStyle() const { return _mapStyle; }
/**
* Shifts the viewport by a given delta
*/
virtual void shiftViewport(const Point &delta);
/**
* Updates the map at the end of a turn
*/
virtual void update();
/**
* Cast a specific spell
*/
virtual void castSpell(uint spell) = 0;
};
} // End of namespace Maps
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,41 @@
/* 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/shared/maps/map_tile.h"
#include "ultima/shared/maps/map_widget.h"
namespace Ultima {
namespace Shared {
namespace Maps {
void MapTile::clear() {
_tileId = _tileDisplayNum = -1;
_widgets.clear();
_widgetNum = -1;
_widget = nullptr;
_isDoor = _isSecretDoor = false;
_isLadderUp = _isLadderDown = false;
_isWall = _isHallway = _isBeams = false;
}
} // End of namespace Maps
} // End of namespace Shared
} // End of namespace Ultima

View File

@@ -0,0 +1,91 @@
/* 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 ULTIMA_SHARED_MAPS_MAP_TILE_H
#define ULTIMA_SHARED_MAPS_MAP_TILE_H
#include "common/array.h"
namespace Ultima {
namespace Shared {
namespace Maps {
class MapWidget;
/**
* Contains data about a given position within the map
*/
class MapTile {
public:
int _tileId; // Original tile Id
int _tileDisplayNum; // Tile number to display. Can differ from tileId, such as tiles in the
// city for talking/stealing to merchants showing as ground
Common::Array<MapWidget *> _widgets; // Widgets on the tile, if any
int _widgetNum; // Widget number of first widget, if any
MapWidget *_widget; // Pointer tofirst widget on tile, if any
// Dungeon tile flags
bool _isDoor, _isSecretDoor;
bool _isLadderUp, _isLadderDown;
bool _isWall, _isHallway, _isBeams;
public:
/**
* Constructor
*/
MapTile() : _tileDisplayNum(-1), _tileId(-1), _widgetNum(-1), _widget(0),
_isDoor(false), _isSecretDoor(false), _isLadderUp(false), _isLadderDown(false), _isWall(false),
_isHallway(false), _isBeams(false) {}
/**
* Destructor
*/
virtual ~MapTile() {}
/**
* Clears the map tile information
*/
virtual void clear();
/**
* Returns true if the tile is a door in a dungeon
*/
bool isDoor() const { return _isDoor; }
/**
* Returns true if the tile is a wall or secret door in a dungeon
*/
bool isWallOrSecretDoor() const { return _isWall || _isSecretDoor; }
/**
* Returns true if the tile in a dungeon is a type that has walls on it: walls, doors, or secret doors
*/
bool isWallOrDoorway() const { return _isWall || _isDoor || _isSecretDoor; }
/**
* Returns true if a tile is a solid type within a dungeon
*/
bool isSolid() const { return !(_isHallway || _isLadderUp || _isLadderDown || _isBeams); }
};
} // End of namespace Maps
} // End of namespace Shared
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,117 @@
/* 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/shared/maps/map_widget.h"
#include "ultima/shared/maps/map_base.h"
#include "ultima/shared/maps/map_tile.h"
#include "ultima/shared/early/game.h"
#include "ultima/shared/gfx/visual_item.h"
namespace Ultima {
namespace Shared {
namespace Maps {
EMPTY_MESSAGE_MAP(MapWidget, MessageTarget);
Direction MapWidget::directionFromKey(Common::KeyCode keycode) {
switch (keycode) {
case Common::KEYCODE_LEFT:
case Common::KEYCODE_KP4:
return DIR_WEST;
case Common::KEYCODE_RIGHT:
case Common::KEYCODE_KP6:
return DIR_EAST;
case Common::KEYCODE_UP:
case Common::KEYCODE_KP8:
return DIR_NORTH;
case Common::KEYCODE_DOWN:
case Common::KEYCODE_KP2:
return DIR_SOUTH;
default:
return DIR_NONE;
}
}
void MapWidget::synchronize(Common::Serializer &s) {
s.syncAsUint16LE(_position.x);
s.syncAsSint16LE(_position.y);
s.syncAsByte(_direction);
s.syncString(_name);
}
void MapWidget::addInfoMsg(const Common::String &text, bool newLine, bool replaceLine) {
CInfoMsg msg(text, newLine, replaceLine);
msg.execute(_game->getView());
}
MapWidget::CanMove MapWidget::canMoveTo(const Point &destPos) {
if (destPos.x < 0 || destPos.y < 0 || destPos.x >= (int)_map->width() || destPos.y >= (int)_map->height()) {
// If the map is fixed, allow moving beyond it's edges so it can be left
if (!_map->isMapWrapped())
return YES;
}
// Get the details of the position
MapTile destTile;
_map->getTileAt(destPos, &destTile);
// If there's a widget blocking the tile, return false
if (destTile._widget && destTile._widget->isBlocking())
return NO;
return UNSET;
}
void MapWidget::moveTo(const Point &destPos, Direction dir) {
// If no direction is specified, we'll need to figure it out relative to the old position
if (dir == DIR_NONE) {
Point delta = destPos - _position;
if (ABS(delta.x) > ABS(delta.y))
_direction = delta.x > 0 ? DIR_EAST : DIR_WEST;
else if (delta.y != 0)
_direction = delta.y > 0 ? DIR_SOUTH : DIR_NORTH;
} else {
_direction = dir;
}
// Set new location
_position = destPos;
// Handle wrap around if need be on maps that wrap
if (_map->isMapWrapped()) {
if (_position.x < 0)
_position.x += _map->width();
else if (_position.x >= (int)_map->width())
_position.x -= _map->width();
if (_position.y < 0)
_position.y += _map->height();
else if (_position.y >= (int)_map->height())
_position.y -= _map->height();
}
}
} // End of namespace Maps
} // End of namespace Shared
} // End of namespace Ultima

Some files were not shown because too many files have changed in this diff Show More