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,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