Initial commit
This commit is contained in:
169
engines/ultima/ultima0/console.cpp
Normal file
169
engines/ultima/ultima0/console.cpp
Normal 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ultima/ultima0/console.h"
|
||||
#include "ultima/ultima0/ultima0.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
|
||||
Console::Console() : GUI::Debugger() {
|
||||
registerCmd("view", WRAP_METHOD(Console, cmdView));
|
||||
registerCmd("food", WRAP_METHOD(Console, cmdFood));
|
||||
registerCmd("hp", WRAP_METHOD(Console, cmdHP));
|
||||
registerCmd("gold", WRAP_METHOD(Console, cmdGold));
|
||||
registerCmd("demo", WRAP_METHOD(Console, cmdDemo));
|
||||
registerCmd("debug", WRAP_METHOD(Console, cmdDebug));
|
||||
registerCmd("monster", WRAP_METHOD(Console, cmdMonster));
|
||||
}
|
||||
|
||||
Console::~Console() {
|
||||
}
|
||||
|
||||
bool Console::cmdView(int argc, const char **argv) {
|
||||
if (argc != 2) {
|
||||
debugPrintf("view <view name>\n");
|
||||
return true;
|
||||
} else {
|
||||
g_events->replaceView(argv[1]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Console::cmdFood(int argc, const char **argv) {
|
||||
if (argc != 2) {
|
||||
debugPrintf("food <amount>\n");
|
||||
return true;
|
||||
} else {
|
||||
g_engine->_player._object[OB_FOOD] = atoi(argv[1]);
|
||||
g_engine->focusedView()->redraw();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Console::cmdGold(int argc, const char **argv) {
|
||||
if (argc != 2) {
|
||||
debugPrintf("gold <amount>\n");
|
||||
return true;
|
||||
} else {
|
||||
g_engine->_player._attr[AT_GOLD] = atoi(argv[1]);
|
||||
g_engine->focusedView()->redraw();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Console::cmdHP(int argc, const char **argv) {
|
||||
if (argc != 2) {
|
||||
debugPrintf("hp <amount>\n");
|
||||
return true;
|
||||
} else {
|
||||
g_engine->_player._attr[AT_HP] = atoi(argv[1]);
|
||||
g_engine->focusedView()->redraw();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Console::cmdDemo(int argc, const char **argv) {
|
||||
auto &p = g_engine->_player;
|
||||
auto &map = g_engine->_worldMap;
|
||||
|
||||
p.init();
|
||||
Common::strcpy_s(p._name, "Demo"); // Characters Name
|
||||
p._class = 'F'; // Fighter
|
||||
p._luckyNumber = 42; // Always the same.....
|
||||
p._skill = 1; // Skill level 1
|
||||
p._task = 1; // Starting first task
|
||||
|
||||
// Nice high attributes
|
||||
Common::fill(p._attr, p._attr + MAX_ATTR, 15);
|
||||
p._attr[AT_HP] = 18;
|
||||
p._attr[AT_GOLD] = 99;
|
||||
|
||||
for (int i = 0; i < MAX_OBJ; i++) // Lots of nice objects
|
||||
p._object[i] = (i == OB_FOOD || i == OB_BOW) ? 999 : 4.0;
|
||||
|
||||
p._level = 0;
|
||||
map.init(p);
|
||||
g_engine->replaceView("WorldMap");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Console::cmdDebug(int argc, const char **argv) {
|
||||
auto &p = g_engine->_player;
|
||||
auto &map = g_engine->_worldMap;
|
||||
int i;
|
||||
|
||||
p.init();
|
||||
Common::strcpy_s(p._name, "Debuggo"); // Characters Name
|
||||
p._class = 'F'; // Fighter
|
||||
p._luckyNumber = 42; // Always the same.....
|
||||
p._skill = 1; // Skill level 1
|
||||
p._task = 1; // Starting first task
|
||||
|
||||
for (i = 0; i < MAX_ATTR; i++) // Nice high attributes
|
||||
p._attr[i] = 99;
|
||||
p._attr[AT_HP] = 999;
|
||||
p._attr[AT_GOLD] = 9999;
|
||||
for (i = 0; i < MAX_OBJ; i++) // Lots of nice objects
|
||||
p._object[i] = (i == OB_FOOD || i == OB_BOW) ? 9999.9 : 99.0;
|
||||
|
||||
p._level = 0;
|
||||
map.init(p);
|
||||
g_engine->replaceView("WorldMap");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Console::cmdMonster(int argc, const char **argv) {
|
||||
const auto &player = g_engine->_player;
|
||||
auto &dungeon = g_engine->_dungeon;
|
||||
|
||||
if (argc != 2) {
|
||||
debugPrintf("monster <1 to 10>\n");
|
||||
return true;
|
||||
} else if (player._level == 0) {
|
||||
debugPrintf("Not in a dungeon.\n");
|
||||
return true;
|
||||
} else {
|
||||
Common::Point pt = player._dungeonPos + player._dungeonDir;
|
||||
|
||||
if (!ISWALKTHRU(dungeon._map[pt.x][pt.y])) {
|
||||
debugPrintf("No free spot in front of player.\n");
|
||||
return true;
|
||||
} else {
|
||||
int num = atoi(argv[1]);
|
||||
|
||||
if (num >= 1 && num <= 10) {
|
||||
dungeon.addMonsterAtPos(player, pt, num);
|
||||
g_events->send("Dungeon", GameMessage("ENDOFTURN"));
|
||||
return false;
|
||||
} else {
|
||||
debugPrintf("Invalid monster number.\n");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
49
engines/ultima/ultima0/console.h
Normal file
49
engines/ultima/ultima0/console.h
Normal 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_ULTIMA0_CONSOLE_H
|
||||
#define ULTIMA_ULTIMA0_CONSOLE_H
|
||||
|
||||
#include "gui/debugger.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
|
||||
class Console : public GUI::Debugger {
|
||||
private:
|
||||
bool cmdView(int argc, const char **argv);
|
||||
bool cmdFood(int argc, const char **argv);
|
||||
bool cmdGold(int argc, const char **argv);
|
||||
bool cmdHP(int argc, const char **argv);
|
||||
bool cmdDemo(int argc, const char **argv);
|
||||
bool cmdDebug(int argc, const char **argv);
|
||||
bool cmdMonster(int argc, const char **argv);
|
||||
|
||||
public:
|
||||
Console();
|
||||
~Console() override;
|
||||
};
|
||||
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
|
||||
#endif
|
||||
389
engines/ultima/ultima0/data/data.cpp
Normal file
389
engines/ultima/ultima0/data/data.cpp
Normal file
@@ -0,0 +1,389 @@
|
||||
/* 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/ultima0/data/data.h"
|
||||
#include "ultima/ultima0/ultima0.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
|
||||
const ObjectInfo OBJECT_INFO[] = {
|
||||
{ "Food", 1, 0, KEYBIND_FOOD },
|
||||
{ "Rapier", 8, 10, KEYBIND_RAPIER },
|
||||
{ "Axe", 5, 5, KEYBIND_AXE },
|
||||
{ "Shield", 6, 1, KEYBIND_SHIELD },
|
||||
{ "Bow and Arrow", 3, 4, KEYBIND_BOW },
|
||||
{ "Magic Amulet", 15, 0, KEYBIND_AMULET }
|
||||
};
|
||||
|
||||
const MonsterInfo MONSTER_INFO[] = {
|
||||
{ nullptr, 0 },
|
||||
{ "Skeleton", 1 },
|
||||
{ "Thief", 2 },
|
||||
{ "Giant Rat", 3 },
|
||||
{ "Orc", 4 },
|
||||
{ "Viper", 5 },
|
||||
{ "Carrion Crawler", 6 },
|
||||
{ "Gremlin", 7 },
|
||||
{ "Mimic", 8 },
|
||||
{ "Daemon", 9 },
|
||||
{ "Balrog", 10 }
|
||||
};
|
||||
|
||||
const char *ATTRIB_NAMES[] = { "Hit Points", "Strength", "Dexterity", "Stamina", "Wisdom", "Gold" };
|
||||
const char *const DIRECTION_NAMES[] = { "North", "East", "South", "West" };
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
void PlayerInfo::init() {
|
||||
Common::fill(_name, _name + MAX_NAME + 1, '\0');
|
||||
_worldPos.x = _worldPos.y = 0;
|
||||
_dungeonPos.x = _dungeonPos.y = 0;
|
||||
_dungeonDir.x = _dungeonDir.y = 0;
|
||||
_class = '?';
|
||||
_hpGain = 0;
|
||||
_luckyNumber = 0;
|
||||
_level = 0;
|
||||
_skill = 0;
|
||||
_task = 0;
|
||||
_taskCompleted = false;
|
||||
Common::fill(_attr, _attr + MAX_ATTR, 0);
|
||||
Common::fill(_object, _object + MAX_OBJ, 0);
|
||||
}
|
||||
|
||||
void PlayerInfo::rollAttributes() {
|
||||
for (int i = 0; i < MAX_ATTR; ++i)
|
||||
_attr[i] = g_engine->getRandomNumber(21) + 4;
|
||||
}
|
||||
|
||||
void PlayerInfo::synchronize(Common::Serializer &s) {
|
||||
s.syncBytes((byte *)_name, MAX_NAME + 1);
|
||||
s.syncAsSint16LE(_worldPos.x);
|
||||
s.syncAsSint16LE(_worldPos.y);
|
||||
s.syncAsSint16LE(_dungeonPos.x);
|
||||
s.syncAsSint16LE(_dungeonPos.y);
|
||||
s.syncAsSint16LE(_dungeonDir.x);
|
||||
s.syncAsSint16LE(_dungeonDir.y);
|
||||
s.syncAsByte(_class);
|
||||
s.syncAsSint32LE(_hpGain);
|
||||
s.syncAsSint32LE(_level);
|
||||
s.syncAsSint32LE(_skill);
|
||||
s.syncAsSint32LE(_task);
|
||||
s.syncAsSint32LE(_taskCompleted);
|
||||
s.syncAsUint32LE(_luckyNumber);
|
||||
|
||||
for (int i = 0; i < MAX_ATTR; ++i)
|
||||
s.syncAsUint32LE(_attr[i]);
|
||||
for (int i = 0; i < MAX_OBJ; ++i) {
|
||||
uint32 val = (uint32)_object[i];
|
||||
s.syncAsUint32LE(val);
|
||||
if (s.isLoading())
|
||||
_object[i] = (double)val;
|
||||
}
|
||||
}
|
||||
|
||||
Direction PlayerInfo::dungeonDir() const {
|
||||
if (_dungeonDir.y < 0)
|
||||
return DIR_NORTH;
|
||||
else if (_dungeonDir.x > 0)
|
||||
return DIR_EAST;
|
||||
else if (_dungeonDir.y > 0)
|
||||
return DIR_SOUTH;
|
||||
else
|
||||
return DIR_WEST;
|
||||
}
|
||||
|
||||
void PlayerInfo::setDungeonDir(Direction newDir) {
|
||||
_dungeonDir.x = 0;
|
||||
_dungeonDir.y = 0;
|
||||
switch (newDir) {
|
||||
case DIR_NORTH:
|
||||
_dungeonDir.y = -1;
|
||||
break;
|
||||
case DIR_EAST:
|
||||
_dungeonDir.x = 1;
|
||||
break;
|
||||
case DIR_SOUTH:
|
||||
_dungeonDir.y = 1;
|
||||
break;
|
||||
case DIR_WEST:
|
||||
_dungeonDir.x = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerInfo::dungeonTurnLeft() {
|
||||
Direction dir = dungeonDir();
|
||||
setDungeonDir((dir == DIR_NORTH) ? DIR_WEST : (Direction)((int)dir - 1));
|
||||
}
|
||||
|
||||
void PlayerInfo::dungeonTurnRight() {
|
||||
Direction dir = dungeonDir();
|
||||
setDungeonDir((dir == DIR_WEST) ? DIR_NORTH : (Direction)((int)dir + 1));
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
void WorldMapInfo::init(PlayerInfo &p) {
|
||||
int c, x, y, size;
|
||||
|
||||
g_engine->setRandomSeed(p._luckyNumber);
|
||||
size = WORLD_MAP_SIZE - 1;
|
||||
|
||||
// Set the boundaries
|
||||
for (x = 0; x <= size; x++) {
|
||||
_map[size][x] = WT_MOUNTAIN;
|
||||
_map[0][x] = WT_MOUNTAIN;
|
||||
_map[x][size] = WT_MOUNTAIN;
|
||||
_map[x][0] = WT_MOUNTAIN;
|
||||
}
|
||||
|
||||
// Set up the map contents
|
||||
for (x = 1; x < size; x++) {
|
||||
for (y = 1; y < size; y++) {
|
||||
c = (int)(pow(RND(), 5.0) * 4.5); // Calculate what's there
|
||||
if (c == WT_TOWN && RND() > .5) // Remove half the towns
|
||||
c = WT_SPACE;
|
||||
_map[x][y] = c;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate player start
|
||||
x = g_engine->getRandomNumber(1, size - 1);
|
||||
y = g_engine->getRandomNumber(1, size - 1);
|
||||
p._worldPos.x = x; p._worldPos.y = y; // Save it
|
||||
_map[x][y] = WT_TOWN; // Make it a town
|
||||
|
||||
// Find place for castle
|
||||
do {
|
||||
x = g_engine->getRandomNumber(1, size - 1);
|
||||
y = g_engine->getRandomNumber(1, size - 1);
|
||||
} while (_map[x][y] != WT_SPACE);
|
||||
|
||||
_map[x][y] = WT_BRITISH; // Put LBs castle there
|
||||
}
|
||||
|
||||
int WorldMapInfo::read(int x, int y) const {
|
||||
if (x < 0 || y < 0)
|
||||
return WT_MOUNTAIN;
|
||||
if (x >= WORLD_MAP_SIZE || y >= WORLD_MAP_SIZE)
|
||||
return WT_MOUNTAIN;
|
||||
return _map[x][y];
|
||||
}
|
||||
|
||||
void WorldMapInfo::synchronize(Common::Serializer &s) {
|
||||
for (int y = 0; y < WORLD_MAP_SIZE; ++y)
|
||||
for (int x = 0; x < WORLD_MAP_SIZE; ++x)
|
||||
s.syncAsByte(_map[x][y]);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
void DungeonMapInfo::create(const PlayerInfo &player) {
|
||||
int i, x, y;
|
||||
const int SIZE = DUNGEON_MAP_SIZE - 1;
|
||||
|
||||
// Seed the random number
|
||||
g_engine->setRandomSeed(player._luckyNumber - player._worldPos.x * 40 -
|
||||
player._worldPos.y * 1000 - player._level);
|
||||
|
||||
// Clear the dungeon
|
||||
Common::fill((byte *)_map, (byte *)_map + DUNGEON_MAP_SIZE * DUNGEON_MAP_SIZE, DT_SPACE);
|
||||
|
||||
// Draw the boundaries
|
||||
for (x = 0; x <= SIZE; x++) {
|
||||
_map[SIZE][x] = DT_SOLID;
|
||||
_map[0][x] = DT_SOLID;
|
||||
_map[x][SIZE] = DT_SOLID;
|
||||
_map[x][0] = DT_SOLID;
|
||||
}
|
||||
|
||||
// Fill with checkerboard
|
||||
for (x = 2; x < SIZE; x = x + 2) {
|
||||
for (y = 1; y < SIZE; y++) {
|
||||
_map[x][y] = DT_SOLID;
|
||||
_map[y][x] = DT_SOLID;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill with stuff
|
||||
for (x = 2; x < SIZE; x = x + 2) {
|
||||
for (y = 1; y < SIZE; y = y + 2) {
|
||||
_map[x][y] = generateContent(_map[x][y]);
|
||||
_map[y][x] = generateContent(_map[y][x]);
|
||||
}
|
||||
}
|
||||
|
||||
// Put stairs in
|
||||
_map[2][1] = DT_SPACE;
|
||||
|
||||
// Different ends each level
|
||||
if (player._level % 2 == 0) {
|
||||
_map[SIZE - 3][3] = DT_LADDERDN;
|
||||
_map[3][SIZE - 3] = DT_LADDERUP;
|
||||
} else {
|
||||
_map[SIZE - 3][3] = DT_LADDERUP;
|
||||
_map[3][SIZE - 3] = DT_LADDERDN;
|
||||
}
|
||||
|
||||
// On first floor
|
||||
if (player._level == 1) {
|
||||
_map[1][1] = DT_LADDERUP; // Ladder at top left
|
||||
_map[SIZE - 3][3] = DT_SPACE; // No other ladder up
|
||||
}
|
||||
|
||||
// WORKAROUND: Make sure dungeon is completable
|
||||
byte mapTrace[DUNGEON_MAP_SIZE][DUNGEON_MAP_SIZE];
|
||||
bool isValid;
|
||||
do {
|
||||
isValid = false;
|
||||
|
||||
// Start a new trace, mark solid spaces
|
||||
for (y = 0; y < DUNGEON_MAP_SIZE; ++y)
|
||||
for (x = 0; x < DUNGEON_MAP_SIZE; ++x)
|
||||
mapTrace[x][y] = _map[x][y] == DT_SOLID ? DT_SOLID : DT_SPACE;
|
||||
|
||||
// Iterate through figuring out route
|
||||
Common::Queue<Common::Point> points;
|
||||
if (player._level % 2 == 0)
|
||||
points.push(Common::Point(SIZE - 3, 3));
|
||||
else
|
||||
points.push(Common::Point(3, SIZE - 3));
|
||||
while (!points.empty() && !isValid) {
|
||||
Common::Point pt = points.pop();
|
||||
isValid = _map[pt.x][pt.y] == DT_LADDERUP;
|
||||
if (isValid)
|
||||
break;
|
||||
|
||||
mapTrace[pt.x][pt.y] = DT_LADDERDN;
|
||||
if (pt.x > 1 && _map[pt.x - 1][pt.y] != DT_SOLID && mapTrace[pt.x - 1][pt.y] == DT_SPACE)
|
||||
points.push(Common::Point(pt.x - 1, pt.y));
|
||||
if (pt.x < SIZE && _map[pt.x + 1][pt.y] != DT_SOLID && mapTrace[pt.x + 1][pt.y] == DT_SPACE)
|
||||
points.push(Common::Point(pt.x + 1, pt.y));
|
||||
if (pt.y > 1 && _map[pt.x][pt.y - 1] != DT_SOLID && mapTrace[pt.x][pt.y - 1] == DT_SPACE)
|
||||
points.push(Common::Point(pt.x, pt.y - 1));
|
||||
if (pt.y < SIZE && _map[pt.x][pt.y + 1] != DT_SOLID && mapTrace[pt.x][pt.y + 1] == DT_SPACE)
|
||||
points.push(Common::Point(pt.x, pt.y + 1));
|
||||
}
|
||||
|
||||
if (!isValid) {
|
||||
// If a path wasn't found, randomly replace a solid square. We'll then
|
||||
// loop to check whether the path can now be completed
|
||||
do {
|
||||
x = g_engine->getRandomNumber(1, SIZE);
|
||||
y = g_engine->getRandomNumber(1, SIZE);
|
||||
} while (_map[x][y] != DT_SOLID);
|
||||
|
||||
_map[x][y] = DT_HIDDENDOOR;
|
||||
}
|
||||
} while (!isValid);
|
||||
|
||||
// Add monsters
|
||||
_monsters.clear();
|
||||
for (i = 1; i <= MAX_MONSTERS; ++i)
|
||||
addMonster(player, i);
|
||||
}
|
||||
|
||||
int DungeonMapInfo::generateContent(int c) {
|
||||
if (RND() > .95) c = DT_TRAP;
|
||||
if (RND() > .6) c = DT_HIDDENDOOR;
|
||||
if (RND() > .6) c = DT_DOOR;
|
||||
if (RND() > .97) c = DT_PIT;
|
||||
if (RND() > .94) c = DT_GOLD;
|
||||
return c;
|
||||
}
|
||||
|
||||
void DungeonMapInfo::addMonster(const PlayerInfo &player, int type) {
|
||||
int x, y;
|
||||
int level = MONSTER_INFO[type]._level;
|
||||
|
||||
// Limit monsters to levels
|
||||
if (level - 2 > player._level)
|
||||
return;
|
||||
|
||||
// Not always there anyway
|
||||
if (RND() > 0.6)
|
||||
return;
|
||||
|
||||
// Find a place for it. Must be empty, not player
|
||||
do {
|
||||
x = urand() % DUNGEON_MAP_SIZE;
|
||||
y = urand() % DUNGEON_MAP_SIZE;
|
||||
} while (_map[x][y] != DT_SPACE ||
|
||||
(x == player._dungeonPos.x && y == player._dungeonPos.y));
|
||||
|
||||
addMonsterAtPos(player, Common::Point(x, y), type);
|
||||
}
|
||||
|
||||
void DungeonMapInfo::addMonsterAtPos(const PlayerInfo &player, const Common::Point &pt, int type) {
|
||||
int level = MONSTER_INFO[type]._level;
|
||||
|
||||
// Fill in details
|
||||
MonsterEntry m;
|
||||
m._type = type;
|
||||
m._strength = level + 3 + player._level;
|
||||
m._alive = true;
|
||||
|
||||
// Record position
|
||||
m._loc = pt;
|
||||
|
||||
_monsters.push_back(m);
|
||||
}
|
||||
|
||||
void DungeonMapInfo::synchronize(Common::Serializer &s) {
|
||||
// Map data
|
||||
for (int y = 0; y < DUNGEON_MAP_SIZE; ++y)
|
||||
for (int x = 0; x < DUNGEON_MAP_SIZE; ++x)
|
||||
s.syncAsByte(_map[x][y]);
|
||||
|
||||
// Monsters
|
||||
uint count = _monsters.size();
|
||||
s.syncAsByte(count);
|
||||
if (s.isLoading())
|
||||
_monsters.resize(count);
|
||||
|
||||
for (auto &m : _monsters)
|
||||
m.synchronize(s);
|
||||
}
|
||||
|
||||
int DungeonMapInfo::findMonster(const Common::Point &c) const {
|
||||
int n = -1;
|
||||
|
||||
for (uint i = 0; i < _monsters.size(); i++) {
|
||||
const auto &m = _monsters[i];
|
||||
if (m._loc == c && m._alive)
|
||||
n = i;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
void MonsterEntry::synchronize(Common::Serializer &s) {
|
||||
s.syncAsByte(_loc.x);
|
||||
s.syncAsByte(_loc.y);
|
||||
s.syncAsByte(_type);
|
||||
s.syncAsByte(_strength);
|
||||
s.syncAsByte(_alive);
|
||||
}
|
||||
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
146
engines/ultima/ultima0/data/data.h
Normal file
146
engines/ultima/ultima0/data/data.h
Normal file
@@ -0,0 +1,146 @@
|
||||
/* 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 ULTIMA0_DATA_H
|
||||
#define ULTIMA0_DATA_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/keyboard.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/serializer.h"
|
||||
#include "ultima/ultima0/data/defines.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
|
||||
enum Direction { DIR_NORTH, DIR_EAST, DIR_SOUTH, DIR_WEST };
|
||||
|
||||
struct PlayerInfo;
|
||||
|
||||
struct ObjectInfo {
|
||||
const char *_name;
|
||||
int _cost;
|
||||
int _maxDamage;
|
||||
int _action;
|
||||
};
|
||||
struct MonsterInfo {
|
||||
const char *_name;
|
||||
int _level;
|
||||
};
|
||||
|
||||
extern const ObjectInfo OBJECT_INFO[];
|
||||
extern const MonsterInfo MONSTER_INFO[];
|
||||
extern const char *ATTRIB_NAMES[];
|
||||
extern const char *const DIRECTION_NAMES[];
|
||||
|
||||
/**
|
||||
* Monster structure
|
||||
*/
|
||||
struct MonsterEntry {
|
||||
Common::Point _loc; // Position
|
||||
int _type = 0; // Monster type
|
||||
int _strength = 0; // Strength
|
||||
bool _alive = false; // Alive flag
|
||||
|
||||
void synchronize(Common::Serializer &s);
|
||||
};
|
||||
|
||||
/**
|
||||
* Dungeon Map Structure
|
||||
*/
|
||||
struct DungeonMapInfo {
|
||||
private:
|
||||
void addMonster(const PlayerInfo &player, int type);
|
||||
int generateContent(int c);
|
||||
|
||||
public:
|
||||
byte _map[DUNGEON_MAP_SIZE][DUNGEON_MAP_SIZE] = {}; // Map information
|
||||
Common::Array<MonsterEntry> _monsters; // Monster records
|
||||
|
||||
void create(const PlayerInfo &player);
|
||||
void synchronize(Common::Serializer &s);
|
||||
|
||||
/**
|
||||
* Find Monster ID at given location
|
||||
*/
|
||||
int findMonster(const Common::Point &c) const;
|
||||
|
||||
void addMonsterAtPos(const PlayerInfo &player, const Common::Point &pt, int type);
|
||||
};
|
||||
|
||||
/**
|
||||
* Player structure
|
||||
*/
|
||||
struct PlayerInfo {
|
||||
char _name[MAX_NAME + 1] = {}; // Player Name
|
||||
Common::Point _worldPos; // World map position
|
||||
Common::Point _dungeonPos; // Dungeon map position
|
||||
Common::Point _dungeonDir; // Dungeon direction facing
|
||||
byte _class = '?'; // Player class (F or M)
|
||||
int _hpGain = 0; // HPs gained in dungeon
|
||||
int _level = 0; // Dungeon level, 0 = world map
|
||||
int _skill = 0; // Skill level
|
||||
int _task = 0; // Task set (-1 = none)
|
||||
bool _taskCompleted = 0; // Task completed
|
||||
uint32 _luckyNumber = 0; // Value used for seeding
|
||||
int _attr[MAX_ATTR] = {}; // Attribute values
|
||||
double _object[MAX_OBJ] = {}; // Object counts
|
||||
|
||||
void init();
|
||||
void rollAttributes();
|
||||
void synchronize(Common::Serializer &s);
|
||||
|
||||
/**
|
||||
* Return the dungeon facing direction
|
||||
*/
|
||||
Direction dungeonDir() const;
|
||||
|
||||
/**
|
||||
* Sets the dungeon direction
|
||||
*/
|
||||
void setDungeonDir(Direction newDir);
|
||||
|
||||
/**
|
||||
* Turn left in the dungeon
|
||||
*/
|
||||
void dungeonTurnLeft();
|
||||
|
||||
/**
|
||||
* Turn right in the dungeon
|
||||
*/
|
||||
void dungeonTurnRight();
|
||||
};
|
||||
|
||||
/**
|
||||
* World Map structure
|
||||
*/
|
||||
struct WorldMapInfo {
|
||||
byte _map[WORLD_MAP_SIZE][WORLD_MAP_SIZE] = {}; // Map information
|
||||
|
||||
void init(PlayerInfo &p);
|
||||
int read(int x, int y) const;
|
||||
void synchronize(Common::Serializer &s);
|
||||
};
|
||||
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
|
||||
#endif
|
||||
133
engines/ultima/ultima0/data/defines.h
Normal file
133
engines/ultima/ultima0/data/defines.h
Normal file
@@ -0,0 +1,133 @@
|
||||
/* 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 ULTIMA0_DATA_DEFINES_H
|
||||
#define ULTIMA0_DATA_DEFINES_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
|
||||
constexpr int DEFAULT_SCX = 640; // Default Screen Size and Depth
|
||||
constexpr int DEFAULT_SCY = 400;
|
||||
|
||||
constexpr int WORLD_MAP_SIZE = 21; // Size of world map
|
||||
constexpr int DUNGEON_MAP_SIZE = 11; // Size of dungeon map
|
||||
constexpr int MAX_MONSTERS = 10; // Number of Monsters
|
||||
constexpr int MAX_ATTR = 6; // Attributes
|
||||
constexpr int MAX_OBJ = 6; // Objects
|
||||
constexpr int WORLD_GRID_SIZE = 3; // Visible part of map is axa
|
||||
constexpr int MAX_NAME = 8; // Max size player name
|
||||
constexpr int MAX_VIEW_DEPTH = 9; // Max viewing depth
|
||||
|
||||
constexpr int MINIMAP_TILE_SIZE = 5;
|
||||
constexpr int WORLD_MINIMAP_SIZE = WORLD_MAP_SIZE * MINIMAP_TILE_SIZE;
|
||||
constexpr int DUNGEON_MINIMAP_SIZE = DUNGEON_MAP_SIZE * MINIMAP_TILE_SIZE;
|
||||
|
||||
#define RND_MAX 0x7fffffff
|
||||
#define RND() (((double)g_engine->getRandomNumber())/RND_MAX)
|
||||
#define urand() g_engine->getRandomNumber()
|
||||
#define AKVERSION (1.000) // Version number
|
||||
|
||||
// Convert RGB to Colour Code
|
||||
#define RGB(r,g,b) ((r?4:0)+(g?2:0)+(b?1:0))
|
||||
|
||||
#define C_BLACK RGB(0,0,0) // Some Colours
|
||||
#define C_RED RGB(1,0,0)
|
||||
#define C_GREEN RGB(0,1,0)
|
||||
#define C_BLUE RGB(0,0,1)
|
||||
#define C_YELLOW RGB(1,1,0)
|
||||
#define C_WHITE RGB(1,1,1)
|
||||
#define C_CYAN RGB(0,1,1)
|
||||
#define C_PURPLE RGB(1,0,1)
|
||||
#define C_ROSE 8
|
||||
#define C_VIOLET 9
|
||||
#define C_GREY 10
|
||||
#define C_TOMATO 11
|
||||
|
||||
#define C_TEXT_DEFAULT C_CYAN
|
||||
|
||||
#define WT_SPACE (0) // World Tiles
|
||||
#define WT_MOUNTAIN (1)
|
||||
#define WT_TREE (2)
|
||||
#define WT_TOWN (3)
|
||||
#define WT_DUNGEON (4)
|
||||
#define WT_BRITISH (5)
|
||||
#define WT_PLAYER (-1) // Used for the player graphic
|
||||
|
||||
#define DT_SPACE (0) // Dungeon tiles
|
||||
#define DT_SOLID (1)
|
||||
#define DT_TRAP (2)
|
||||
#define DT_HIDDENDOOR (3)
|
||||
#define DT_DOOR (4)
|
||||
#define DT_GOLD (5)
|
||||
#define DT_LADDERDN (7)
|
||||
#define DT_LADDERUP (8)
|
||||
#define DT_PIT (9)
|
||||
|
||||
#define ISWALKTHRU(x) ((x) != DT_SOLID) // Tests for them
|
||||
#define ISDRAWWALL(x) ((x) == DT_SOLID || (x) == DT_HIDDENDOOR)
|
||||
#define ISDRAWDOOR(x) ((x) == DT_DOOR)
|
||||
#define ISDRAWOPEN(x) (ISDRAWWALL(x) == 0 && ISDRAWDOOR(x) == 0)
|
||||
|
||||
// Object Colours
|
||||
#define COL_WALL (g_engine->_player._level == 1 ? C_WHITE : C_BLUE)
|
||||
#define COL_LADDER (C_RED)
|
||||
#define COL_DOOR (C_BLUE)
|
||||
#define COL_HOLE (C_RED)
|
||||
#define COL_MONSTER (C_WHITE)
|
||||
#define COL_MOUNTAIN (C_YELLOW)
|
||||
#define COL_TREE (C_GREEN)
|
||||
#define COL_DUNGEON (C_RED)
|
||||
#define COL_TOWN (C_BLUE)
|
||||
#define COL_BRITISH (C_WHITE)
|
||||
#define COL_PLAYER (C_CYAN)
|
||||
|
||||
#define MN_SKELETON (1) // Monster types
|
||||
#define MN_THIEF (2)
|
||||
#define MN_RAT (3)
|
||||
#define MN_ORC (4)
|
||||
#define MN_VIPER (5)
|
||||
#define MN_CARRION (6)
|
||||
#define MN_GREMLIN (7)
|
||||
#define MN_MIMIC (8)
|
||||
#define MN_DAEMON (9)
|
||||
#define MN_BALROG (10)
|
||||
|
||||
#define AT_HP (0) // Player attributes
|
||||
#define AT_STRENGTH (1)
|
||||
#define AT_DEXTERITY (2)
|
||||
#define AT_STAMINA (3)
|
||||
#define AT_WISDOM (4)
|
||||
#define AT_GOLD (5)
|
||||
|
||||
#define OB_FOOD (0) // Object Attributes
|
||||
#define OB_RAPIER (1)
|
||||
#define OB_AXE (2)
|
||||
#define OB_SHIELD (3)
|
||||
#define OB_BOW (4)
|
||||
#define OB_AMULET (5)
|
||||
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
|
||||
#endif
|
||||
203
engines/ultima/ultima0/data/monster_logic.cpp
Normal file
203
engines/ultima/ultima0/data/monster_logic.cpp
Normal 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ultima/ultima0/data/monster_logic.h"
|
||||
#include "ultima/ultima0/ultima0.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
|
||||
void MonsterLogic::checkForAttacks(PlayerInfo &p, DungeonMapInfo &d) {
|
||||
int attacked;
|
||||
double dist;
|
||||
|
||||
// Go through all monsters
|
||||
for (MonsterEntry &m : d._monsters) {
|
||||
dist = pow(m._loc.x - p._dungeonPos.x, 2); // Calculate Distance
|
||||
dist = dist + pow(m._loc.y - p._dungeonPos.y, 2);
|
||||
dist = sqrt(dist);
|
||||
|
||||
// If alive
|
||||
if (m._alive) {
|
||||
attacked = 0;
|
||||
|
||||
// If within range
|
||||
if (dist < 1.3)
|
||||
attacked = attack(m, p);
|
||||
|
||||
// If didn't attack, then move
|
||||
if (attacked == 0) {
|
||||
// Mimics only if near enough
|
||||
if (m._type != MN_MIMIC || dist >= 3.0)
|
||||
move(m, p, d);
|
||||
|
||||
// Recovers if didn't attack
|
||||
if (m._strength < p._level * p._skill)
|
||||
m._strength = m._strength + p._level;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MonsterLogic::showLines(const Common::String &msg) {
|
||||
g_events->send("DungeonStatus", GameMessage("LINES", msg));
|
||||
}
|
||||
|
||||
int MonsterLogic::attack(MonsterEntry &m, PlayerInfo &p) {
|
||||
int n;
|
||||
|
||||
Common::String msg = "You are being attacked\nby a ";
|
||||
msg += (char)C_BLUE;
|
||||
msg += MONSTER_INFO[m._type]._name;
|
||||
msg += (char)C_TEXT_DEFAULT;
|
||||
msg += '\n';
|
||||
|
||||
// Special case for Gremlin/Thief stealing
|
||||
if (m._type == MN_GREMLIN || m._type == MN_THIEF)
|
||||
if (RND() > 0.5)
|
||||
// Half the time
|
||||
return steal(msg, m, p);
|
||||
|
||||
n = urand() % 20; // Calculate hit chance
|
||||
if (p._object[OB_SHIELD] > 0) n--;
|
||||
n = n - p._attr[AT_STAMINA];
|
||||
n = n + m._type + p._level;
|
||||
|
||||
if (n < 0) {
|
||||
// Missed
|
||||
msg += (char)C_TOMATO;
|
||||
msg += "Missed!";
|
||||
} else {
|
||||
// Hit
|
||||
n = urand() % m._type; // Calculate damage done.
|
||||
n = n + p._level;
|
||||
p._attr[AT_HP] -= n; // Adjust hit points
|
||||
|
||||
msg += (char)C_TOMATO;
|
||||
msg += "Hit! ";
|
||||
msg += (char)C_TEXT_DEFAULT;
|
||||
msg += " Damage = ";
|
||||
msg += (char)C_BLUE;
|
||||
msg += Common::String::format("%d", n);
|
||||
}
|
||||
|
||||
showLines(msg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void MonsterLogic::move(MonsterEntry &m, PlayerInfo &p, DungeonMapInfo &d) {
|
||||
int x, y, xi, yi;
|
||||
|
||||
// Calculate direction
|
||||
xi = yi = 0;
|
||||
if (p._dungeonPos.x != m._loc.x)
|
||||
xi = (p._dungeonPos.x > m._loc.x) ? 1 : -1;
|
||||
if (p._dungeonPos.y != m._loc.y)
|
||||
yi = (p._dungeonPos.y > m._loc.y) ? 1 : -1;
|
||||
|
||||
// Running away
|
||||
if (m._strength < p._level * p._skill) {
|
||||
xi = -xi; yi = -yi;
|
||||
}
|
||||
|
||||
// Get position
|
||||
x = m._loc.x; y = m._loc.y;
|
||||
|
||||
// Check move okay
|
||||
if (ABS(xi) > ABS(yi)) {
|
||||
if (canMoveTo(d, x + xi, yi)) yi = 0;
|
||||
else if (canMoveTo(d, x, y + yi)) xi = 0;
|
||||
} else {
|
||||
if (canMoveTo(d, x, y + yi)) xi = 0;
|
||||
else if (canMoveTo(d, x + xi, yi)) yi = 0;
|
||||
}
|
||||
|
||||
if (xi == 0 && yi == 0)
|
||||
return; // No move
|
||||
|
||||
x = x + xi; y = y + yi; // Work out new position
|
||||
if (!canMoveTo(d, x, y)) // Fail if can't move there
|
||||
return;
|
||||
if (x == p._dungeonPos.x && // Can't move onto us
|
||||
y == p._dungeonPos.y) return;
|
||||
|
||||
// Move to new position
|
||||
m._loc.x = x; m._loc.y = y;
|
||||
|
||||
// If the tile was for a hidden door, flag it as a normal visible door
|
||||
if (d._map[x][y] == DT_HIDDENDOOR)
|
||||
d._map[x][y] = DT_DOOR;
|
||||
}
|
||||
|
||||
bool MonsterLogic::canMoveTo(DungeonMapInfo &d, int x, int y) {
|
||||
Common::Point c;
|
||||
int t = d._map[x][y]; // See what's there
|
||||
if (!ISWALKTHRU(t))
|
||||
return 0; // Can't walk through walls
|
||||
c.x = x; c.y = y; // Set up coord structure
|
||||
|
||||
// True if no monster here
|
||||
return d.findMonster(c) < 0;
|
||||
}
|
||||
|
||||
int MonsterLogic::steal(const Common::String &attackStr, MonsterEntry &m, PlayerInfo &p) {
|
||||
int n;
|
||||
const char *s1, *s2;
|
||||
|
||||
Common::String msg = attackStr;
|
||||
msg += (char)C_GREEN;
|
||||
msg += "A ";
|
||||
msg += MONSTER_INFO[m._type]._name;
|
||||
msg += " stole ";
|
||||
|
||||
if (m._type == MN_GREMLIN) {
|
||||
// HALVES the food.... aargh
|
||||
p._object[OB_FOOD] = floor(p._object[OB_FOOD]) / 2.0;
|
||||
msg += "some ";
|
||||
msg += (char)C_BLUE;
|
||||
msg += "Food";
|
||||
showLines(msg);
|
||||
|
||||
} else if (m._type == MN_THIEF) {
|
||||
// Figure out what stolen
|
||||
do {
|
||||
n = urand() % MAX_OBJ;
|
||||
} while (p._object[n] == 0);
|
||||
|
||||
p._object[n]--; // Stole one
|
||||
s2 = OBJECT_INFO[n]._name;
|
||||
s1 = "a";
|
||||
|
||||
if (strchr("aeiou", tolower(*s2))) s1 = "an";
|
||||
if (n == 0) s1 = "some";
|
||||
|
||||
msg += s1;
|
||||
msg += ' ';
|
||||
msg += (char)C_BLUE;
|
||||
msg += s2;
|
||||
showLines(msg);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
67
engines/ultima/ultima0/data/monster_logic.h
Normal file
67
engines/ultima/ultima0/data/monster_logic.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ULTIMA0_MONSTER_LOGIC_H
|
||||
#define ULTIMA0_MONSTER_LOGIC_H
|
||||
|
||||
#include "ultima/ultima0/data/data.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
|
||||
class MonsterLogic {
|
||||
private:
|
||||
/**
|
||||
* Shows a message in the dungeon status area
|
||||
*/
|
||||
static void showLines(const Common::String &msg);
|
||||
|
||||
/**
|
||||
* Monster Attacks
|
||||
*/
|
||||
static int attack(MonsterEntry &m, PlayerInfo &p);
|
||||
|
||||
/**
|
||||
* Monster Moves
|
||||
*/
|
||||
static void move(MonsterEntry &m, PlayerInfo &p, DungeonMapInfo &d);
|
||||
|
||||
/**
|
||||
* Can monster move to a square
|
||||
*/
|
||||
static bool canMoveTo(DungeonMapInfo &d, int x, int y);
|
||||
|
||||
/**
|
||||
* Monster Stealing
|
||||
*/
|
||||
static int steal(const Common::String &attackStr, MonsterEntry &m, PlayerInfo &p);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Check Monsters Attacking
|
||||
*/
|
||||
static void checkForAttacks(PlayerInfo &p, DungeonMapInfo &d);
|
||||
};
|
||||
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
|
||||
#endif
|
||||
382
engines/ultima/ultima0/events.cpp
Normal file
382
engines/ultima/ultima0/events.cpp
Normal file
@@ -0,0 +1,382 @@
|
||||
/* 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/system.h"
|
||||
#include "common/config-manager.h"
|
||||
#include "graphics/cursorman.h"
|
||||
#include "graphics/screen.h"
|
||||
#include "ultima/ultima0/events.h"
|
||||
#include "ultima/ultima0/gfx/gfx_surface.h"
|
||||
#include "ultima/ultima0/views/views.h"
|
||||
#include "ultima/ultima0/ultima0.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
|
||||
Events *g_events;
|
||||
|
||||
constexpr int CURSOR_W = 12;
|
||||
constexpr int CURSOR_H = 20;
|
||||
|
||||
static const byte ARROW_CURSOR[CURSOR_W * CURSOR_H] = {
|
||||
0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
0, 7, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
0, 7, 7, 0, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
0, 7, 7, 7, 0, 9, 9, 9, 9, 9, 9, 9,
|
||||
0, 7, 7, 7, 7, 0, 9, 9, 9, 9, 9, 9,
|
||||
0, 7, 7, 7, 7, 7, 0, 9, 9, 9, 9, 9,
|
||||
0, 7, 7, 7, 7, 7, 7, 0, 9, 9, 9, 9,
|
||||
0, 7, 7, 7, 7, 7, 7, 7, 0, 9, 9, 9,
|
||||
0, 7, 7, 7, 7, 7, 7, 7, 7, 0, 9, 9,
|
||||
0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 9,
|
||||
0, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0,
|
||||
0, 7, 7, 7, 0, 7, 7, 0, 9, 9, 9, 9,
|
||||
0, 7, 7, 0, 0, 7, 7, 0, 9, 9, 9, 9,
|
||||
0, 7, 0, 9, 9, 0, 7, 7, 0, 9, 9, 9,
|
||||
0, 0, 9, 9, 9, 0, 7, 7, 0, 9, 9, 9,
|
||||
0, 9, 9, 9, 9, 9, 0, 7, 7, 0, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 0, 7, 7, 0, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 0, 7, 7, 0, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 0, 7, 7, 0, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9
|
||||
};
|
||||
|
||||
Events::Events() : UIElement("Root", nullptr) {
|
||||
g_events = this;
|
||||
}
|
||||
|
||||
Events::~Events() {
|
||||
g_events = nullptr;
|
||||
}
|
||||
|
||||
void Events::runGame() {
|
||||
uint currTime, nextFrameTime = 0;
|
||||
_screen = new Graphics::Screen();
|
||||
Views::Views views; // Loads all views in the structure
|
||||
|
||||
CursorMan.pushCursor(ARROW_CURSOR, CURSOR_W, CURSOR_H, 0, 0, 9);
|
||||
|
||||
// Run the game
|
||||
int saveSlot = ConfMan.getInt("save_slot");
|
||||
if (saveSlot == -1 || g_engine->loadGameState(saveSlot).getCode() != Common::kNoError)
|
||||
// Except when loading a savegame from the launcher, default to first screen
|
||||
addView("Startup");
|
||||
|
||||
Common::Event e;
|
||||
while (!_views.empty() && !shouldQuit()) {
|
||||
while (g_system->getEventManager()->pollEvent(e)) {
|
||||
if (e.type == Common::EVENT_QUIT ||
|
||||
e.type == Common::EVENT_RETURN_TO_LAUNCHER) {
|
||||
_views.clear();
|
||||
break;
|
||||
} else {
|
||||
processEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (_views.empty())
|
||||
break;
|
||||
|
||||
g_system->delayMillis(10);
|
||||
if ((currTime = g_system->getMillis()) >= nextFrameTime) {
|
||||
nextFrameTime = currTime + FRAME_DELAY;
|
||||
tick();
|
||||
drawElements();
|
||||
_screen->update();
|
||||
}
|
||||
}
|
||||
|
||||
delete _screen;
|
||||
}
|
||||
|
||||
void Events::processEvent(Common::Event &ev) {
|
||||
switch (ev.type) {
|
||||
case Common::EVENT_KEYDOWN:
|
||||
CursorMan.showMouse(false);
|
||||
if (ev.kbd.keycode < Common::KEYCODE_NUMLOCK)
|
||||
msgKeypress(KeypressMessage(ev.kbd));
|
||||
break;
|
||||
case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
|
||||
CursorMan.showMouse(false);
|
||||
msgAction(ActionMessage(ev.customType));
|
||||
break;
|
||||
case Common::EVENT_LBUTTONDOWN:
|
||||
case Common::EVENT_RBUTTONDOWN:
|
||||
case Common::EVENT_MBUTTONDOWN:
|
||||
CursorMan.showMouse(true);
|
||||
msgMouseDown(MouseDownMessage(ev.type, ev.mouse));
|
||||
break;
|
||||
case Common::EVENT_LBUTTONUP:
|
||||
case Common::EVENT_RBUTTONUP:
|
||||
case Common::EVENT_MBUTTONUP:
|
||||
CursorMan.showMouse(true);
|
||||
msgMouseUp(MouseUpMessage(ev.type, ev.mouse));
|
||||
break;
|
||||
case Common::EVENT_MOUSEMOVE:
|
||||
CursorMan.showMouse(true);
|
||||
msgMouseMove(MouseMoveMessage(ev.type, ev.mouse));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Events::replaceView(UIElement *ui, bool replaceAllViews) {
|
||||
assert(ui);
|
||||
UIElement *priorView = focusedView();
|
||||
|
||||
if (replaceAllViews) {
|
||||
clearViews();
|
||||
|
||||
} else if (!_views.empty()) {
|
||||
priorView->msgUnfocus(UnfocusMessage());
|
||||
_views.pop();
|
||||
}
|
||||
|
||||
_views.push(ui);
|
||||
ui->redraw();
|
||||
ui->msgFocus(FocusMessage(priorView));
|
||||
}
|
||||
|
||||
void Events::replaceView(const Common::String &name, bool replaceAllViews) {
|
||||
replaceView(findView(name));
|
||||
}
|
||||
|
||||
void Events::addView(UIElement *ui) {
|
||||
assert(ui);
|
||||
UIElement *priorView = focusedView();
|
||||
|
||||
if (!_views.empty())
|
||||
priorView->msgUnfocus(UnfocusMessage());
|
||||
|
||||
_views.push(ui);
|
||||
ui->redraw();
|
||||
ui->msgFocus(FocusMessage(priorView));
|
||||
}
|
||||
|
||||
void Events::addView(const Common::String &name) {
|
||||
addView(findView(name));
|
||||
}
|
||||
|
||||
void Events::popView() {
|
||||
UIElement *priorView = focusedView();
|
||||
priorView->msgUnfocus(UnfocusMessage());
|
||||
_views.pop();
|
||||
|
||||
for (int i = 0; i < (int)_views.size() - 1; ++i) {
|
||||
_views[i]->redraw();
|
||||
_views[i]->draw();
|
||||
}
|
||||
|
||||
if (!_views.empty()) {
|
||||
UIElement *view = focusedView();
|
||||
view->msgFocus(FocusMessage(priorView));
|
||||
view->redraw();
|
||||
view->draw();
|
||||
}
|
||||
}
|
||||
|
||||
void Events::redrawViews() {
|
||||
for (uint i = 0; i < _views.size(); ++i) {
|
||||
_views[i]->redraw();
|
||||
_views[i]->draw();
|
||||
}
|
||||
}
|
||||
|
||||
bool Events::isPresent(const Common::String &name) const {
|
||||
for (uint i = 0; i < _views.size(); ++i) {
|
||||
if (_views[i]->_name == name)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Events::clearViews() {
|
||||
if (!_views.empty())
|
||||
focusedView()->msgUnfocus(UnfocusMessage());
|
||||
|
||||
_views.clear();
|
||||
}
|
||||
|
||||
void Events::addKeypress(const Common::KeyCode kc) {
|
||||
Common::KeyState ks;
|
||||
ks.keycode = kc;
|
||||
if (kc >= Common::KEYCODE_SPACE && kc <= Common::KEYCODE_TILDE)
|
||||
ks.ascii = kc;
|
||||
|
||||
focusedView()->msgKeypress(KeypressMessage(ks));
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
Bounds::Bounds(Common::Rect &innerBounds) :
|
||||
_bounds(0, 0, DEFAULT_SCX, DEFAULT_SCY),
|
||||
_innerBounds(innerBounds),
|
||||
left(_bounds.left), top(_bounds.top),
|
||||
right(_bounds.right), bottom(_bounds.bottom) {
|
||||
}
|
||||
|
||||
Bounds &Bounds::operator=(const Common::Rect &r) {
|
||||
_bounds = r;
|
||||
_innerBounds = r;
|
||||
_innerBounds.grow(-_borderSize);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Bounds::setBorderSize(size_t borderSize) {
|
||||
_borderSize = borderSize;
|
||||
_innerBounds = *this;
|
||||
_innerBounds.grow(-_borderSize);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
UIElement::UIElement(const Common::String &name) :
|
||||
_name(name), _parent(g_engine), _bounds(_innerBounds) {
|
||||
g_engine->_children.push_back(this);
|
||||
}
|
||||
|
||||
UIElement::UIElement(const Common::String &name, UIElement *uiParent) :
|
||||
_name(name), _parent(uiParent),
|
||||
_bounds(_innerBounds) {
|
||||
if (_parent)
|
||||
_parent->_children.push_back(this);
|
||||
}
|
||||
|
||||
void UIElement::redraw() {
|
||||
_needsRedraw = true;
|
||||
|
||||
for (size_t i = 0; i < _children.size(); ++i)
|
||||
_children[i]->redraw();
|
||||
}
|
||||
|
||||
void UIElement::drawElements() {
|
||||
if (_needsRedraw) {
|
||||
draw();
|
||||
_needsRedraw = false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _children.size(); ++i)
|
||||
_children[i]->drawElements();
|
||||
}
|
||||
|
||||
UIElement *UIElement::findViewGlobally(const Common::String &name) {
|
||||
return g_events->findView(name);
|
||||
}
|
||||
|
||||
void UIElement::focus() {
|
||||
g_events->replaceView(this);
|
||||
}
|
||||
|
||||
void UIElement::close() {
|
||||
assert(g_events->focusedView() == this);
|
||||
g_events->popView();
|
||||
}
|
||||
|
||||
bool UIElement::isFocused() const {
|
||||
return g_events->focusedView() == this;
|
||||
}
|
||||
|
||||
void UIElement::clearSurface() {
|
||||
Graphics::ManagedSurface s = getSurface();
|
||||
s.fillRect(Common::Rect(s.w, s.h), 0);
|
||||
}
|
||||
|
||||
void UIElement::draw() {
|
||||
for (size_t i = 0; i < _children.size(); ++i) {
|
||||
_children[i]->draw();
|
||||
}
|
||||
}
|
||||
|
||||
bool UIElement::tick() {
|
||||
if (_timeoutCtr && --_timeoutCtr == 0) {
|
||||
timeout();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _children.size(); ++i) {
|
||||
if (_children[i]->tick())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
UIElement *UIElement::findView(const Common::String &name) {
|
||||
if (_name.equalsIgnoreCase(name))
|
||||
return this;
|
||||
|
||||
UIElement *result;
|
||||
for (size_t i = 0; i < _children.size(); ++i) {
|
||||
if ((result = _children[i]->findView(name)) != nullptr)
|
||||
return result;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void UIElement::replaceView(UIElement *ui, bool replaceAllViews) {
|
||||
g_events->replaceView(ui, replaceAllViews);
|
||||
}
|
||||
|
||||
void UIElement::replaceView(const Common::String &name, bool replaceAllViews) {
|
||||
g_events->replaceView(name, replaceAllViews);
|
||||
}
|
||||
|
||||
void UIElement::addView(UIElement *ui) {
|
||||
g_events->addView(ui);
|
||||
}
|
||||
|
||||
void UIElement::addView(const Common::String &name) {
|
||||
g_events->addView(name);
|
||||
}
|
||||
|
||||
void UIElement::addView() {
|
||||
g_events->addView(this);
|
||||
}
|
||||
|
||||
Gfx::GfxSurface UIElement::getSurface() const {
|
||||
return Gfx::GfxSurface(*g_events->getScreen(), _bounds);
|
||||
}
|
||||
|
||||
int UIElement::getRandomNumber(int minNumber, int maxNumber) {
|
||||
return g_engine->getRandomNumber(maxNumber - minNumber + 1) + minNumber;
|
||||
}
|
||||
|
||||
int UIElement::getRandomNumber(int maxNumber) {
|
||||
return g_engine->getRandomNumber(maxNumber);
|
||||
}
|
||||
|
||||
void UIElement::delaySeconds(uint seconds) {
|
||||
_timeoutCtr = seconds * FRAME_RATE;
|
||||
}
|
||||
|
||||
void UIElement::delayFrames(uint frames) {
|
||||
_timeoutCtr = frames;
|
||||
}
|
||||
|
||||
void UIElement::timeout() {
|
||||
redraw();
|
||||
}
|
||||
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
|
||||
425
engines/ultima/ultima0/events.h
Normal file
425
engines/ultima/ultima0/events.h
Normal file
@@ -0,0 +1,425 @@
|
||||
/* 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 ULTIMA0_EVENTS_H
|
||||
#define ULTIMA0_EVENTS_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/stack.h"
|
||||
#include "graphics/screen.h"
|
||||
#include "ultima/ultima0/messages.h"
|
||||
#include "ultima/ultima0/gfx/gfx_surface.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
|
||||
#define FRAME_RATE 20
|
||||
#define FRAME_DELAY (1000 / FRAME_RATE)
|
||||
|
||||
class Events;
|
||||
|
||||
/**
|
||||
* Implements a thunk layer around an element's bounds,
|
||||
* allowing access to it as if it were a simple Common::Rect,
|
||||
* but any changes to it will also be applied to a linked inner bounds
|
||||
*/
|
||||
struct Bounds {
|
||||
private:
|
||||
Common::Rect _bounds;
|
||||
Common::Rect &_innerBounds;
|
||||
int _borderSize = 0;
|
||||
public:
|
||||
const int16 &left;
|
||||
const int16 ⊤
|
||||
const int16 &right;
|
||||
const int16 ⊥
|
||||
public:
|
||||
Bounds(Common::Rect &innerBounds);
|
||||
operator const Common::Rect &() const {
|
||||
return _bounds;
|
||||
}
|
||||
Bounds &operator=(const Common::Rect &r);
|
||||
void setBorderSize(size_t borderSize);
|
||||
size_t borderSize() const {
|
||||
return _borderSize;
|
||||
}
|
||||
int16 width() const {
|
||||
return _bounds.width();
|
||||
}
|
||||
int16 height() const {
|
||||
return _bounds.height();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* User interface element
|
||||
*/
|
||||
class UIElement {
|
||||
friend class Events;
|
||||
private:
|
||||
int _timeoutCtr = 0;
|
||||
protected:
|
||||
UIElement *_parent;
|
||||
Common::Array<UIElement *> _children;
|
||||
Common::Rect _innerBounds;
|
||||
Bounds _bounds;
|
||||
bool _needsRedraw = true;
|
||||
Common::String _name;
|
||||
protected:
|
||||
/**
|
||||
* Set a delay countdown in seconds, after which timeout() is called
|
||||
*/
|
||||
void delaySeconds(uint seconds);
|
||||
|
||||
/**
|
||||
* Set a delay countdown in frames, after which timeout() is called
|
||||
*/
|
||||
void delayFrames(uint frames);
|
||||
|
||||
/**
|
||||
* Returns true if a delay is active
|
||||
*/
|
||||
bool isDelayActive() const {
|
||||
return _timeoutCtr != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels any active delay
|
||||
*/
|
||||
void cancelDelay() {
|
||||
_timeoutCtr = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an active timeout countdown expired
|
||||
*/
|
||||
virtual void timeout();
|
||||
|
||||
private:
|
||||
/**
|
||||
* Outer method for doing drawing
|
||||
*
|
||||
*/
|
||||
void drawElements();
|
||||
|
||||
/**
|
||||
* Finds a view globally
|
||||
*/
|
||||
static UIElement *findViewGlobally(const Common::String &name);
|
||||
public:
|
||||
UIElement(const Common::String &name, UIElement *uiParent);
|
||||
UIElement(const Common::String &name);
|
||||
virtual ~UIElement() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the elements needs to be redrawn
|
||||
*/
|
||||
bool needsRedraw() const {
|
||||
return _needsRedraw;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets that the element needs to be redrawn
|
||||
*/
|
||||
void redraw();
|
||||
|
||||
/**
|
||||
* Focuses the element as the current view
|
||||
*/
|
||||
void focus();
|
||||
|
||||
/**
|
||||
* Closes the current view. The view must have been added
|
||||
* via addView, so there's a remaining view afterwards
|
||||
*/
|
||||
virtual void close();
|
||||
|
||||
/*
|
||||
* Returns true if the view is focused
|
||||
*/
|
||||
bool isFocused() const;
|
||||
|
||||
/**
|
||||
* Returns the view name
|
||||
*/
|
||||
Common::String getName() const {
|
||||
return _name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the focus to a new view
|
||||
*/
|
||||
void replaceView(UIElement *ui, bool replaceAllViews = false);
|
||||
void replaceView(const Common::String &name, bool replaceAllViews = false);
|
||||
|
||||
/**
|
||||
* Adds a focused view to the view stack without replacing current one
|
||||
*/
|
||||
void addView(UIElement *ui);
|
||||
void addView(const Common::String &name);
|
||||
void addView();
|
||||
void open() {
|
||||
addView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a random number
|
||||
*/
|
||||
int getRandomNumber(int minNumber, int maxNumber);
|
||||
int getRandomNumber(int maxNumber);
|
||||
|
||||
/**
|
||||
* Sets the element's bounds
|
||||
*/
|
||||
virtual void setBounds(const Common::Rect &r) {
|
||||
_bounds = r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the element's bounds
|
||||
*/
|
||||
Common::Rect getBounds() const {
|
||||
return _bounds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a surface for drawing the element
|
||||
*/
|
||||
Gfx::GfxSurface getSurface() const;
|
||||
|
||||
/**
|
||||
* Clear the surface
|
||||
*/
|
||||
virtual void clearSurface();
|
||||
|
||||
/**
|
||||
* Draws the element
|
||||
*/
|
||||
virtual void draw();
|
||||
|
||||
/**
|
||||
* Called for game frame ticks
|
||||
*/
|
||||
virtual bool tick();
|
||||
|
||||
/**
|
||||
* Find a view by name
|
||||
*/
|
||||
virtual UIElement *findView(const Common::String &name);
|
||||
|
||||
/**
|
||||
* Handles events
|
||||
*/
|
||||
// Mouse move only has a minimal implementation for performance reasons
|
||||
protected:
|
||||
virtual bool msgMouseMove(const MouseMoveMessage &msg) {
|
||||
return false;
|
||||
}
|
||||
public:
|
||||
bool send(const MouseMoveMessage &msg) {
|
||||
return msgMouseMove(msg);
|
||||
}
|
||||
|
||||
#define MESSAGE(NAME) \
|
||||
protected: \
|
||||
virtual bool msg##NAME(const NAME##Message &e) { \
|
||||
for (Common::Array<UIElement *>::iterator it = _children.begin(); \
|
||||
it != _children.end(); ++it) { \
|
||||
if ((*it)->msg##NAME(e)) return true; \
|
||||
} \
|
||||
return false; \
|
||||
} \
|
||||
public: \
|
||||
bool send(const Common::String &viewName, const NAME##Message &msg) { \
|
||||
UIElement *view = UIElement::findViewGlobally(viewName); \
|
||||
assert(view); \
|
||||
return view->msg##NAME(msg); \
|
||||
} \
|
||||
bool send(const NAME##Message &msg) { \
|
||||
return msg##NAME(msg); \
|
||||
} \
|
||||
|
||||
MESSAGE(Focus);
|
||||
MESSAGE(Unfocus);
|
||||
MESSAGE(MouseEnter);
|
||||
MESSAGE(MouseLeave);
|
||||
MESSAGE(Keypress);
|
||||
MESSAGE(MouseDown);
|
||||
MESSAGE(MouseUp);
|
||||
MESSAGE(Action);
|
||||
MESSAGE(Game);
|
||||
MESSAGE(Value);
|
||||
#undef MESSAGE
|
||||
};
|
||||
|
||||
/**
|
||||
* Main events and view manager. This is kept separate from the engine
|
||||
* class because the engine may add a lot of globals and bring in other
|
||||
* classes. So to save on compilation time, classes that only need to
|
||||
* access basic view management methods like addView or replaceView
|
||||
* only need to include events.h rather than the whole engine.
|
||||
*/
|
||||
class Events : public UIElement {
|
||||
private:
|
||||
Graphics::Screen *_screen = nullptr;
|
||||
Common::Stack<UIElement *> _views;
|
||||
protected:
|
||||
/**
|
||||
* Process an event
|
||||
*/
|
||||
void processEvent(Common::Event &ev);
|
||||
|
||||
/**
|
||||
* Returns true if the game should quit
|
||||
*/
|
||||
virtual bool shouldQuit() const = 0;
|
||||
|
||||
/**
|
||||
* Overrides events we want to only go to the focused view
|
||||
*/
|
||||
#define MESSAGE(NAME) \
|
||||
bool msg##NAME(const NAME##Message &e) override { \
|
||||
return !_views.empty() ? focusedView()->msg##NAME(e) : false; \
|
||||
}
|
||||
MESSAGE(Action);
|
||||
MESSAGE(Focus);
|
||||
MESSAGE(Unfocus);
|
||||
MESSAGE(MouseEnter);
|
||||
MESSAGE(MouseLeave);
|
||||
MESSAGE(Keypress);
|
||||
MESSAGE(MouseDown);
|
||||
MESSAGE(MouseUp);
|
||||
MESSAGE(MouseMove);
|
||||
#undef MESSAGE
|
||||
public:
|
||||
Events();
|
||||
virtual ~Events();
|
||||
|
||||
/**
|
||||
* Main game loop
|
||||
*/
|
||||
void runGame();
|
||||
|
||||
/**
|
||||
* Sets the focus to a new view
|
||||
*/
|
||||
void replaceView(UIElement *ui, bool replaceAllViews = false);
|
||||
void replaceView(const Common::String &name, bool replaceAllViews = false);
|
||||
|
||||
/**
|
||||
* Adds a focused view to the view stack without replacing current one
|
||||
*/
|
||||
void addView(UIElement *ui);
|
||||
void addView(const Common::String &name);
|
||||
|
||||
/**
|
||||
* Clears the view list
|
||||
*/
|
||||
void clearViews();
|
||||
|
||||
/**
|
||||
* Pops a view from the view stack
|
||||
*/
|
||||
void popView();
|
||||
|
||||
/**
|
||||
* Redraws the views in order. This is used in rare cases
|
||||
* where a view draws outside it's defined area, and needs
|
||||
* to restore whether the background was before
|
||||
*/
|
||||
void redrawViews();
|
||||
|
||||
/**
|
||||
* Returns the currently focused view, if any
|
||||
*/
|
||||
UIElement *focusedView() const {
|
||||
return _views.empty() ? nullptr : _views.top();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the view prior to the current view, if any
|
||||
*/
|
||||
UIElement *priorView() const {
|
||||
return _views.size() < 2 ? nullptr :
|
||||
_views[_views.size() - 2];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a view of a given name is present
|
||||
* at all in the visible view stack
|
||||
*/
|
||||
bool isPresent(const Common::String &name) const;
|
||||
|
||||
/**
|
||||
* Returns true if combat is active
|
||||
*/
|
||||
bool isInCombat() const {
|
||||
return isPresent("Combat");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying screen
|
||||
*/
|
||||
Graphics::Screen *getScreen() const {
|
||||
return _screen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the focused view
|
||||
*/
|
||||
void drawElements() {
|
||||
if (!_views.empty())
|
||||
focusedView()->drawElements();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a keypress to the event queue
|
||||
*/
|
||||
void addKeypress(const Common::KeyCode kc);
|
||||
|
||||
/**
|
||||
* Events manager doesn't have any intrinsic drawing
|
||||
*/
|
||||
void draw() override {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called once every game frame
|
||||
*/
|
||||
bool tick() override {
|
||||
return !_views.empty() ? focusedView()->tick() : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calling the close method for g_events closes the active view
|
||||
*/
|
||||
void close() override {
|
||||
focusedView()->close();
|
||||
}
|
||||
};
|
||||
|
||||
extern Events *g_events;
|
||||
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
|
||||
#endif
|
||||
272
engines/ultima/ultima0/gfx/dungeon.cpp
Normal file
272
engines/ultima/ultima0/gfx/dungeon.cpp
Normal file
@@ -0,0 +1,272 @@
|
||||
/* 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/ultima0/gfx/dungeon.h"
|
||||
#include "ultima/ultima0/gfx/monster.h"
|
||||
#include "ultima/ultima0/ultima0.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Gfx {
|
||||
|
||||
int Dungeon::_xLeft;
|
||||
int Dungeon::_xRight;
|
||||
int Dungeon::_yBottom;
|
||||
int Dungeon::_yDiffLeft;
|
||||
int Dungeon::_yDiffRight;
|
||||
|
||||
#define HWColour(IDX) color = IDX
|
||||
#define X(n) (x1 + w * (n)/10)
|
||||
#define Y(n) (y1 + h * (n)/10)
|
||||
#define HWLine(X1, Y1, X2, Y2) s->drawLine(X1, Y1, X2, Y2, color)
|
||||
#define BOX(x1,y1,x2,y2) { HWLine(X(x1),Y(y1),X(x2),Y(y1));HWLine(X(x1),Y(y1),X(x1),Y(y2));HWLine(X(x2),Y(y2),X(x2),Y(y1));HWLine(X(x2),Y(y2),X(x1),Y(y2)); }
|
||||
|
||||
void Dungeon::draw(Graphics::ManagedSurface *s) {
|
||||
const auto &player = g_engine->_player;
|
||||
const auto &dungeon = g_engine->_dungeon;
|
||||
|
||||
s->clear();
|
||||
|
||||
double level = 0;
|
||||
Common::Rect rIn, rOut;
|
||||
Common::Point dir, pos, next;
|
||||
int monster, front, left, right;
|
||||
calcRect(s, &rOut, 0);
|
||||
pos = player._dungeonPos; // Get position
|
||||
|
||||
// Iterate through drawing successively distinct tiles in the facing direction
|
||||
do {
|
||||
level++; // Next level
|
||||
calcRect(s, &rIn, level);
|
||||
|
||||
next.x = pos.x + player._dungeonDir.x; // Next position
|
||||
next.y = pos.y + player._dungeonDir.y;
|
||||
|
||||
dir = player._dungeonDir; rotateLeft(&dir); // To the left
|
||||
left = dungeon._map[pos.x + dir.x][pos.y + dir.y];
|
||||
rotateLeft(&dir); rotateLeft(&dir); // To the right
|
||||
right = dungeon._map[pos.x + dir.x][pos.y + dir.y];
|
||||
front = dungeon._map[next.x][next.y]; // What's in front ?
|
||||
|
||||
// Check for monster present
|
||||
monster = dungeon.findMonster(pos);
|
||||
if (monster >= 0)
|
||||
monster = dungeon._monsters[monster]._type;
|
||||
|
||||
// Draw the dungeon
|
||||
drawDungeon(s, &rOut, &rIn, left, front, right,
|
||||
dungeon._map[pos.x][pos.y], monster);
|
||||
|
||||
pos = next; // Next position down
|
||||
rOut = rIn; // Last in is new out
|
||||
} while (level < MAX_VIEW_DEPTH && ISDRAWOPEN(front));
|
||||
}
|
||||
|
||||
void Dungeon::calcRect(Graphics::ManagedSurface *s, Common::Rect *r, double level) {
|
||||
const int centerX = s->w / 2, centerY = s->h / 2;
|
||||
int xWidth = s->w / (level + 1);
|
||||
int yWidth = s->h / (level + 1);
|
||||
|
||||
// Set bounding box
|
||||
r->left = centerX - xWidth / 2;
|
||||
r->right = centerX + xWidth / 2;
|
||||
r->top = centerY - yWidth / 2;
|
||||
r->bottom = centerY + yWidth / 2;
|
||||
}
|
||||
|
||||
void Dungeon::rotateLeft(Common::Point *dir) {
|
||||
int t;
|
||||
if (dir->y == 0) dir->x = -dir->x;
|
||||
t = dir->x;
|
||||
dir->x = dir->y;
|
||||
dir->y = t;
|
||||
}
|
||||
|
||||
void Dungeon::drawDungeon(Graphics::ManagedSurface *s, Common::Rect *rOut,
|
||||
Common::Rect *rIn, int left, int centre, int right, int room, int monster) {
|
||||
int x1, y1, x, y, y2;
|
||||
Common::Rect r;
|
||||
double Scale;
|
||||
int color;
|
||||
|
||||
HWColour(COL_WALL); // Start on the walls
|
||||
|
||||
// Do we draw the left edge
|
||||
if (ISDRAWOPEN(left)) {
|
||||
HWLine(rOut->left, rIn->top, rIn->left, rIn->top);
|
||||
HWLine(rOut->left, rIn->bottom, rIn->left, rIn->bottom);
|
||||
HWLine(rOut->left, rOut->top, rOut->left, rOut->bottom);
|
||||
} else {
|
||||
// If closed, draw left diags
|
||||
HWLine(rOut->left, rOut->top, rIn->left, rIn->top);
|
||||
HWLine(rOut->left, rOut->bottom, rIn->left, rIn->bottom);
|
||||
}
|
||||
|
||||
// Do we draw the right edge
|
||||
if (ISDRAWOPEN(right)) {
|
||||
HWLine(rOut->right, rIn->top, rIn->right, rIn->top);
|
||||
HWLine(rOut->right, rIn->bottom, rIn->right, rIn->bottom);
|
||||
HWLine(rOut->right, rOut->top, rOut->right, rOut->bottom);
|
||||
} else {
|
||||
// If closed draw right diags
|
||||
HWLine(rOut->right, rOut->top, rIn->right, rIn->top);
|
||||
HWLine(rOut->right, rOut->bottom, rIn->right, rIn->bottom);
|
||||
}
|
||||
|
||||
// Back wall ?
|
||||
if (!ISDRAWOPEN(centre)) {
|
||||
HWLine(rIn->left, rIn->top, rIn->right, rIn->top);
|
||||
HWLine(rIn->left, rIn->bottom, rIn->right, rIn->bottom);
|
||||
if (!ISDRAWOPEN(left)) // Corner if left,right closed
|
||||
HWLine(rIn->left, rIn->top, rIn->left, rIn->bottom);
|
||||
if (!ISDRAWOPEN(right))
|
||||
HWLine(rIn->right, rIn->top, rIn->right, rIn->bottom);
|
||||
}
|
||||
|
||||
// Set up for left side
|
||||
setRange(rOut->left, rIn->left,
|
||||
rOut->bottom,
|
||||
rOut->bottom - rOut->top,
|
||||
rIn->bottom - rIn->top);
|
||||
drawWall(s, left);
|
||||
|
||||
// Set up for right side
|
||||
setRange(rIn->right, rOut->right,
|
||||
rIn->bottom,
|
||||
rIn->bottom - rIn->top,
|
||||
rOut->bottom - rOut->top);
|
||||
drawWall(s, right);
|
||||
|
||||
// Set up for centre
|
||||
setRange(rIn->left, rIn->right,
|
||||
rIn->bottom,
|
||||
rIn->bottom - rIn->top,
|
||||
rIn->bottom - rIn->top);
|
||||
drawWall(s, centre);
|
||||
|
||||
if (room == DT_LADDERUP) {
|
||||
r = Common::Rect(rOut->left, rOut->top, rOut->right, rIn->top);
|
||||
_DRAWPit(s, &r, 1);
|
||||
}
|
||||
if (room == DT_LADDERDN || room == DT_PIT) {
|
||||
r = Common::Rect(rOut->left, rIn->bottom, rOut->right, rOut->bottom);
|
||||
_DRAWPit(s, &r, -1);
|
||||
}
|
||||
|
||||
// Get the object area
|
||||
r = Common::Rect(
|
||||
(rIn->left + rOut->left) / 2,
|
||||
(rIn->top + rOut->top) / 2,
|
||||
(rIn->right + rOut->right) / 2,
|
||||
(rIn->bottom + rOut->bottom) / 2);
|
||||
|
||||
// Ladder here ?
|
||||
if (room == DT_LADDERUP || room == DT_LADDERDN) {
|
||||
HWColour(COL_LADDER);
|
||||
y1 = r.top; y2 = r.bottom;
|
||||
x = (r.right - r.left) * 3 / 10;
|
||||
|
||||
// Vertical lines
|
||||
HWLine(r.left + x, y1, r.left + x, y2);
|
||||
HWLine(r.right - x, y1, r.right - x, y2);
|
||||
x1 = (y2 - y1) / 5;
|
||||
|
||||
// Horizontal ladder rungs
|
||||
for (y = y1 + x1 / 2; y < y2; y += x1)
|
||||
HWLine(r.left + x, y, r.right - x, y);
|
||||
}
|
||||
|
||||
// Scale for monsters/gold. Scale factor has been empirically chosen
|
||||
Scale = 0.35 / (r.right - r.left) * s->w;
|
||||
|
||||
// Monster here ?
|
||||
if (monster > 0) {
|
||||
HWColour(COL_MONSTER);
|
||||
Monster::draw(s, (r.left + r.right) / 2, r.bottom, monster, Scale);
|
||||
}
|
||||
|
||||
// Draw the gold (as a mimic)
|
||||
if (room == DT_GOLD) {
|
||||
HWColour(COL_MONSTER);
|
||||
Monster::draw(s, (r.left + r.right) / 2, r.bottom, MN_MIMIC, Scale);
|
||||
}
|
||||
}
|
||||
|
||||
void Dungeon::setRange(int x1, int x2, int y, int yd1, int yd2) {
|
||||
_xLeft = x1; _xRight = x2; // Set x ranges
|
||||
_yBottom = y; // Set lower left y value
|
||||
_yDiffLeft = yd1; _yDiffRight = yd2; // Set difference for either end
|
||||
}
|
||||
|
||||
void Dungeon::drawWall(Graphics::ManagedSurface *s, int n) {
|
||||
int x1, y1, x2, y2;
|
||||
int color = 0;
|
||||
|
||||
if (n == DT_DOOR) {
|
||||
HWColour(COL_DOOR);
|
||||
x1 = 35; y1 = 0; x2 = 35; y2 = 60;
|
||||
drawConvert(&x1, &y1);
|
||||
drawConvert(&x2, &y2);
|
||||
HWLine(x1, y1, x2, y2);
|
||||
x1 = 65; y1 = 60; drawConvert(&x1, &y1);
|
||||
HWLine(x1, y1, x2, y2);
|
||||
x2 = 65; y2 = 0; drawConvert(&x2, &y2);
|
||||
HWLine(x1, y1, x2, y2);
|
||||
}
|
||||
}
|
||||
|
||||
void Dungeon::drawConvert(int *px, int *py) {
|
||||
long x, y, yd; // Longs for overflow in 16 bit
|
||||
x = (_xRight - _xLeft); // Calculate width
|
||||
x = x * (*px) / 100 + _xLeft; // Work out horiz value
|
||||
yd = (_yDiffRight - _yDiffLeft); // Work out height of vert for x
|
||||
yd = yd * (*px) / 100;
|
||||
y = _yBottom + // Half of the distance
|
||||
yd / 2 - // + Scaled total size
|
||||
(yd + _yDiffLeft) * (*py) / 100;
|
||||
|
||||
*px = (int)x; // Write back, casting to int
|
||||
*py = (int)y;
|
||||
}
|
||||
|
||||
void Dungeon::_DRAWPit(Graphics::ManagedSurface *s, Common::Rect *r, int Dir) {
|
||||
int x1, x2, y1;
|
||||
int color;
|
||||
|
||||
HWColour(COL_HOLE);
|
||||
y1 = (r->top - r->bottom) / 5;
|
||||
r->bottom += y1; r->top -= y1;
|
||||
x1 = (r->right - r->left) / 5;
|
||||
r->left += x1; r->right -= x1;
|
||||
x2 = 0; x1 = x1 / 2;
|
||||
if (Dir > 0)
|
||||
{
|
||||
y1 = x1; x1 = x2; x2 = y1;
|
||||
}
|
||||
HWLine(r->left + x1, r->top, r->right - x1, r->top);
|
||||
HWLine(r->left + x1, r->top, r->left + x2, r->bottom);
|
||||
HWLine(r->left + x2, r->bottom, r->right - x2, r->bottom);
|
||||
HWLine(r->right - x1, r->top, r->right - x2, r->bottom);
|
||||
}
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
81
engines/ultima/ultima0/gfx/dungeon.h
Normal file
81
engines/ultima/ultima0/gfx/dungeon.h
Normal 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 ULTIMA0_GFX_MAP_H
|
||||
#define ULTIMA0_GFX_MAP_H
|
||||
|
||||
#include "graphics/managed_surface.h"
|
||||
#include "ultima/ultima0/data/data.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Gfx {
|
||||
|
||||
class Dungeon {
|
||||
private:
|
||||
// Slanted drawing constants
|
||||
static int _xLeft, _xRight, _yBottom, _yDiffLeft, _yDiffRight;
|
||||
|
||||
/**
|
||||
* Calculate display rectangle
|
||||
*/
|
||||
static void calcRect(Graphics::ManagedSurface *s, Common::Rect *r, double _level);
|
||||
|
||||
/**
|
||||
* Rotate a direction left
|
||||
*/
|
||||
static void rotateLeft(Common::Point *Dir);
|
||||
|
||||
/**
|
||||
* Draw part of dungeon
|
||||
*/
|
||||
static void drawDungeon(Graphics::ManagedSurface *s, Common::Rect *rOut,
|
||||
Common::Rect *rIn, int Left, int Centre, int Right, int Room, int Monster);
|
||||
|
||||
/**
|
||||
* Set the oblique drawing routine
|
||||
*/
|
||||
static void setRange(int x1, int x2, int y, int yd1, int yd2);
|
||||
|
||||
/**
|
||||
* Draw wall object using current setting
|
||||
*/
|
||||
static void drawWall(Graphics::ManagedSurface *s, int n);
|
||||
|
||||
/**
|
||||
* Convert coordinates from oblique to logical
|
||||
*/
|
||||
static void drawConvert(int *px, int *py);
|
||||
|
||||
/**
|
||||
* Draw the pits/ladder hole
|
||||
*/
|
||||
static void _DRAWPit(Graphics::ManagedSurface *s, Common::Rect *r, int Dir);
|
||||
|
||||
public:
|
||||
static void draw(Graphics::ManagedSurface *s);
|
||||
};
|
||||
|
||||
} // namespace Gfx
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
|
||||
#endif
|
||||
224
engines/ultima/ultima0/gfx/font.cpp
Normal file
224
engines/ultima/ultima0/gfx/font.cpp
Normal file
@@ -0,0 +1,224 @@
|
||||
/* 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/ultima0/gfx/font.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Gfx {
|
||||
|
||||
static const byte FONT1[2048] = {
|
||||
124,130,186,162,186,130,124,0,126,129,165,129,165,153,129,126,
|
||||
126,129,165,129,153,165,129,126,108,246,246,254,124,56,16,0,
|
||||
16,56,124,254,124,56,16,0,16,56,84,254,84,16,56,0,
|
||||
56,124,254,254,108,16,56,0,16,24,20,20,48,112,96,0,
|
||||
254,254,254,238,254,254,254,0,236,138,138,170,170,170,236,0,
|
||||
142,136,136,140,136,136,232,0,174,170,170,234,170,170,174,0,
|
||||
238,136,136,204,136,136,136,0,238,138,138,142,140,138,234,0,
|
||||
62,34,62,34,102,238,204,0,16,84,40,198,40,84,16,0,
|
||||
240,248,252,254,252,248,240,0,30,62,126,254,126,62,30,0,
|
||||
16,56,124,16,124,56,16,0,238,238,238,238,238,0,238,0,
|
||||
254,68,68,68,68,68,68,0,126,128,188,198,122,2,252,0,
|
||||
0,0,0,0,255,255,0,0,16,56,124,16,124,56,16,254,
|
||||
16,56,124,254,56,56,56,0,56,56,56,254,124,56,16,0,
|
||||
16,24,252,254,252,24,16,0,16,48,126,254,126,48,16,0,
|
||||
|
||||
144,72,36,18,36,72,144,0,18,36,72,144,72,36,18,0,
|
||||
16,40,68,146,40,68,130,0,130,68,40,146,68,40,16,0,
|
||||
0,0,0,0,0,0,0,0,16,16,16,16,16,0,16,0,
|
||||
|
||||
40,40,40,0,0,0,0,0,68,254,68,68,68,254,68,0,
|
||||
16,126,144,124,18,252,16,0,66,164,72,16,36,74,132,0,
|
||||
56,68,56,112,138,132,122,0,16,16,32,0,0,0,0,0,
|
||||
8,16,16,16,16,16,8,0,32,16,16,16,16,16,32,0,
|
||||
16,84,56,254,56,84,16,0,16,16,16,254,16,16,16,0,
|
||||
0,0,0,0,0,16,16,32,0,0,0,254,0,0,0,0,
|
||||
0,0,0,0,0,0,16,0,2,4,8,16,32,64,128,0,
|
||||
124,130,130,130,130,130,124,0,240,16,16,16,16,16,254,0,
|
||||
252,2,2,124,128,128,254,0,252,2,2,28,2,2,252,0,
|
||||
130,130,130,126,2,2,2,0,254,128,252,2,2,2,252,0,
|
||||
126,128,252,130,130,130,124,0,252,2,2,2,2,2,2,0,
|
||||
124,130,130,124,130,130,124,0,126,130,130,126,2,2,252,0,
|
||||
0,0,0,16,0,0,16,0,0,0,0,16,0,0,16,32,
|
||||
8,16,32,64,32,16,8,0,0,0,0,254,0,254,0,0,
|
||||
64,32,16,8,16,32,64,0,56,68,4,8,16,0,16,0,
|
||||
60,66,154,170,156,64,62,0,124,130,130,254,130,130,130,0,
|
||||
252,130,130,252,130,130,252,0,124,130,128,128,128,130,124,0,
|
||||
252,130,130,130,130,130,252,0,254,128,128,240,128,128,254,0,
|
||||
254,128,128,240,128,128,128,0,124,130,128,142,130,130,124,0,
|
||||
130,130,130,254,130,130,130,0,254,16,16,16,16,16,254,0,
|
||||
62,2,2,2,130,130,124,0,130,132,136,240,136,132,130,0,
|
||||
128,128,128,128,128,128,254,0,252,146,146,146,146,146,146,0,
|
||||
130,194,162,146,138,134,130,0,124,130,130,130,130,130,124,0,
|
||||
252,130,130,252,128,128,128,0,124,130,130,130,138,134,126,0,
|
||||
252,130,130,252,130,130,130,0,126,128,128,124,2,2,252,0,
|
||||
254,16,16,16,16,16,16,0,130,130,130,130,130,130,124,0,
|
||||
130,130,68,68,40,40,16,0,130,130,130,146,146,146,108,0,
|
||||
130,68,40,16,40,68,130,0,130,130,130,126,2,2,252,0,
|
||||
254,4,8,16,32,64,254,0,56,32,32,32,32,32,56,0,
|
||||
128,64,32,16,8,4,2,0,56,8,8,8,8,8,56,0,
|
||||
16,40,68,130,0,0,0,0,0,0,0,0,0,0,0,255,
|
||||
32,32,16,0,0,0,0,0,0,0,56,68,124,68,68,0,
|
||||
0,0,120,68,120,68,120,0,0,0,60,64,64,64,60,0,
|
||||
0,0,120,68,68,68,120,0,0,0,124,64,112,64,124,0,
|
||||
0,0,124,64,112,64,64,0,0,0,60,64,76,68,60,0,
|
||||
0,0,68,68,124,68,68,0,0,0,124,16,16,16,124,0,
|
||||
0,0,28,4,4,68,56,0,0,0,68,72,112,72,68,0,
|
||||
0,0,64,64,64,64,124,0,0,0,120,84,84,84,84,0,
|
||||
0,0,120,68,68,68,68,0,0,0,56,68,68,68,56,0,
|
||||
0,0,120,68,120,64,64,0,0,0,56,68,68,76,54,0,
|
||||
0,0,120,68,120,68,68,0,0,0,60,64,56,4,120,0,
|
||||
0,0,124,16,16,16,16,0,0,0,68,68,68,68,56,0,
|
||||
0,0,68,68,40,40,16,0,0,0,68,68,84,108,68,0,
|
||||
0,0,68,40,16,40,68,0,0,0,68,68,60,4,120,0,
|
||||
0,0,124,8,16,32,124,0,8,16,16,32,16,16,8,0,
|
||||
16,16,16,0,16,16,16,0,32,16,16,8,16,16,32,0,
|
||||
80,40,0,0,0,0,0,0,0,16,40,68,130,130,254,0,
|
||||
254,254,254,254,254,254,254,0,0,0,0,0,0,254,254,0,
|
||||
0,0,124,124,124,124,124,0,0,0,0,0,0,0,124,0,
|
||||
128,128,128,128,128,128,128,0,0,64,64,64,64,64,64,0,
|
||||
16,24,28,30,28,24,16,0,16,48,112,240,112,48,16,0,
|
||||
62,30,30,62,114,224,64,0,4,14,156,248,240,240,248,0,
|
||||
64,224,114,62,30,30,62,0,248,240,240,248,156,14,4,0,
|
||||
56,68,130,130,130,68,56,0,56,124,254,254,254,124,56,0,
|
||||
0,124,68,68,68,124,0,0,0,124,124,124,124,124,0,0,
|
||||
0,60,110,126,112,126,60,0,0,60,118,126,14,126,60,0,
|
||||
0,60,126,106,126,126,106,0,0,60,126,86,126,126,86,0,
|
||||
0,0,0,24,24,0,0,0,0,0,24,60,60,24,0,0,
|
||||
|
||||
0,12,52,36,36,108,72,0,0,0,0,0,0,0,0,0,
|
||||
60,126,198,231,255,224,126,60,60,126,227,231,255,7,126,60,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,52,118,118,94,126,60,0,0,60,110,126,112,126,60,0,
|
||||
0,60,126,122,110,110,44,0,0,60,126,14,126,118,60,0,
|
||||
0,0,0,0,0,0,0,0,126,126,126,126,60,0,0,0,
|
||||
0,15,31,31,31,31,15,0,126,127,127,127,127,127,63,0,
|
||||
0,0,0,60,126,126,126,126,126,126,126,126,126,126,126,126,
|
||||
0,63,127,127,127,127,127,126,126,127,127,127,127,127,127,126,
|
||||
|
||||
0,240,248,248,248,248,240,0,126,254,254,254,254,254,252,0,
|
||||
0,255,255,255,255,255,255,0,126,255,255,255,255,255,255,0,
|
||||
0,252,254,254,254,254,254,126,126,254,254,254,254,254,254,126,
|
||||
0,255,255,255,255,255,255,126,126,255,255,255,255,255,255,126,
|
||||
0,0,63,63,48,55,52,52,0,0,255,255,0,255,0,0,
|
||||
0,0,248,248,24,216,88,88,88,88,88,88,88,88,88,88,
|
||||
88,216,24,248,248,0,0,0,0,255,0,255,255,0,0,0,
|
||||
52,55,48,63,63,0,0,0,52,52,52,52,52,52,52,52,
|
||||
0,0,0,31,24,24,24,24,0,0,0,255,0,0,0,0,
|
||||
0,0,0,240,48,48,48,48,48,48,48,48,48,48,48,48,
|
||||
48,48,48,240,0,0,0,0,0,0,0,255,0,0,0,0,
|
||||
24,24,24,31,0,0,0,0,24,24,24,24,24,24,24,24,
|
||||
136,34,136,34,136,34,136,34,85,170,85,170,85,170,85,170,
|
||||
68,170,68,170,68,170,68,170,51,102,204,153,51,102,204,153,
|
||||
204,102,51,153,204,102,51,153,199,143,31,62,124,248,241,227,
|
||||
227,241,248,124,62,31,143,199,174,128,186,2,234,8,171,32,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
};
|
||||
|
||||
|
||||
void Font::writeChar(Graphics::ManagedSurface *dst, uint32 chr,
|
||||
const Common::Point &textPos, byte textColor) {
|
||||
if (chr == ' ')
|
||||
return; // Don't do anything for spaces
|
||||
|
||||
const byte *GfxData = FONT1 + chr * 8;
|
||||
Graphics::Surface charArea = dst->getSubArea(Common::Rect(textPos.x, textPos.y,
|
||||
textPos.x + GLYPH_WIDTH, textPos.y + GLYPH_HEIGHT));
|
||||
const int w = 1;
|
||||
const int h = 1;
|
||||
|
||||
// Work through the 64 pixel array
|
||||
for (int x = 0; x < 8; ++x) {
|
||||
for (int y = 0; y < 8; ++y) {
|
||||
// Check for whether character has pixel in this position
|
||||
if (_FONTPixelSet(GfxData, x, y)) {
|
||||
Common::Rect rc2(x * 2, y * 2, x * 2 + 2, y * 2 + 2);
|
||||
charArea.fillRect(rc2, textColor);
|
||||
|
||||
// Neaten the diagonals
|
||||
if (_FONTPixelSet(GfxData, x, y + 1) == 0 &&
|
||||
_FONTPixelSet(GfxData, x - 1, y) == 0 &&
|
||||
_FONTPixelSet(GfxData, x - 1, y + 1) != 0)
|
||||
_FONTAngleDraw(&charArea, &rc2, -w, h, textColor);
|
||||
|
||||
if (_FONTPixelSet(GfxData, x, y + 1) == 0 &&
|
||||
_FONTPixelSet(GfxData, x + 1, y) == 0 &&
|
||||
_FONTPixelSet(GfxData, x + 1, y + 1) != 0)
|
||||
_FONTAngleDraw(&charArea, &rc2, w, h, textColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Font::_FONTPixelSet(const byte * Data, int x, int y) {
|
||||
if (x < 0 || y < 0 || x > 7 || y > 7)
|
||||
return false;
|
||||
return (Data[y] & (0x80 >> x)) ? 1 : 0;
|
||||
}
|
||||
|
||||
void Font::_FONTAngleDraw(Graphics::Surface *s, Common::Rect *rc, int w, int h, byte colour) {
|
||||
int i, m;
|
||||
Common::Rect rc3;
|
||||
|
||||
m = ABS(w);
|
||||
if (ABS(h) > m)
|
||||
m = ABS(h);
|
||||
|
||||
for (i = 0; i < m; i++) {
|
||||
rc3.left = rc->left + w * i / m;
|
||||
rc3.top = rc->top + h * i / m;
|
||||
rc3.setWidth(rc->width());
|
||||
rc3.setHeight(rc->height());
|
||||
s->fillRect(rc3, colour);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Gfx
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
71
engines/ultima/ultima0/gfx/font.h
Normal file
71
engines/ultima/ultima0/gfx/font.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/* 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 ULTIMA0_GFX_FONT_H
|
||||
#define ULTIMA0_GFX_FONT_H
|
||||
|
||||
#include "common/rect.h"
|
||||
#include "graphics/managed_surface.h"
|
||||
#include "ultima/ultima0/data/defines.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Gfx {
|
||||
|
||||
constexpr int GLYPH_HEIGHT = 16;
|
||||
constexpr int GLYPH_WIDTH = 16;
|
||||
constexpr int TEXT_WIDTH = DEFAULT_SCX / GLYPH_WIDTH;
|
||||
constexpr int TEXT_HEIGHT = DEFAULT_SCY / GLYPH_HEIGHT;
|
||||
|
||||
class TextRect : public ::Common::Rect {
|
||||
public:
|
||||
TextRect() : ::Common::Rect() {}
|
||||
TextRect(int left_, int top_, int right_, int bottom_) :
|
||||
::Common::Rect(left_ * GLYPH_WIDTH, top_ * GLYPH_HEIGHT,
|
||||
(right_ + 1) * GLYPH_WIDTH, (bottom_ + 1) * GLYPH_HEIGHT) {}
|
||||
};
|
||||
|
||||
class Font {
|
||||
private:
|
||||
/**
|
||||
* Returns true if a pixel is set in the source font data
|
||||
*/
|
||||
static bool _FONTPixelSet(const byte *Data, int x, int y);
|
||||
|
||||
/**
|
||||
* Draw an angled line - this stops the squared corners on diagonals showing
|
||||
*/
|
||||
static void _FONTAngleDraw(Graphics::Surface *s, Common::Rect *rc,
|
||||
int w, int h, byte colour);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Draws a character onto the passed surface
|
||||
*/
|
||||
static void writeChar(Graphics::ManagedSurface *dst, uint32 chr,
|
||||
const Common::Point &textPos, byte textColor);
|
||||
};
|
||||
|
||||
} // namespace Gfx
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
|
||||
#endif
|
||||
109
engines/ultima/ultima0/gfx/gfx_surface.cpp
Normal file
109
engines/ultima/ultima0/gfx/gfx_surface.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
/* 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/ultima0/gfx/gfx_surface.h"
|
||||
#include "ultima/ultima0/gfx/font.h"
|
||||
#include "ultima/ultima0/ultima0.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Gfx {
|
||||
|
||||
void GfxSurface::writeString(const Common::Point &pt, const Common::String &str,
|
||||
Graphics::TextAlign align) {
|
||||
_textPos = pt;
|
||||
writeString(str, align);
|
||||
}
|
||||
|
||||
void GfxSurface::writeString(const Common::String &str, Graphics::TextAlign align) {
|
||||
size_t strSize = 0;
|
||||
for (const char *p = str.c_str(); *p; ++p)
|
||||
strSize += Common::isPrint(*p) ? 1 : 0;
|
||||
|
||||
switch (align) {
|
||||
case Graphics::kTextAlignCenter:
|
||||
_textPos.x -= strSize / 2;
|
||||
break;
|
||||
case Graphics::kTextAlignRight:
|
||||
_textPos.x -= strSize;
|
||||
break;
|
||||
case Graphics::kTextAlignLeft:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (const char *p = str.c_str(); *p; ++p) {
|
||||
if (*p == '\n') {
|
||||
assert(align == Graphics::kTextAlignLeft);
|
||||
newLine();
|
||||
} else if (*p < 32) {
|
||||
setColor((byte)*p);
|
||||
} else {
|
||||
writeChar(*p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GfxSurface::writeChar(uint32 chr) {
|
||||
if (chr >= ' ') {
|
||||
Font::writeChar(this, chr, Common::Point(_textPos.x * GLYPH_WIDTH,
|
||||
_textPos.y * GLYPH_HEIGHT), _textColor);
|
||||
++_textPos.x;
|
||||
}
|
||||
|
||||
if (_textPos.x >= TEXT_WIDTH || chr == '\n') {
|
||||
newLine();
|
||||
}
|
||||
}
|
||||
|
||||
void GfxSurface::newLine() {
|
||||
_textPos.x = 0;
|
||||
_textPos.y++;
|
||||
|
||||
if (_textPos.y >= TEXT_HEIGHT) {
|
||||
_textPos.y = TEXT_HEIGHT - 1;
|
||||
|
||||
// Scroll the screen contents up
|
||||
blitFrom(*this, Common::Rect(0, GLYPH_HEIGHT, DEFAULT_SCX, DEFAULT_SCY),
|
||||
Common::Point(0, 0));
|
||||
fillRect(Common::Rect(0, DEFAULT_SCX - GLYPH_HEIGHT, DEFAULT_SCX, DEFAULT_SCY), 0);
|
||||
}
|
||||
}
|
||||
|
||||
void GfxSurface::setTextPos(const Common::Point &pt) {
|
||||
_textPos = pt;
|
||||
}
|
||||
|
||||
byte GfxSurface::setColor(byte color) {
|
||||
byte oldColor = _textColor;
|
||||
_textColor = color;
|
||||
return oldColor;
|
||||
}
|
||||
|
||||
byte GfxSurface::setColor(byte r, byte g, byte b) {
|
||||
byte oldColor = _textColor;
|
||||
_textColor = g_engine->_palette.findBestColor(r, g, b);
|
||||
return oldColor;
|
||||
}
|
||||
|
||||
} // namespace Gfx
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
61
engines/ultima/ultima0/gfx/gfx_surface.h
Normal file
61
engines/ultima/ultima0/gfx/gfx_surface.h
Normal 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ULTIMA0_GFX_SURFACE_H
|
||||
#define ULTIMA0_GFX_SURFACE_H
|
||||
|
||||
#include "graphics/font.h"
|
||||
#include "graphics/managed_surface.h"
|
||||
#include "ultima/ultima0/gfx/font.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Gfx {
|
||||
|
||||
class GfxSurface : public Graphics::ManagedSurface {
|
||||
private:
|
||||
Common::Point _textPos;
|
||||
byte _textColor = C_TEXT_DEFAULT;
|
||||
|
||||
void newLine();
|
||||
|
||||
public:
|
||||
GfxSurface() : Graphics::ManagedSurface() {}
|
||||
GfxSurface(Graphics::ManagedSurface &surf, const Common::Rect &bounds) : Graphics::ManagedSurface(surf, bounds) {}
|
||||
|
||||
/**
|
||||
* Write some text to the surface
|
||||
*/
|
||||
void writeString(const Common::Point &pt, const Common::String &str,
|
||||
Graphics::TextAlign align = Graphics::kTextAlignLeft);
|
||||
void writeString(const Common::String &str, Graphics::TextAlign align = Graphics::kTextAlignLeft);
|
||||
void writeChar(uint32 chr);
|
||||
|
||||
void setTextPos(const Common::Point &pt);
|
||||
byte setColor(byte color);
|
||||
byte setColor(byte r, byte g, byte b);
|
||||
};
|
||||
|
||||
} // namespace Gfx
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
|
||||
#endif
|
||||
142
engines/ultima/ultima0/gfx/map.cpp
Normal file
142
engines/ultima/ultima0/gfx/map.cpp
Normal file
@@ -0,0 +1,142 @@
|
||||
/* 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/ultima0/gfx/map.h"
|
||||
#include "ultima/ultima0/ultima0.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Gfx {
|
||||
|
||||
void Map::draw(Graphics::ManagedSurface *s, bool showAsMap) {
|
||||
const auto &player = g_engine->_player;
|
||||
const auto &map = g_engine->_worldMap;
|
||||
|
||||
s->clear();
|
||||
|
||||
int x, y, x1, y1, w, h, grid;
|
||||
Common::Rect r;
|
||||
grid = showAsMap ? WORLD_MAP_SIZE : (g_engine->isEnhanced() ? 7 : 3);
|
||||
w = s->w / grid; h = s->h / grid; // Get grid sizes
|
||||
|
||||
for (x = 0; x < grid; x++) {
|
||||
for (y = 0; y < grid; y++) {
|
||||
r = Common::Rect(x * w, y * h, x * w + w - 1, y * h + h - 1);
|
||||
|
||||
if (showAsMap) {
|
||||
// If map, not centered around us
|
||||
x1 = x, y1 = y;
|
||||
} else {
|
||||
// Which cell?
|
||||
x1 = player._worldPos.x - grid / 2 + x;
|
||||
y1 = player._worldPos.y - grid / 2 + y;
|
||||
}
|
||||
|
||||
drawTile(s, r, map.read(x1, y1));
|
||||
|
||||
// Draw us if we're there
|
||||
if (x1 == player._worldPos.x && y1 == player._worldPos.y)
|
||||
drawTile(s, r, WT_PLAYER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define HWColour(IDX) color = IDX
|
||||
#define X(n) (x1 + w * (n)/10)
|
||||
#define Y(n) (y1 + h * (n)/10)
|
||||
#define HWLine(X1, Y1, X2, Y2) s->drawLine(X1, Y1, X2, Y2, color)
|
||||
#define BOX(x1,y1,x2,y2) { HWLine(X(x1),Y(y1),X(x2),Y(y1));HWLine(X(x1),Y(y1),X(x1),Y(y2));HWLine(X(x2),Y(y2),X(x2),Y(y1));HWLine(X(x2),Y(y2),X(x1),Y(y2)); }
|
||||
|
||||
void Map::drawTile(Graphics::ManagedSurface *s, const Common::Rect &r, int obj) {
|
||||
int x1 = r.left;
|
||||
int y1 = r.top;
|
||||
int w = r.width();
|
||||
int h = r.height();
|
||||
byte color = 0;
|
||||
|
||||
// Decide on the object
|
||||
switch (obj) {
|
||||
case WT_SPACE:
|
||||
// Space does nothing at all
|
||||
break;
|
||||
|
||||
case WT_MOUNTAIN:
|
||||
// Mountain the cracked effect
|
||||
HWColour(COL_MOUNTAIN);
|
||||
HWLine(X(2), Y(6), X(2), Y(10));
|
||||
HWLine(X(0), Y(8), X(2), Y(8));
|
||||
HWLine(X(2), Y(6), X(4), Y(6));
|
||||
HWLine(X(4), Y(6), X(4), Y(4));
|
||||
HWLine(X(2), Y(2), X(4), Y(4));
|
||||
HWLine(X(2), Y(2), X(2), Y(0));
|
||||
HWLine(X(2), Y(2), X(0), Y(2));
|
||||
HWLine(X(8), Y(4), X(4), Y(4));
|
||||
HWLine(X(8), Y(4), X(8), Y(0));
|
||||
HWLine(X(8), Y(2), X(10), Y(2));
|
||||
HWLine(X(6), Y(4), X(6), Y(8));
|
||||
HWLine(X(10), Y(8), X(6), Y(8));
|
||||
HWLine(X(8), Y(8), X(8), Y(10));
|
||||
break;
|
||||
|
||||
case WT_TREE:
|
||||
// Tree is just a box
|
||||
HWColour(COL_TREE);
|
||||
BOX(3, 3, 7, 7);
|
||||
break;
|
||||
|
||||
case WT_TOWN:
|
||||
// Town is 5 boxes
|
||||
HWColour(COL_TOWN);
|
||||
BOX(2, 2, 4, 4); BOX(4, 4, 6, 6); BOX(6, 6, 8, 8);
|
||||
BOX(6, 2, 8, 4); BOX(2, 6, 4, 8);
|
||||
break;
|
||||
|
||||
case WT_DUNGEON:
|
||||
// Dungeon is a cross
|
||||
HWColour(COL_DUNGEON);
|
||||
HWLine(X(3), Y(3), X(7), Y(7));
|
||||
HWLine(X(7), Y(3), X(3), Y(7));
|
||||
break;
|
||||
|
||||
case WT_BRITISH:
|
||||
// British castle
|
||||
HWColour(COL_BRITISH);
|
||||
HWLine(X(2), Y(2), X(8), Y(8));
|
||||
HWLine(X(8), Y(2), X(2), Y(8));
|
||||
BOX(0, 0, 10, 10);
|
||||
BOX(2, 2, 8, 8);
|
||||
break;
|
||||
|
||||
case WT_PLAYER:
|
||||
// Player
|
||||
HWColour(COL_PLAYER);
|
||||
HWLine(X(4), Y(5), X(6), Y(5));
|
||||
HWLine(X(5), Y(4), X(5), Y(6));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
43
engines/ultima/ultima0/gfx/map.h
Normal file
43
engines/ultima/ultima0/gfx/map.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/* 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 ULTIMA0_GFX_MAP_H
|
||||
#define ULTIMA0_GFX_MAP_H
|
||||
|
||||
#include "graphics/managed_surface.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Gfx {
|
||||
|
||||
class Map {
|
||||
private:
|
||||
static void drawTile(Graphics::ManagedSurface *s, const Common::Rect &r, int obj);
|
||||
|
||||
public:
|
||||
static void draw(Graphics::ManagedSurface *s, bool showAsMap = false);
|
||||
};
|
||||
|
||||
} // namespace Gfx
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
|
||||
#endif
|
||||
205
engines/ultima/ultima0/gfx/monster.cpp
Normal file
205
engines/ultima/ultima0/gfx/monster.cpp
Normal file
@@ -0,0 +1,205 @@
|
||||
/* 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/ultima0/gfx/monster.h"
|
||||
#include "ultima/ultima0/ultima0.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Gfx {
|
||||
|
||||
Monster::DrawFn Monster::DRAW_FUNCTIONS[] = {
|
||||
nullptr, drawSkeleton, drawThief, drawRat, drawOrc, drawViper,
|
||||
drawCarrion, drawGremlin, drawMimic, drawDaemon, drawBalrog
|
||||
};
|
||||
int Monster::_xPos = 640;
|
||||
int Monster::_yPos = 512;
|
||||
constexpr int color = COL_MONSTER;
|
||||
|
||||
// End marker
|
||||
#define END (-9999.99)
|
||||
|
||||
#define X(n) (x1 + w * (n)/10)
|
||||
#define Y(n) (y1 + h * (n)/10)
|
||||
#define HWLine(X1, Y1, X2, Y2) s->drawLine(X1, Y1, X2, Y2, color)
|
||||
#define BOX(x1,y1,x2,y2) { HWLine(X(x1),Y(y1),X(x2),Y(y1));HWLine(X(x1),Y(y1),X(x1),Y(y2));HWLine(X(x2),Y(y2),X(x2),Y(y1));HWLine(X(x2),Y(y2),X(x1),Y(y2)); }
|
||||
|
||||
void Monster::draw(Graphics::ManagedSurface *s, int x, int y, int monster, double scale) {
|
||||
// Save drawing pos
|
||||
_xPos = x; _yPos = y;
|
||||
if (monster == MN_MIMIC)
|
||||
// Fix for Mimic/Chest
|
||||
_xPos -= 90;
|
||||
|
||||
// Call appropriate function
|
||||
assert(monster > 0 && monster <= MN_BALROG);
|
||||
(*DRAW_FUNCTIONS[monster])(s, 0, 0, scale);
|
||||
}
|
||||
|
||||
void Monster::hPlot(Graphics::ManagedSurface *s, double x, double y, ...) {
|
||||
va_list alist;
|
||||
double y1, x1;
|
||||
|
||||
// Start reading values
|
||||
va_start(alist, y);
|
||||
bool isPixel = true;
|
||||
|
||||
do {
|
||||
x1 = va_arg(alist, double); // Get the next two
|
||||
y1 = va_arg(alist, double);
|
||||
if (x1 != END && y1 != END) {
|
||||
// If legit, draw the line
|
||||
HWLine(_xPos + x, _yPos + y, _xPos + x1, _yPos + y1);
|
||||
isPixel = false;
|
||||
} else if (isPixel)
|
||||
// Single pixel only
|
||||
HWLine(_xPos + x, _yPos + y, _xPos + x, _yPos + y);
|
||||
|
||||
x = x1; y = y1;
|
||||
} while (x1 != END && y1 != END);
|
||||
|
||||
va_end(alist);
|
||||
}
|
||||
|
||||
void Monster::drawSkeleton(Graphics::ManagedSurface *s, double x, double y, double d) {
|
||||
hPlot(s, x - 23 / d, y, x - 15 / d, y, x - 15 / d, y - 15 / d, x - 8 / d, y - 30 / d, x + 8 / d, y - 30 / d, x + 15 / d, y - 15 / d, x + 15 / d, y, x + 23 / d, y, END, END);
|
||||
hPlot(s, x, y - 26 / d, x, y - 65 / d, END, END);
|
||||
hPlot(s, x - 2 / d + .5, y - 38 / d, x + 2 / d + .5, y - 38 / d, END, END);
|
||||
hPlot(s, x - 3 / d + .5, y - 45 / d, x + 3 / d + .5, y - 45 / d, END, END);
|
||||
hPlot(s, x - 5 / d + .5, y - 53 / d, x + 5 / d + .5, y - 53 / d, END, END);
|
||||
hPlot(s, x - 23 / d, y - 56 / d, x - 30 / d, y - 53 / d, x - 23 / d, y - 45 / d, x - 23 / d, y - 53 / d, x - 8 / d, y - 38 / d, END, END);
|
||||
hPlot(s, x - 15 / d, y - 45 / d, x - 8 / d, y - 60 / d, x + 8 / d, y - 60 / d, x + 15 / d, y - 45 / d, END, END);
|
||||
hPlot(s, x + 15 / d, y - 42 / d, x + 15 / d, y - 57 / d, END, END);
|
||||
hPlot(s, x + 12 / d, y - 45 / d, x + 20 / d, y - 45 / d, END, END);
|
||||
hPlot(s, x, y - 75 / d, x - 5 / d + .5, y - 80 / d, x - 8 / d, y - 75 / d, x - 5 / d + .5, y - 65 / d, x + 5 / d + .5, y - 65 / d, x + 5 / d + .5, y - 68 / d, x - 5 / d + .5, y - 68 / d, x - 5 / d + .5, y - 65 / d, END, END);
|
||||
hPlot(s, x + 5 / d + .5, y - 65 / d, x + 8 / d, y - 75 / d, x + 5 / d + .5, y - 80 / d, x - 5 / d + .5, y - 80 / d, END, END);
|
||||
hPlot(s, x - 5 / d + .5, y - 72 / d, END, END);
|
||||
hPlot(s, x + 5 / d + .5, y - 72 / d, END, END);
|
||||
}
|
||||
|
||||
void Monster::drawThief(Graphics::ManagedSurface *s, double x, double y, double d) {
|
||||
hPlot(s, x, y - 56 / d, x, y - 8 / d, x + 10 / d, y, x + 30 / d, y, x + 30 / d, y - 45 / d, x + 10 / d, y - 64 / d, x, y - 56 / d, END, END);
|
||||
hPlot(s, x - 10 / d, y - 64 / d, x - 30 / d, y - 45 / d, x - 30 / d, y, x - 10 / d, y, x, y - 8 / d, END, END);
|
||||
hPlot(s, x - 10 / d, y - 64 / d, x - 10 / d, y - 75 / d, x, y - 83 / d, x + 10 / d, y - 75 / d, x, y - 79 / d, x - 10 / d, y - 75 / d, x, y - 60 / d, x + 10 / d, y - 75 / d, x + 10 / d, y - 64 / d, END, END);
|
||||
}
|
||||
|
||||
void Monster::drawRat(Graphics::ManagedSurface *s, double x, double y, double d) {
|
||||
hPlot(s, x + 5 / d, y - 30 / d, x, y - 25 / d, x - 5 / d, y - 30 / d, x - 15 / d, y - 5 / d, x - 10 / d, y, x + 10 / d, y, x + 15 / d, y - 5 / d, END, END);
|
||||
hPlot(s, x + 20 / d, y - 5 / d, x + 10 / d, y, x + 15 / d, y - 5 / d, x + 5 / d, y - 30 / d, x + 10 / d, y - 40 / d, x + 3 / d + .5, y - 35 / d, x - 3 / d + .5, y - 35 / d, x - 10 / d, y - 40 / d, x - 5 / d, y - 30 / d, END, END);
|
||||
hPlot(s, x - 5 / d, y - 33 / d, x - 3 / d + .5, y - 30 / d, END, END);
|
||||
hPlot(s, x + 5 / d, y - 33 / d, x + 3 / d + .5, y - 30 / d, END, END);
|
||||
hPlot(s, x - 5 / d, y - 20 / d, x - 5 / d, y - 15 / d, END, END);
|
||||
hPlot(s, x + 5 / d, y - 20 / d, x + 5 / d, y - 15 / d, END, END);
|
||||
hPlot(s, x - 7 / d, y - 20 / d, x - 7 / d, y - 15 / d, END, END);
|
||||
hPlot(s, x + 7 / d, y - 20 / d, x + 7 / d, y - 15 / d, END, END);
|
||||
}
|
||||
|
||||
void Monster::drawOrc(Graphics::ManagedSurface *s, double x, double y, double d) {
|
||||
hPlot(s, x, y, x - 15 / d, y, x - 8 / d, y - 8 / d, x - 8 / d, y - 15 / d, x - 15 / d, y - 23 / d, x - 15 / d, y - 15 / d, x - 23 / d, y - 23 / d, END, END);
|
||||
hPlot(s, x - 23 / d, y - 23 / d, x - 15 / d, y - 53 / d, x - 8 / d, y - 53 / d, x - 15 / d, y - 68 / d, x - 8 / d, y - 75 / d, x, y - 75 / d, END, END);
|
||||
hPlot(s, x, y, x + 15 / d, y, x + 8 / d, y - 8 / d, x + 8 / d, y - 15 / d, x + 15 / d, y - 23 / d, x + 15 / d, y - 15 / d, x + 23 / d, y - 23 / d, END, END);
|
||||
hPlot(s, x + 23 / d, y - 23 / d, x + 15 / d, y - 53 / d, x + 8 / d, y - 53 / d, x + 15 / d, y - 68 / d, x + 8 / d, y - 75 / d, x, y - 75 / d, END, END);
|
||||
hPlot(s, x - 15 / d, y - 68 / d, x + 15 / d, y - 68 / d, END, END);
|
||||
hPlot(s, x - 8 / d, y - 53 / d, x + 8 / d, y - 53 / d, END, END);
|
||||
hPlot(s, x - 23 / d, y - 15 / d, x + 8 / d, y - 45 / d, END, END);
|
||||
hPlot(s, x - 8 / d, y - 68 / d, x, y - 60 / d, x + 8 / d, y - 68 / d, x + 8 / d, y - 60 / d, x - 8 / d, y - 60 / d, x - 8 / d, y - 68 / d, END, END);
|
||||
hPlot(s, x, y - 38 / d, x - 8 / d, y - 38 / d, x + 8 / d, y - 53 / d, x + 8 / d, y - 45 / d, x + 15 / d, y - 45 / d, x, y - 30 / d, x, y - 38 / d, END, END);
|
||||
}
|
||||
|
||||
void Monster::drawViper(Graphics::ManagedSurface *s, double x, double y, double d) {
|
||||
hPlot(s, x - 10 / d, y - 15 / d, x - 10 / d, y - 30 / d, x - 15 / d, y - 20 / d, x - 15 / d, y - 15 / d, x - 15 / d, y, x + 15 / d, y, x + 15 / d, y - 15 / d, x - 15 / d, y - 15 / d, END, END);
|
||||
hPlot(s, x - 15 / d, y - 10 / d, x + 15 / d, y - 10 / d, END, END);
|
||||
hPlot(s, x - 15 / d, y - 5 / d, x + 15 / d, y - 5 / d, END, END);
|
||||
hPlot(s, x, y - 15 / d, x - 5 / d, y - 20 / d, x - 5 / d, y - 35 / d, x + 5 / d, y - 35 / d, x + 5 / d, y - 20 / d, x + 10 / d, y - 15 / d, END, END);
|
||||
hPlot(s, x - 5 / d, y - 20 / d, x + 5 / d, y - 20 / d, END, END);
|
||||
hPlot(s, x - 5 / d, y - 25 / d, x + 5 / d, y - 25 / d, END, END);
|
||||
hPlot(s, x - 5 / d, y - 30 / d, x + 5 / d, y - 30 / d, END, END);
|
||||
hPlot(s, x - 10 / d, y - 35 / d, x - 10 / d, y - 40 / d, x - 5 / d, y - 45 / d, x + 5 / d, y - 45 / d, x + 10 / d, y - 40 / d, x + 10 / d, y - 35 / d, END, END);
|
||||
hPlot(s, x - 10 / d, y - 40 / d, x, y - 45 / d, x + 10 / d, y - 40 / d, END, END);
|
||||
hPlot(s, x - 5 / d, y - 40 / d, x + 5 / d, y - 40 / d, x + 15 / d, y - 30 / d, x, y - 40 / d, x - 15 / d, y - 30 / d, x - 5 / d + .5, y - 40 / d, END, END);
|
||||
}
|
||||
|
||||
void Monster::drawCarrion(Graphics::ManagedSurface *s, double x, double y, double d) {
|
||||
// 79-dst.recty(d) line here
|
||||
hPlot(s, x - 20 / d, y - 79 / d, x - 20 / d, y - 88 / d, x - 10 / d, y - 83 / d, x + 10 / d, y - 83 / d, x + 20 / d, y - 88 / d, x + 20 / d, y - 79 / d, x - 20 / d, y - 79 / d, END, END);
|
||||
hPlot(s, x - 20 / d, y - 88 / d, x - 30 / d, y - 83 / d, x - 30 / d, y - 78 / d, END, END);
|
||||
hPlot(s, x + 20 / d, y - 88 / d, x + 30 / d, y - 83 / d, x + 40 / d, y - 83 / d, END, END);
|
||||
hPlot(s, x - 15 / d, y - 86 / d, x - 20 / d, y - 83 / d, x - 20 / d, y - 78 / d, x - 30 / d, y - 73 / d, x - 30 / d, y - 68 / d, x - 20 / d, y - 63 / d, END, END);
|
||||
hPlot(s, x - 10 / d, y - 83 / d, x - 10 / d, y - 58 / d, x, y - 50 / d, END, END);
|
||||
hPlot(s, x + 10 / d, y - 83 / d, x + 10 / d, y - 78 / d, x + 20 / d, y - 73 / d, x + 20 / d, y - 40 / d, END, END);
|
||||
hPlot(s, x + 15 / d, y - 85 / d, x + 20 / d, y - 78 / d, x + 30 / d, y - 76 / d, x + 30 / d, y - 60 / d, END, END);
|
||||
hPlot(s, x, y - 83 / d, x, y - 73 / d, x + 10 / d, y - 68 / d, x + 10 / d, y - 63 / d, x, y - 58 / d, END, END);
|
||||
}
|
||||
|
||||
void Monster::drawGremlin(Graphics::ManagedSurface *s, double x, double y, double d) {
|
||||
hPlot(s, x + 5 / d + 1, y - 10 / d, x - 5 / d + 1, y - 10 / d, x, y - 15 / d, x + 10 / d, y - 20 / d, x + 5 / d + 1, y - 15 / d, x + 5 / d + 1, y - 10 / d, END, END);
|
||||
hPlot(s, x + 5 / d + 1, y - 10 / d, x + 7 / d + 1, y - 6 / d, x + 5 / d + 1, y - 3 / d, x - 5 / d + 1, y - 3 / d, x - 7 / d + 1, y - 6 / d, x - 5 / d + 1, y - 10 / d, END, END);
|
||||
hPlot(s, x + 2 / d + 1, y - 3 / d, x + 5 / d + 1, y, x + 8 / d, y, END, END);
|
||||
hPlot(s, x - 2 / d + 1, y - 3 / d, x - 5 / d + 1, y, x - 8 / d, y, END, END);
|
||||
hPlot(s, x + 3 / d + 1, y - 8 / d, END, END);
|
||||
hPlot(s, x - 3 / d + 1, y - 8 / d, END, END);
|
||||
hPlot(s, x + 3 / d + 1, y - 5 / d, x - 3 / d + 1, y - 5 / d, END, END);
|
||||
}
|
||||
|
||||
void Monster::drawMimic(Graphics::ManagedSurface *s, double x, double y, double d) {
|
||||
double xx = x;
|
||||
hPlot(s, 139 - 10 / d, xx, 139 - 10 / d, xx - 10 / d, 139 + 10 / d, xx - 10 / d, 139 + 10 / d, xx, 139 - 10 / d, xx, END, END);
|
||||
hPlot(s, 139 - 10 / d, xx - 10 / d, 139 - 5 / d, xx - 15 / d, 139 + 15 / d, xx - 15 / d, 139 + 15 / d, xx - 5 / d, 139 + 10 / d, xx, END, END);
|
||||
hPlot(s, 139 + 10 / d, xx - 10 / d, 139 + 15 / d, xx - 15 / d, END, END);
|
||||
}
|
||||
|
||||
void Monster::drawDaemon(Graphics::ManagedSurface *s, double x, double y, double d) {
|
||||
hPlot(s, x - 14 / d, y - 46 / d, x - 12 / d, y - 37 / d, x - 20 / d, y - 32 / d, x - 30 / d, y - 32 / d, x - 22 / d, y - 24 / d, x - 40 / d, y - 17 / d, x - 40 / d, y - 7 / d, x - 38 / d, y - 5 / d, x - 40 / d, y - 3 / d, x - 40 / d, y, END, END);
|
||||
hPlot(s, x - 40 / d, y, x - 36 / d, y, x - 34 / d, y - 2 / d, x - 32 / d, y, x - 28 / d, y, x - 28 / d, y - 3 / d, x - 30 / d, y - 5 / d, x - 28 / d, y - 7 / d, x - 28 / d, y - 15 / d, x, y - 27 / d, END, END);
|
||||
hPlot(s, x + 14 / d, y - 46 / d, x + 12 / d, y - 37 / d, x + 20 / d, y - 32 / d, x + 30 / d, y - 32 / d, x + 22 / d, y - 24 / d, x + 40 / d, y - 17 / d, x + 40 / d, y - 7 / d, x + 38 / d, y - 5 / d, x + 40 / d, y - 3 / d, x + 40 / d, y, END, END);
|
||||
hPlot(s, x + 40 / d, y, x + 36 / d, y, x + 34 / d, y - 2 / d, x + 32 / d, y, x + 28 / d, y, x + 28 / d, y - 3 / d, x + 30 / d, y - 5 / d, x + 28 / d, y - 7 / d, x + 28 / d, y - 15 / d, x, y - 27 / d, END, END);
|
||||
hPlot(s, x + 6 / d, y - 48 / d, x + 38 / d, y - 41 / d, x + 40 / d, y - 42 / d, x + 18 / d, y - 56 / d, x + 12 / d, y - 56 / d, x + 10 / d, y - 57 / d, x + 8 / d, y - 56 / d, x - 8 / d, y - 56 / d, x - 10 / d, y - 58 / d, x + 14 / d, y - 58 / d, x + 16 / d, y - 59 / d, END, END);
|
||||
hPlot(s, x + 16 / d, y - 59 / d, x + 8 / d, y - 63 / d, x + 6 / d, y - 63 / d, x + 2 / d + .5, y - 70 / d, x + 2 / d + .5, y - 63 / d, x - 2 / d + .5, y - 63 / d, x - 2 / d + .5, y - 70 / d, x - 6 / d, y - 63 / d, x - 8 / d, y - 63 / d, x - 16 / d, y - 59 / d, x - 14 / d, y - 58 / d, x - 10 / d, y - 58 / d, END, END);
|
||||
hPlot(s, x - 10 / d, y - 57 / d, x - 12 / d, y - 56 / d, x - 18 / d, y - 56 / d, x - 36 / d, y - 47 / d, x - 36 / d, y - 39 / d, x - 28 / d, y - 41 / d, x - 28 / d, y - 46 / d, x - 20 / d, y - 50 / d, x - 18 / d, y - 50 / d, x - 14 / d, y - 46 / d, END, END);
|
||||
hPlot(s, x - 28 / d, y - 41 / d, x + 30 / d, y - 55 / d, END, END);
|
||||
hPlot(s, x + 28 / d, y - 58 / d, x + 22 / d, y - 56 / d, x + 22 / d, y - 53 / d, x + 28 / d, y - 52 / d, x + 34 / d, y - 54 / d, END, END);
|
||||
hPlot(s, x + 20 / d, y - 50 / d, x + 26 / d, y - 47 / d, END, END);
|
||||
hPlot(s, x + 10 / d, y - 58 / d, x + 10 / d, y - 61 / d, x + 4 / d, y - 58 / d, END, END);
|
||||
hPlot(s, x - 10 / d, y - 58 / d, x - 10 / d, y - 61 / d, x - 4 / d, y - 58 / d, END, END);
|
||||
hPlot(s, x + 40 / d, y - 9 / d, x + 50 / d, y - 12 / d, x + 40 / d, y - 7 / d, END, END);
|
||||
hPlot(s, x - 8 / d, y - 25 / d, x + 6 / d, y - 7 / d, x + 28 / d, y - 7 / d, x + 28 / d, y - 9 / d, x + 20 / d, y - 9 / d, x + 6 / d, y - 25 / d, END, END);
|
||||
}
|
||||
|
||||
void Monster::drawBalrog(Graphics::ManagedSurface *s, double x, double y, double d) {
|
||||
hPlot(s, x + 6 / d, y - 60 / d, x + 30 / d, y - 90 / d, x + 60 / d, y - 30 / d, x + 60 / d, y - 10 / d, x + 30 / d, y - 40 / d, x + 15 / d, y - 40 / d, END, END);
|
||||
hPlot(s, x - 6 / d, y - 60 / d, x - 30 / d, y - 90 / d, x - 60 / d, y - 30 / d, x - 60 / d, y - 10 / d, x - 30 / d, y - 40 / d, x - 15 / d, y - 40 / d, END, END);
|
||||
hPlot(s, x, y - 25 / d, x + 6 / d, y - 25 / d, x + 10 / d, y - 20 / d, x + 12 / d, y - 10 / d, x + 10 / d, y - 6 / d, x + 10 / d, y, x + 14 / d, y, x + 15 / d, y - 5 / d, x + 16 / d, y, x + 20 / d, y, END, END);
|
||||
hPlot(s, x + 20 / d, y, x + 20 / d, y - 6 / d, x + 18 / d, y - 10 / d, x + 18 / d, y - 20 / d, x + 15 / d, y - 30 / d, x + 15 / d, y - 45 / d, x + 40 / d, y - 60 / d, x + 40 / d, y - 70 / d, END, END);
|
||||
hPlot(s, x + 40 / d, y - 70 / d, x + 10 / d, y - 55 / d, x + 6 / d, y - 60 / d, x + 10 / d, y - 74 / d, x + 6 / d, y - 80 / d, x + 4 / d + .5, y - 80 / d, x + 3 / d + .5, y - 82 / d, x + 2 / d + .5, y - 80 / d, x, y - 80 / d, END, END);
|
||||
hPlot(s, x, y - 25 / d, x - 6 / d, y - 25 / d, x - 10 / d, y - 20 / d, x - 12 / d, y - 10 / d, x - 10 / d, y - 6 / d, x - 10 / d, y, x - 14 / d, y, x - 15 / d, y - 5 / d, x - 16 / d, y, x - 20 / d, y, END, END);
|
||||
hPlot(s, x - 20 / d, y, x - 20 / d, y - 6 / d, x - 18 / d, y - 10 / d, x - 18 / d, y - 20 / d, x - 15 / d, y - 30 / d, x - 15 / d, y - 45 / d, x - 40 / d, y - 60 / d, x - 40 / d, y - 70 / d, END, END); // left wing
|
||||
hPlot(s, x - 40 / d, y - 70 / d, x - 10 / d, y - 55 / d, x - 6 / d, y - 60 / d, x - 10 / d, y - 74 / d, x - 6 / d, y - 80 / d, x - 4 / d + .5, y - 80 / d, x - 3 / d + .5, y - 82 / d, x - 2 / d + .5, y - 80 / d, x, y - 80 / d, END, END);
|
||||
hPlot(s, x - 6 / d, y - 25 / d, x, y - 6 / d, x + 10 / d, y, x + 4 / d + .5, y - 8 / d, x + 6 / d, y - 25 / d, END, END);
|
||||
hPlot(s, x - 40 / d, y - 64 / d, x - 40 / d, y - 90 / d, x - 52 / d, y - 80 / d, x - 52 / d, y - 40 / d, END, END);
|
||||
hPlot(s, x + 40 / d, y - 86 / d, x + 38 / d, y - 92 / d, x + 42 / d, y - 92 / d, x + 40 / d, y - 86 / d, x + 40 / d, y - 50 / d, END, END);
|
||||
hPlot(s, x + 4 / d + .5, y - 70 / d, x + 6 / d, y - 74 / d, END, END);
|
||||
hPlot(s, x - 4 / d + .5, y - 70 / d, x - 6 / d, y - 74 / d, END, END);
|
||||
hPlot(s, x, y - 64 / d, x, y - 60 / d, END, END);
|
||||
}
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
67
engines/ultima/ultima0/gfx/monster.h
Normal file
67
engines/ultima/ultima0/gfx/monster.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ULTIMA0_GFX_MONSTER_H
|
||||
#define ULTIMA0_GFX_MONSTER_H
|
||||
|
||||
#include "graphics/managed_surface.h"
|
||||
#include "ultima/ultima0/data/data.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Gfx {
|
||||
|
||||
class Monster {
|
||||
private:
|
||||
// Drawing position
|
||||
static int _xPos, _yPos;
|
||||
|
||||
/**
|
||||
* Emulate the Apple ][ HPLOT function
|
||||
*/
|
||||
static void hPlot(Graphics::ManagedSurface *s, double x, double y, ...);
|
||||
|
||||
/**
|
||||
* Monster drawing functions
|
||||
*/
|
||||
typedef void(*DrawFn)(Graphics::ManagedSurface *s, double x, double y, double d);
|
||||
static void drawSkeleton(Graphics::ManagedSurface *s, double x,double y,double d);
|
||||
static void drawThief(Graphics::ManagedSurface *s, double x,double y,double d);
|
||||
static void drawRat(Graphics::ManagedSurface *s, double x,double y,double d);
|
||||
static void drawOrc(Graphics::ManagedSurface *s, double x,double y,double d);
|
||||
static void drawViper(Graphics::ManagedSurface *s, double x,double y,double d);
|
||||
static void drawCarrion(Graphics::ManagedSurface *s, double x,double y,double d);
|
||||
static void drawGremlin(Graphics::ManagedSurface *s, double x,double y,double d);
|
||||
static void drawMimic(Graphics::ManagedSurface *s, double x,double y,double d);
|
||||
static void drawDaemon(Graphics::ManagedSurface *s, double x,double y,double d);
|
||||
static void drawBalrog(Graphics::ManagedSurface *s, double x,double y,double d);
|
||||
static DrawFn DRAW_FUNCTIONS[];
|
||||
|
||||
public:
|
||||
static void draw(Graphics::ManagedSurface *s, int x, int y,
|
||||
int monster, double scale);
|
||||
};
|
||||
|
||||
} // namespace Gfx
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
|
||||
#endif
|
||||
45
engines/ultima/ultima0/messages.cpp
Normal file
45
engines/ultima/ultima0/messages.cpp
Normal 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/ultima0/messages.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
|
||||
MouseMessage::MouseMessage(Common::EventType type,
|
||||
const Common::Point &pos) : Message(), _pos(pos) {
|
||||
switch (type) {
|
||||
case Common::EVENT_RBUTTONDOWN:
|
||||
case Common::EVENT_RBUTTONUP:
|
||||
_button = MB_RIGHT;
|
||||
break;
|
||||
case Common::EVENT_MBUTTONDOWN:
|
||||
case Common::EVENT_MBUTTONUP:
|
||||
_button = MB_MIDDLE;
|
||||
break;
|
||||
default:
|
||||
_button = MB_LEFT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
134
engines/ultima/ultima0/messages.h
Normal file
134
engines/ultima/ultima0/messages.h
Normal file
@@ -0,0 +1,134 @@
|
||||
/* 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 ULTIMA0_MESSAGES_H
|
||||
#define ULTIMA0_MESSAGES_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/events.h"
|
||||
#include "common/str.h"
|
||||
#include "ultima/ultima0/metaengine.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
|
||||
class UIElement;
|
||||
|
||||
struct Message {};
|
||||
|
||||
struct FocusMessage : public Message {
|
||||
UIElement *_priorView = nullptr;
|
||||
FocusMessage() : Message() {
|
||||
}
|
||||
FocusMessage(UIElement *priorView) : Message(),
|
||||
_priorView(priorView) {
|
||||
}
|
||||
};
|
||||
|
||||
struct UnfocusMessage : public Message {};
|
||||
struct MouseEnterMessage : public Message {};
|
||||
struct MouseLeaveMessage : public Message {};
|
||||
|
||||
struct KeypressMessage : public Message, public Common::KeyState {
|
||||
KeypressMessage() : Message() {
|
||||
}
|
||||
KeypressMessage(const Common::KeyState &ks) :
|
||||
Message(), Common::KeyState(ks) {
|
||||
}
|
||||
};
|
||||
|
||||
struct MouseMessage : public Message {
|
||||
enum Button {
|
||||
MB_LEFT, MB_RIGHT, MB_MIDDLE
|
||||
};
|
||||
Button _button;
|
||||
Common::Point _pos;
|
||||
|
||||
MouseMessage() : Message(), _button(MB_LEFT) {
|
||||
}
|
||||
MouseMessage(Button btn, const Common::Point &pos) :
|
||||
Message(), _button(btn), _pos(pos) {
|
||||
}
|
||||
MouseMessage(Common::EventType type, const Common::Point &pos);
|
||||
};
|
||||
struct MouseDownMessage : public MouseMessage {
|
||||
MouseDownMessage() : MouseMessage() {
|
||||
}
|
||||
MouseDownMessage(Button btn, const Common::Point &pos) :
|
||||
MouseMessage(btn, pos) {
|
||||
}
|
||||
MouseDownMessage(Common::EventType type, const Common::Point &pos) :
|
||||
MouseMessage(type, pos) {
|
||||
}
|
||||
};
|
||||
struct MouseUpMessage : public MouseMessage {
|
||||
MouseUpMessage() : MouseMessage() {
|
||||
}
|
||||
MouseUpMessage(Button btn, const Common::Point &pos) :
|
||||
MouseMessage(btn, pos) {
|
||||
}
|
||||
MouseUpMessage(Common::EventType type, const Common::Point &pos) :
|
||||
MouseMessage(type, pos) {
|
||||
}
|
||||
};
|
||||
typedef MouseMessage MouseMoveMessage;
|
||||
|
||||
struct GameMessage : public Message {
|
||||
Common::String _name;
|
||||
int _value;
|
||||
Common::String _stringValue;
|
||||
|
||||
GameMessage() : Message(), _value(-1) {
|
||||
}
|
||||
GameMessage(const Common::String &name) : Message(),
|
||||
_name(name), _value(-1) {
|
||||
}
|
||||
GameMessage(const Common::String &name, int value) : Message(),
|
||||
_name(name), _value(value) {
|
||||
}
|
||||
GameMessage(const Common::String &name, const Common::String &value) :
|
||||
Message(), _name(name), _stringValue(value) {
|
||||
}
|
||||
};
|
||||
|
||||
struct ValueMessage : public Message {
|
||||
int _value;
|
||||
|
||||
ValueMessage() : Message(), _value(0) {
|
||||
}
|
||||
ValueMessage(int value) : Message(),
|
||||
_value(value) {
|
||||
}
|
||||
};
|
||||
|
||||
struct ActionMessage : public Message {
|
||||
int _action;
|
||||
ActionMessage() : Message(), _action(0) {
|
||||
}
|
||||
ActionMessage(int action) : Message(),
|
||||
_action(action) {
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
|
||||
#endif
|
||||
204
engines/ultima/ultima0/metaengine.cpp
Normal file
204
engines/ultima/ultima0/metaengine.cpp
Normal file
@@ -0,0 +1,204 @@
|
||||
/* 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/ultima0/metaengine.h"
|
||||
#include "ultima/ultima0/ultima0.h"
|
||||
#include "common/translation.h"
|
||||
#include "backends/keymapper/action.h"
|
||||
#include "backends/keymapper/standard-actions.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
|
||||
struct KeybindingRecord {
|
||||
KeybindingAction _action;
|
||||
const char *_id;
|
||||
const char *_desc;
|
||||
const char *_key;
|
||||
const char *_joy;
|
||||
};
|
||||
|
||||
static const KeybindingRecord MINIMAL_KEYS[] = {
|
||||
{ KEYBIND_ESCAPE, "ESCAPE", _s("Escape"), "ESCAPE", "JOY_Y" },
|
||||
{ KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr }
|
||||
};
|
||||
|
||||
static const KeybindingRecord MENU_KEYS[] = {
|
||||
{ KEYBIND_UP, "UP", _s("Up"), "UP", "JOY_UP" },
|
||||
{ KEYBIND_DOWN, "DOWN", _s("Down"), "DOWN", "JOY_DOWN" },
|
||||
{ KEYBIND_SELECT, "SELECT", _s("Select"), "SPACE", nullptr },
|
||||
{ KEYBIND_QUIT, "QUIT", _s("Quit"), "q", nullptr },
|
||||
{ KEYBIND_SWING, "SWING", _s("Swing"), "s", nullptr },
|
||||
{ KEYBIND_THROW, "THROW", _s("Throw"), "t", nullptr },
|
||||
{ KEYBIND_FOOD, "FOOD", _s("Food"), "f", nullptr },
|
||||
{ KEYBIND_RAPIER, "RAPIER", _s("Rapier"), "r", nullptr },
|
||||
{ KEYBIND_AXE, "AXE", _s("Axe"), "a", nullptr },
|
||||
{ KEYBIND_SHIELD, "SHIELD", _s("Shield"), "s", nullptr },
|
||||
{ KEYBIND_BOW, "BOW", _s("Bow & Arrow"), "b", nullptr },
|
||||
{ KEYBIND_AMULET, "AMULET", _s("Magic Amulet"), "m", nullptr },
|
||||
{ KEYBIND_AMULET1, "AMULET1", _s("Amulet Option 1"), "1", nullptr },
|
||||
{ KEYBIND_AMULET2, "AMULET2", _s("Amulet Option 2"), "2", nullptr },
|
||||
{ KEYBIND_AMULET3, "AMULET3", _s("Amulet Option 3"), "3", nullptr },
|
||||
{ KEYBIND_AMULET4, "AMULET4", _s("Amulet Option 4"), "4", nullptr },
|
||||
{ KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr }
|
||||
};
|
||||
|
||||
static const KeybindingRecord OVERWORLD_KEYS[] = {
|
||||
{ KEYBIND_UP, "UP", _s("North"), "UP", "JOY_UP" },
|
||||
{ KEYBIND_DOWN, "DOWN", _s("South"), "DOWN", "JOY_DOWN" },
|
||||
{ KEYBIND_LEFT, "LEFT", _s("West"), "LEFT", "JOY_LEFT" },
|
||||
{ KEYBIND_RIGHT, "RIGHT", _s("East"), "RIGHT", "JOY_RIGHT" },
|
||||
{ KEYBIND_ENTER, "ENTER", _s("Enter/Exit"), "e", "JOY_B" },
|
||||
{ KEYBIND_INFO, "INFO", _s("Info"), "z", "JOY_X" },
|
||||
{ KEYBIND_QUIT, "QUIT", _s("Quit"), "q", nullptr },
|
||||
{ KEYBIND_PASS, "PASS", _s("Pass/Wait"), "SPACE", nullptr },
|
||||
{ KEYBIND_MINIMAP, "MINIMAP", _s("Minimap"), "m", nullptr },
|
||||
{ KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr }
|
||||
};
|
||||
|
||||
static const KeybindingRecord DUNGEON_KEYS[] = {
|
||||
{ KEYBIND_UP, "UP", _s("Move Forward"), "UP", "JOY_UP" },
|
||||
{ KEYBIND_DOWN, "DOWN", _s("Turn Around"), "DOWN", "JOY_DOWN" },
|
||||
{ KEYBIND_LEFT, "LEFT", _s("Turn Left"), "LEFT", "JOY_LEFT" },
|
||||
{ KEYBIND_RIGHT, "RIGHT", _s("Turn Right"), "RIGHT", "JOY_RIGHT" },
|
||||
{ KEYBIND_ATTACK, "ATTACK", _s("Attack"), "a", "JOY_A" },
|
||||
{ KEYBIND_ENTER, "ENTER", _s("Enter/Exit"), "e", "JOY_B" },
|
||||
{ KEYBIND_INFO, "INFO", _s("Info"), "z", "JOY_X" },
|
||||
{ KEYBIND_QUIT, "QUIT", _s("Quit"), "q", nullptr },
|
||||
{ KEYBIND_PASS, "PASS", _s("Pass/Wait"), "SPACE", nullptr },
|
||||
{ KEYBIND_MINIMAP, "MINIMAP", _s("Minimap"), "m", nullptr },
|
||||
{ KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr }
|
||||
};
|
||||
|
||||
struct KeysRecord {
|
||||
const char *_id;
|
||||
const char *_desc;
|
||||
const KeybindingRecord *_keys;
|
||||
};
|
||||
|
||||
static const KeysRecord ALL_RECORDS[] = {
|
||||
{ "ultima0", _s("Basic Keys"), MINIMAL_KEYS },
|
||||
{ "menu", _s("Menu Keys"), MENU_KEYS },
|
||||
{ "overworld", _s("Overworld Keys"), OVERWORLD_KEYS },
|
||||
{ "dungeon", _s("Dungeon Keys"), DUNGEON_KEYS },
|
||||
{ nullptr, nullptr, nullptr }
|
||||
};
|
||||
|
||||
static const KeysRecord MINIMAL_RECORDS[] = {
|
||||
{ "ultima0", _s("Basic Keys"), MINIMAL_KEYS },
|
||||
{ nullptr, nullptr, nullptr }
|
||||
};
|
||||
|
||||
static const KeysRecord MENU_RECORDS[] = {
|
||||
{ "ultima0", _s("Basic Keys"), MINIMAL_KEYS },
|
||||
{ "menu", _s("Menu Keys"), MENU_KEYS },
|
||||
{ nullptr, nullptr, nullptr }
|
||||
};
|
||||
|
||||
static const KeysRecord OVERWORLD_RECORDS[] = {
|
||||
{ "ultima0", _s("Basic Keys"), MINIMAL_KEYS },
|
||||
{ "overworld", _s("Overworld Keys"), OVERWORLD_KEYS },
|
||||
{ nullptr, nullptr, nullptr }
|
||||
};
|
||||
|
||||
static const KeysRecord DUNGEON_RECORDS[] = {
|
||||
{ "ultima0", _s("Basic Keys"), MINIMAL_KEYS },
|
||||
{ "dungeon", _s("Dungeon Keys"), DUNGEON_KEYS },
|
||||
{ nullptr, nullptr, nullptr }
|
||||
};
|
||||
|
||||
static const KeysRecord *MODE_RECORDS[] = {
|
||||
ALL_RECORDS,
|
||||
MINIMAL_RECORDS,
|
||||
MENU_RECORDS,
|
||||
OVERWORLD_RECORDS,
|
||||
DUNGEON_RECORDS,
|
||||
};
|
||||
|
||||
Common::KeymapArray MetaEngine::initKeymaps(KeybindingMode mode) {
|
||||
Common::KeymapArray keymapArray;
|
||||
Common::Keymap *keyMap;
|
||||
Common::Action *act;
|
||||
const KeysRecord *recPtr = MODE_RECORDS[mode];
|
||||
|
||||
for (int kCtr = 0; recPtr->_id; ++recPtr, ++kCtr) {
|
||||
// Core keymaps
|
||||
keyMap = new Common::Keymap(Common::Keymap::kKeymapTypeGame,
|
||||
recPtr->_id, recPtr->_desc);
|
||||
keymapArray.push_back(keyMap);
|
||||
|
||||
if (kCtr == 0) {
|
||||
addMouseClickActions(*keyMap);
|
||||
}
|
||||
|
||||
for (const KeybindingRecord *r = recPtr->_keys; r->_id; ++r) {
|
||||
act = new Common::Action(r->_id, _(r->_desc));
|
||||
act->setCustomEngineActionEvent(r->_action);
|
||||
act->addDefaultInputMapping(r->_key);
|
||||
if (r->_joy)
|
||||
act->addDefaultInputMapping(r->_joy);
|
||||
if (r->_action == KEYBIND_ENTER)
|
||||
act->addDefaultInputMapping("x"); // x also works to eXit
|
||||
else if (r->_action == KEYBIND_SELECT)
|
||||
act->addDefaultInputMapping("RETURN");
|
||||
else if (r->_action == KEYBIND_QUIT)
|
||||
act->addDefaultInputMapping("p"); // Map "Pause" to Quit
|
||||
|
||||
if (r->_action == KEYBIND_UP || r->_action == KEYBIND_DOWN ||
|
||||
r->_action == KEYBIND_LEFT || r->_action == KEYBIND_RIGHT)
|
||||
// Allow movement actions to be triggered on keyboard repeats
|
||||
act->allowKbdRepeats();
|
||||
|
||||
keyMap->addAction(act);
|
||||
}
|
||||
}
|
||||
|
||||
return keymapArray;
|
||||
}
|
||||
|
||||
void MetaEngine::addMouseClickActions(Common::Keymap &keyMap) {
|
||||
Common::Action *act;
|
||||
|
||||
act = new Common::Action(Common::kStandardActionLeftClick, _("Left click"));
|
||||
act->setLeftClickEvent();
|
||||
act->addDefaultInputMapping("MOUSE_LEFT");
|
||||
act->addDefaultInputMapping("JOY_A");
|
||||
keyMap.addAction(act);
|
||||
|
||||
act = new Common::Action(Common::kStandardActionRightClick, _("Right click"));
|
||||
act->setRightClickEvent();
|
||||
act->addDefaultInputMapping("MOUSE_RIGHT");
|
||||
act->addDefaultInputMapping("JOY_B");
|
||||
keyMap.addAction(act);
|
||||
}
|
||||
|
||||
void MetaEngine::setKeybindingMode(KeybindingMode mode) {
|
||||
Common::Keymapper *const mapper = g_engine->getEventManager()->getKeymapper();
|
||||
mapper->cleanupGameKeymaps();
|
||||
|
||||
Common::KeymapArray arr = initKeymaps(mode);
|
||||
|
||||
for (uint idx = 0; idx < arr.size(); ++idx)
|
||||
mapper->addGameKeymap(arr[idx]);
|
||||
}
|
||||
|
||||
} // End of namespace Ultima0
|
||||
} // End of namespace Ultima
|
||||
72
engines/ultima/ultima0/metaengine.h
Normal file
72
engines/ultima/ultima0/metaengine.h
Normal 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ULTIMA0_METAENGINE_H
|
||||
#define ULTIMA0_METAENGINE_H
|
||||
|
||||
#include "backends/keymapper/keymapper.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
|
||||
enum KeybindingAction {
|
||||
KEYBIND_UP, KEYBIND_DOWN, KEYBIND_LEFT, KEYBIND_RIGHT,
|
||||
KEYBIND_ESCAPE, KEYBIND_QUIT, KEYBIND_ENTER, KEYBIND_INFO,
|
||||
KEYBIND_PASS, KEYBIND_ATTACK, KEYBIND_SWING, KEYBIND_THROW,
|
||||
KEYBIND_AMULET1, KEYBIND_AMULET2, KEYBIND_AMULET3, KEYBIND_AMULET4,
|
||||
KEYBIND_MINIMAP,
|
||||
|
||||
KEYBIND_SELECT, KEYBIND_FOOD, KEYBIND_RAPIER, KEYBIND_AXE,
|
||||
KEYBIND_SHIELD, KEYBIND_BOW, KEYBIND_AMULET,
|
||||
|
||||
KEYBIND_NONE
|
||||
};
|
||||
|
||||
enum KeybindingMode {
|
||||
KBMODE_ALL,
|
||||
KBMODE_MINIMAL,
|
||||
KBMODE_MENUS,
|
||||
KBMODE_OVERWORLD,
|
||||
KBMODE_DUNGEONS
|
||||
};
|
||||
|
||||
class MetaEngine {
|
||||
private:
|
||||
/**
|
||||
* Adds the default actions for the mouse buttons
|
||||
*/
|
||||
static void addMouseClickActions(Common::Keymap &keyMap);
|
||||
public:
|
||||
/**
|
||||
* Initialize keymaps
|
||||
*/
|
||||
static Common::KeymapArray initKeymaps(KeybindingMode mode = KBMODE_ALL);
|
||||
|
||||
/**
|
||||
* Sets the current set of actions which are active
|
||||
*/
|
||||
static void setKeybindingMode(KeybindingMode mode);
|
||||
};
|
||||
|
||||
} // End of namespace Ultima0
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
||||
93
engines/ultima/ultima0/music.cpp
Normal file
93
engines/ultima/ultima0/music.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
/* 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 "audio/mididrv.h"
|
||||
#include "audio/midiparser.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/file.h"
|
||||
#include "ultima/ultima0/music.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
|
||||
MusicPlayer::MusicPlayer(const char *filename) : _filename(filename) {
|
||||
MidiPlayer::createDriver();
|
||||
|
||||
int ret = _driver->open();
|
||||
if (ret == 0) {
|
||||
if (_nativeMT32)
|
||||
_driver->sendMT32Reset();
|
||||
else
|
||||
_driver->sendGMReset();
|
||||
|
||||
_driver->setTimerCallback(this, &timerCallback);
|
||||
}
|
||||
}
|
||||
|
||||
void MusicPlayer::sendToChannel(byte channel, uint32 b) {
|
||||
if (!_channelsTable[channel]) {
|
||||
_channelsTable[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
|
||||
// If a new channel is allocated during the playback, make sure
|
||||
// its volume is correctly initialized.
|
||||
if (_channelsTable[channel])
|
||||
_channelsTable[channel]->volume(_channelsVolume[channel] * _masterVolume / 255);
|
||||
}
|
||||
|
||||
if (_channelsTable[channel])
|
||||
_channelsTable[channel]->send(b);
|
||||
}
|
||||
|
||||
void MusicPlayer::playSMF(bool loop) {
|
||||
Common::StackLock lock(_mutex);
|
||||
|
||||
stop();
|
||||
|
||||
// Load MIDI resource data
|
||||
Common::File musicFile;
|
||||
if (!musicFile.open(_filename))
|
||||
return;
|
||||
|
||||
int midiMusicSize = musicFile.size();
|
||||
free(_midiData);
|
||||
_midiData = (byte *)malloc(midiMusicSize);
|
||||
musicFile.read(_midiData, midiMusicSize);
|
||||
musicFile.close();
|
||||
|
||||
MidiParser *parser = MidiParser::createParser_SMF();
|
||||
if (parser->loadMusic(_midiData, midiMusicSize)) {
|
||||
parser->setTrack(0);
|
||||
parser->setMidiDriver(this);
|
||||
parser->setTimerRate(_driver->getBaseTempo());
|
||||
parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
|
||||
|
||||
_parser = parser;
|
||||
|
||||
syncVolume();
|
||||
|
||||
_isLooping = loop;
|
||||
_isPlaying = true;
|
||||
} else {
|
||||
delete parser;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
47
engines/ultima/ultima0/music.h
Normal file
47
engines/ultima/ultima0/music.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// Music class
|
||||
|
||||
#ifndef ULTIMA_ULTIMA0_MUSIC_H
|
||||
#define ULTIMA_ULTIMA0_MUSIC_H
|
||||
|
||||
#include "audio/midiplayer.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
|
||||
class MusicPlayer : public Audio::MidiPlayer {
|
||||
private:
|
||||
Common::Path _filename;
|
||||
|
||||
public:
|
||||
MusicPlayer(const char *filename);
|
||||
void playSMF(bool loop = true);
|
||||
|
||||
// Overload Audio::MidiPlayer method
|
||||
void sendToChannel(byte channel, uint32 b) override;
|
||||
};
|
||||
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
|
||||
#endif
|
||||
138
engines/ultima/ultima0/ultima0.cpp
Normal file
138
engines/ultima/ultima0/ultima0.cpp
Normal 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/system.h"
|
||||
#include "common/savefile.h"
|
||||
#include "engines/util.h"
|
||||
#include "graphics/paletteman.h"
|
||||
#include "ultima/ultima0/ultima0.h"
|
||||
#include "ultima/ultima0/console.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
|
||||
static const byte PALETTE[][3] = {
|
||||
{ 0, 0, 0 }, // Black
|
||||
{ 0, 0, 255 }, // Blue
|
||||
{ 0, 255, 0 }, // Green,
|
||||
{ 0, 255, 255 }, // Cyan
|
||||
{ 255, 0, 0 }, // Red
|
||||
{ 255, 0, 255 }, // Purple
|
||||
{ 255, 255, 0 }, // Yellow
|
||||
{ 255, 255, 255 }, // White
|
||||
{ 255, 0, 128 }, // Rose
|
||||
{ 80, 80, 255 }, // Violet
|
||||
{ 180, 180, 180 }, // Grey
|
||||
{ 255, 80, 80 } // Orange
|
||||
};
|
||||
|
||||
|
||||
Ultima0Engine *g_engine;
|
||||
|
||||
Ultima0Engine::Ultima0Engine(OSystem *syst, const Ultima::UltimaGameDescription *gameDesc) :
|
||||
Engine(syst), /*_gameDescription(gameDesc), */_randomSource("Ultima0"),
|
||||
_palette(&PALETTE[0][0], sizeof(PALETTE) / 3) {
|
||||
g_engine = this;
|
||||
}
|
||||
|
||||
Ultima0Engine::~Ultima0Engine() {
|
||||
stopMidi();
|
||||
}
|
||||
|
||||
Common::Error Ultima0Engine::run() {
|
||||
// Initialize the graphics
|
||||
initGraphics(DEFAULT_SCX, DEFAULT_SCY);
|
||||
g_system->getPaletteManager()->setPalette(_palette);
|
||||
|
||||
// Set the debugger console
|
||||
setDebugger(new Console());
|
||||
MetaEngine::setKeybindingMode(KBMODE_MINIMAL);
|
||||
|
||||
// Play the game
|
||||
runGame();
|
||||
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
bool Ultima0Engine::hasFeature(EngineFeature f) const {
|
||||
return (f == kSupportsReturnToLauncher) ||
|
||||
(f == kSupportsLoadingDuringRuntime) ||
|
||||
(f == kSupportsSavingDuringRuntime);
|
||||
|
||||
}
|
||||
|
||||
bool Ultima0Engine::canSaveGameStateCurrently(Common::U32String *msg) {
|
||||
auto *view = focusedView();
|
||||
if (!view)
|
||||
return false;
|
||||
|
||||
Common::String name = focusedView()->getName();
|
||||
return name == "WorldMap" || name == "Dungeon";
|
||||
}
|
||||
|
||||
Common::Error Ultima0Engine::loadGameStream(Common::SeekableReadStream *stream) {
|
||||
Common::Serializer s(stream, nullptr);
|
||||
syncSavegame(s);
|
||||
|
||||
stopMidi();
|
||||
replaceView(_player._level == 0 ? "WorldMap" : "Dungeon");
|
||||
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
Common::Error Ultima0Engine::saveGameStream(Common::WriteStream *stream, bool isAutosave) {
|
||||
Common::Serializer s(nullptr, stream);
|
||||
syncSavegame(s);
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
void Ultima0Engine::syncSavegame(Common::Serializer &s) {
|
||||
_player.synchronize(s);
|
||||
_worldMap.synchronize(s);
|
||||
_dungeon.synchronize(s);
|
||||
}
|
||||
|
||||
bool Ultima0Engine::savegamesExist() const {
|
||||
Common::String slotName = getSaveStateName(1);
|
||||
Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(slotName);
|
||||
bool result = saveFile != nullptr;
|
||||
|
||||
delete saveFile;
|
||||
return result;
|
||||
}
|
||||
|
||||
void Ultima0Engine::playMidi(const char *name) {
|
||||
stopMidi();
|
||||
|
||||
_music = new MusicPlayer(name);
|
||||
_music->playSMF(true);
|
||||
}
|
||||
|
||||
void Ultima0Engine::stopMidi() {
|
||||
if (_music) {
|
||||
_music->stop();
|
||||
delete _music;
|
||||
_music = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
137
engines/ultima/ultima0/ultima0.h
Normal file
137
engines/ultima/ultima0/ultima0.h
Normal file
@@ -0,0 +1,137 @@
|
||||
/* 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 ULTIMA0_H
|
||||
#define ULTIMA0_H
|
||||
|
||||
#include "common/random.h"
|
||||
#include "common/serializer.h"
|
||||
#include "graphics/palette.h"
|
||||
#include "engines/engine.h"
|
||||
#include "ultima/detection.h"
|
||||
#include "ultima/ultima0/data/data.h"
|
||||
#include "ultima/ultima0/events.h"
|
||||
#include "ultima/ultima0/music.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
|
||||
class Ultima0Engine : public Engine, public Events {
|
||||
private:
|
||||
Common::RandomSource _randomSource;
|
||||
//const UltimaGameDescription *_gameDescription;
|
||||
|
||||
void syncSavegame(Common::Serializer &s);
|
||||
|
||||
protected:
|
||||
// Engine APIs
|
||||
Common::Error run() override;
|
||||
|
||||
public:
|
||||
Graphics::Palette _palette;
|
||||
PlayerInfo _player;
|
||||
WorldMapInfo _worldMap;
|
||||
DungeonMapInfo _dungeon;
|
||||
bool _showMinimap = false;
|
||||
MusicPlayer *_music = nullptr;
|
||||
|
||||
Ultima0Engine(OSystem *syst, const Ultima::UltimaGameDescription *gameDesc);
|
||||
~Ultima0Engine() override;
|
||||
|
||||
/**
|
||||
* Returns true if the game should quit
|
||||
*/
|
||||
bool shouldQuit() const override {
|
||||
return Engine::shouldQuit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns supported engine features
|
||||
*/
|
||||
bool hasFeature(EngineFeature f) const override;
|
||||
|
||||
/**
|
||||
* Sets the random number seed
|
||||
*/
|
||||
void setRandomSeed(uint seed) {
|
||||
_randomSource.setSeed(seed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a random number
|
||||
*/
|
||||
uint getRandomNumber(uint maxVal = RND_MAX) { return _randomSource.getRandomNumber(maxVal); }
|
||||
uint getRandomNumber(uint minVal, uint maxVal) {
|
||||
return _randomSource.getRandomNumber(maxVal - minVal) + minVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if enhancements are turned on
|
||||
*/
|
||||
bool isEnhanced() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a savegame can be loaded
|
||||
*/
|
||||
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the game can be saved
|
||||
*/
|
||||
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
|
||||
|
||||
/**
|
||||
* Load a game state.
|
||||
* @param stream the stream to load the savestate from
|
||||
* @return returns kNoError on success, else an error code.
|
||||
*/
|
||||
Common::Error loadGameStream(Common::SeekableReadStream *stream) override;
|
||||
|
||||
/**
|
||||
* Save a game state.
|
||||
* @param stream The write stream to save the savegame data to
|
||||
* @param isAutosave Expected to be true if an autosave is being created
|
||||
* @return returns kNoError on success, else an error code.
|
||||
*/
|
||||
Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave = false) override;
|
||||
|
||||
/**
|
||||
* Returns true if any savegames exist
|
||||
*/
|
||||
bool savegamesExist() const;
|
||||
|
||||
void playMidi(const char *name);
|
||||
void stopMidi();
|
||||
bool isMidiPlaying() const {
|
||||
return _music != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
extern Ultima0Engine *g_engine;
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
||||
112
engines/ultima/ultima0/views/acknowledgements.cpp
Normal file
112
engines/ultima/ultima0/views/acknowledgements.cpp
Normal 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ultima/ultima0/views/acknowledgements.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
static const char *LINES[] = {
|
||||
"Akalabeth PC-Conversion",
|
||||
"",
|
||||
"",
|
||||
"Written by Richard Garriott",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"PC-Conversion by",
|
||||
"Corey Roth",
|
||||
"with special assistance by",
|
||||
"Nathan Tucker",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"Greets and Thanx go out to",
|
||||
"Jake Groshong",
|
||||
"Ronny McCrory",
|
||||
"Adrian Dilley",
|
||||
"Russell Kabir",
|
||||
"James Ashley",
|
||||
"Chris Harjo",
|
||||
"and everyone else out there",
|
||||
"who helped me out",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"This game made possible by:",
|
||||
"",
|
||||
"Origin",
|
||||
"and",
|
||||
"JUiCEY Bird Productions"
|
||||
};
|
||||
|
||||
|
||||
bool Acknowledgements::msgFocus(const FocusMessage &msg) {
|
||||
// Set up the lines to display
|
||||
_ctr = -1;
|
||||
_lines.clear();
|
||||
for (const char *line : LINES)
|
||||
_lines.push(line);
|
||||
|
||||
for (int i = 0; i < 25; ++i)
|
||||
_lines.push("");
|
||||
|
||||
auto s = getSurface();
|
||||
s.clear();
|
||||
|
||||
// Create a buffer for rendering new lines
|
||||
_pendingLine.create(s.w, Gfx::GLYPH_HEIGHT);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Acknowledgements::draw() {
|
||||
auto s = getSurface();
|
||||
|
||||
// Shift up by one line
|
||||
s.blitFrom(s, Common::Rect(0, 1, s.w, s.h), Common::Point(0, 0));
|
||||
s.blitFrom(_pendingLine, Common::Rect(0, 0, _pendingLine.w, 1),
|
||||
Common::Point(0, s.h - 1));
|
||||
_pendingLine.blitFrom(_pendingLine, Common::Rect(0, 1, s.w, Gfx::GLYPH_HEIGHT),
|
||||
Common::Point(0, 0));
|
||||
}
|
||||
|
||||
bool Acknowledgements::tick() {
|
||||
_ctr = (_ctr + 1) % Gfx::GLYPH_HEIGHT;
|
||||
if (_ctr == 0) {
|
||||
if (_lines.empty()) {
|
||||
showTitle();
|
||||
} else {
|
||||
Common::String line = _lines.pop();
|
||||
_pendingLine.writeString(Common::Point(20, 0), line, Graphics::kTextAlignCenter);
|
||||
}
|
||||
}
|
||||
|
||||
redraw();
|
||||
return View::tick();
|
||||
}
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
66
engines/ultima/ultima0/views/acknowledgements.h
Normal file
66
engines/ultima/ultima0/views/acknowledgements.h
Normal 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 ULTIMA0_VIEWS_ACKNOWLEDGEMENTS_H
|
||||
#define ULTIMA0_VIEWS_ACKNOWLEDGEMENTS_H
|
||||
|
||||
#include "common/queue.h"
|
||||
#include "ultima/ultima0/views/view.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
class Acknowledgements : public View {
|
||||
private:
|
||||
Common::Queue<Common::String> _lines;
|
||||
Gfx::GfxSurface _pendingLine;
|
||||
int _ctr = 0;
|
||||
|
||||
void showTitle() {
|
||||
replaceView("Title");
|
||||
}
|
||||
public:
|
||||
Acknowledgements() : View("Acknowledgements") {}
|
||||
~Acknowledgements() override {}
|
||||
|
||||
bool msgFocus(const FocusMessage &msg) override;
|
||||
void draw() override;
|
||||
bool tick() override;
|
||||
bool msgKeypress(const KeypressMessage &msg) override {
|
||||
showTitle();
|
||||
return true;
|
||||
}
|
||||
bool msgMouseDown(const MouseDownMessage &msg) override {
|
||||
showTitle();
|
||||
return true;
|
||||
}
|
||||
bool msgAction(const ActionMessage &msg) override {
|
||||
showTitle();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
|
||||
#endif
|
||||
330
engines/ultima/ultima0/views/attack.cpp
Normal file
330
engines/ultima/ultima0/views/attack.cpp
Normal file
@@ -0,0 +1,330 @@
|
||||
/* 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/ultima0/views/attack.h"
|
||||
#include "ultima/ultima0/data/data.h"
|
||||
#include "ultima/ultima0/ultima0.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
Attack::Attack() : View("Attack") {
|
||||
setBounds(Gfx::TextRect(1, 22, 26, 24));
|
||||
}
|
||||
|
||||
bool Attack::msgFocus(const FocusMessage &msg) {
|
||||
_mode = WHICH_WEAPON;
|
||||
_message = "";
|
||||
MetaEngine::setKeybindingMode(KBMODE_MENUS);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Attack::msgUnfocus(const UnfocusMessage &msg) {
|
||||
MetaEngine::setKeybindingMode(KBMODE_MINIMAL);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Attack::draw() {
|
||||
auto s = getSurface();
|
||||
s.clear();
|
||||
|
||||
if (_mode == AMULET) {
|
||||
s.writeString(Common::Point(0, 0), "1] Ladder Up");
|
||||
s.writeString(Common::Point(0, 1), "2] Ladder Down");
|
||||
s.writeString(Common::Point(0, 2), "3] Attack Monster");
|
||||
s.writeString(Common::Point(0, 3), "4] Bad Magic");
|
||||
return;
|
||||
}
|
||||
|
||||
s.writeString(Common::Point(1, 1), "Which Weapon? ");
|
||||
if (_mode != WHICH_WEAPON)
|
||||
s.writeString(_weapon <= 0 ? "Hands" : OBJECT_INFO[_weapon]._name);
|
||||
|
||||
if (!_message.empty())
|
||||
s.writeString(Common::Point(1, 2), _message);
|
||||
}
|
||||
|
||||
bool Attack::msgKeypress(const KeypressMessage &msg) {
|
||||
if (_mode == WHICH_WEAPON) {
|
||||
selectObject(-1);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Attack::msgAction(const ActionMessage &msg) {
|
||||
int objNum;
|
||||
|
||||
switch (_mode) {
|
||||
case WHICH_WEAPON:
|
||||
// Check for object selection, anything but food
|
||||
objNum = -1;
|
||||
for (uint i = OB_RAPIER; i < MAX_OBJ; ++i) {
|
||||
if (msg._action == OBJECT_INFO[i]._action) {
|
||||
objNum = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
selectObject(objNum);
|
||||
break;
|
||||
|
||||
case AMULET:
|
||||
if (msg._action >= KEYBIND_AMULET1 && msg._action <= KEYBIND_AMULET4) {
|
||||
selectMagic(msg._action - KEYBIND_AMULET1);
|
||||
}
|
||||
break;
|
||||
|
||||
case THROW_SWING:
|
||||
if (msg._action == KEYBIND_THROW) {
|
||||
_message += "Throw\n";
|
||||
attackMissile();
|
||||
} else if (msg._action == KEYBIND_SWING) {
|
||||
_message += "Swing\n";
|
||||
attackWeapon();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Attack::selectObject(int objNum) {
|
||||
auto &player = g_engine->_player;
|
||||
|
||||
_weapon = objNum;
|
||||
_damage = (objNum <= 0) ? 0 : OBJECT_INFO[objNum]._maxDamage;
|
||||
|
||||
// Must own an object
|
||||
if (player._object[_weapon] == 0) {
|
||||
showMessage("Not owned.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Mages are limited
|
||||
if (player._class == 'M' && (objNum == OB_BOW || objNum == OB_RAPIER)) {
|
||||
showMessage("Mages can't use that.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Use an amulet
|
||||
if (objNum == OB_AMULET) {
|
||||
if (player._class == 'M') {
|
||||
// Mages can properly select the magic to use
|
||||
_mode = AMULET;
|
||||
|
||||
// Amulet selection requires all four lines
|
||||
_bounds = Gfx::TextRect(0, 22, 26, 24);
|
||||
|
||||
redraw();
|
||||
} else {
|
||||
// Fighters get a random effect
|
||||
selectMagic(g_engine->getRandomNumber(3));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (objNum == OB_BOW) {
|
||||
attackMissile();
|
||||
} else if (objNum == OB_AXE) {
|
||||
_mode = THROW_SWING;
|
||||
_message += "Throw or Swing ? ";
|
||||
redraw();
|
||||
} else {
|
||||
attackWeapon();
|
||||
}
|
||||
}
|
||||
|
||||
void Attack::selectMagic(int magicNum) {
|
||||
auto &dungeon = g_engine->_dungeon;
|
||||
auto &player = g_engine->_player;
|
||||
int i;
|
||||
|
||||
// Last charge?
|
||||
Common::String msg;
|
||||
if (urand() % 5 == 0) {
|
||||
msg = "Last charge on this Amulet.\n";
|
||||
player._object[OB_AMULET]--;
|
||||
}
|
||||
|
||||
switch (magicNum) {
|
||||
case 0:
|
||||
// Ladder up
|
||||
dungeon._map[player._dungeonPos.x][player._dungeonPos.y] = DT_LADDERUP;
|
||||
break;
|
||||
case 1:
|
||||
// Ladder down
|
||||
dungeon._map[player._dungeonPos.x][player._dungeonPos.y] = DT_LADDERDN;
|
||||
break;
|
||||
case 2:
|
||||
// Amulet Attack
|
||||
attackMissile();
|
||||
break;
|
||||
case 3:
|
||||
// Bad Magic
|
||||
switch (urand() % 3) {
|
||||
case 0:
|
||||
msg += "You have been turned into a Toad.\n";
|
||||
for (i = AT_STRENGTH; i <= AT_WISDOM; i++)
|
||||
player._attr[i] = 3;
|
||||
break;
|
||||
case 1:
|
||||
msg += "You have been turned into a Lizard Man.\n";
|
||||
for (i = AT_HP; i <= AT_WISDOM; i++)
|
||||
player._attr[i] = floor(player._attr[i] * 5 / 2);
|
||||
break;
|
||||
case 2:
|
||||
msg += "Backfire !!\n";
|
||||
player._attr[AT_HP] = floor(player._attr[AT_HP]) / 2;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (msg.empty()) {
|
||||
timeout();
|
||||
} else {
|
||||
redraw();
|
||||
delaySeconds(1);
|
||||
}
|
||||
}
|
||||
|
||||
void Attack::attackMissile() {
|
||||
const auto &dungeon = g_engine->_dungeon;
|
||||
auto &player = g_engine->_player;
|
||||
Common::Point c1, c = player._dungeonPos;
|
||||
int Dist = -1;
|
||||
|
||||
// A maximum distance of 5
|
||||
for (int y = 0; y < 5; y++) {
|
||||
c += player._dungeonDir;
|
||||
int n = dungeon.findMonster(c); // Monster there ?
|
||||
if (n >= 0) {
|
||||
c1 = c;
|
||||
Dist = n;
|
||||
}
|
||||
|
||||
// If wall, or door, stop
|
||||
if (!ISDRAWOPEN(dungeon._map[c.x][c.y]))
|
||||
break;
|
||||
}
|
||||
|
||||
if (Dist < 0) {
|
||||
// Hit nothing
|
||||
_message += "You missed !!\n";
|
||||
_mode = DONE;
|
||||
delaySeconds(1);
|
||||
} else {
|
||||
attackHitMonster(c1);
|
||||
}
|
||||
}
|
||||
|
||||
void Attack::attackWeapon() {
|
||||
const auto &player = g_engine->_player;
|
||||
Common::Point c = player._dungeonPos + player._dungeonDir;
|
||||
attackHitMonster(c);
|
||||
}
|
||||
|
||||
void Attack::attackHitMonster(const Common::Point &c) {
|
||||
auto &player = g_engine->_player;
|
||||
auto &dungeon = g_engine->_dungeon;
|
||||
int n = 0, monNum, damage;
|
||||
MonsterEntry *m = nullptr;
|
||||
|
||||
// Is there a monster there ?
|
||||
monNum = dungeon.findMonster(c);
|
||||
if (monNum >= 0) {
|
||||
// Set up a pointer
|
||||
m = &dungeon._monsters[monNum];
|
||||
n = m->_type;
|
||||
}
|
||||
|
||||
// Get weaponry info
|
||||
damage = 0;
|
||||
if (_weapon >= 0 && _weapon != OB_AMULET)
|
||||
damage = OBJECT_INFO[_weapon]._maxDamage;
|
||||
if (_weapon == OB_AMULET)
|
||||
// Amulet Special Case
|
||||
damage = 10 + player._level;
|
||||
|
||||
// If no, or not dexterous
|
||||
if (monNum < 0 || player._attr[AT_DEXTERITY] - ((int)urand() % 25) < n + player._level) {
|
||||
// Then a miss.
|
||||
_message += "\nMissed!";
|
||||
_mode = DONE;
|
||||
redraw();
|
||||
delaySeconds(1);
|
||||
return;
|
||||
}
|
||||
|
||||
// Scored a hit
|
||||
_message += "Hit !!!\n";
|
||||
|
||||
// Calculate HPs lost
|
||||
n = 0;
|
||||
if (damage > 0)
|
||||
n = (urand() % damage);
|
||||
n = n + player._attr[AT_STRENGTH] / 5;
|
||||
m->_strength = m->_strength - n; // Lose them
|
||||
|
||||
if (m->_strength < 0)
|
||||
m->_strength = 0;
|
||||
_message += Common::String::format("%s's Hit\nPoints now %d.\n",
|
||||
MONSTER_INFO[m->_type]._name, m->_strength);
|
||||
|
||||
// Killed it ?
|
||||
if (m->_strength == 0) {
|
||||
m->_alive = false; // It has ceased to be
|
||||
int gold = (m->_type + player._level); // Amount of gold
|
||||
_message += Common::String::format("You get %d pieces of eight.\n", gold);
|
||||
player._attr[AT_GOLD] += gold;
|
||||
|
||||
player._hpGain += (m->_type * player._level) / 2; // Calculate Gain
|
||||
|
||||
if (m->_type == player._task) // Check done LB's task
|
||||
player._taskCompleted = true;
|
||||
}
|
||||
|
||||
_mode = DONE;
|
||||
redraw();
|
||||
delaySeconds(1);
|
||||
}
|
||||
|
||||
void Attack::showMessage(const Common::String &msg) {
|
||||
_message = msg;
|
||||
_mode = DONE;
|
||||
redraw();
|
||||
delaySeconds(1);
|
||||
}
|
||||
|
||||
void Attack::timeout() {
|
||||
close();
|
||||
g_events->send("Dungeon", GameMessage("ENDOFTURN"));
|
||||
}
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
66
engines/ultima/ultima0/views/attack.h
Normal file
66
engines/ultima/ultima0/views/attack.h
Normal 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 ULTIMA0_VIEWS_ATTACK_H
|
||||
#define ULTIMA0_VIEWS_ATTACK_H
|
||||
|
||||
#include "ultima/ultima0/views/view.h"
|
||||
#include "ultima/ultima0/data/data.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
class Attack : public View {
|
||||
private:
|
||||
enum Mode {
|
||||
WHICH_WEAPON, AMULET, THROW_SWING, DONE
|
||||
};
|
||||
Mode _mode = WHICH_WEAPON;
|
||||
int _weapon = -1;
|
||||
int _damage = 0;
|
||||
Common::String _message;
|
||||
|
||||
void selectObject(int objNum);
|
||||
void selectMagic(int magicNum);
|
||||
void attackMissile();
|
||||
void attackWeapon();
|
||||
void attackHitMonster(const Common::Point &c);
|
||||
void showMessage(const Common::String &msg);
|
||||
|
||||
public:
|
||||
Attack();
|
||||
~Attack() override {}
|
||||
|
||||
bool msgFocus(const FocusMessage &msg) override;
|
||||
bool msgUnfocus(const UnfocusMessage &msg) override;
|
||||
void draw() override;
|
||||
|
||||
bool msgKeypress(const KeypressMessage &msg) override;
|
||||
bool msgAction(const ActionMessage &msg) override;
|
||||
void timeout() override;
|
||||
};
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
|
||||
#endif
|
||||
218
engines/ultima/ultima0/views/castle.cpp
Normal file
218
engines/ultima/ultima0/views/castle.cpp
Normal file
@@ -0,0 +1,218 @@
|
||||
/* 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/ultima0/views/castle.h"
|
||||
#include "ultima/ultima0/ultima0.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
static const char *GO_FORTH = " Go now upon this quest, and may\n"
|
||||
"Lady Luck be fair unto you.....\n"
|
||||
".....Also I, British, have increased\n"
|
||||
"each of thy attributes by one.!";
|
||||
|
||||
bool Castle::msgFocus(const FocusMessage &msg) {
|
||||
const auto &player = g_engine->_player;
|
||||
|
||||
if (Common::String(player._name).empty())
|
||||
_mode = NAMING;
|
||||
else if (player._taskCompleted) {
|
||||
_mode = TASK_COMPLETE;
|
||||
} else {
|
||||
_mode = TASK_INCOMPLETE;
|
||||
}
|
||||
|
||||
g_engine->playMidi("lordbrit.mid");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Castle::msgUnfocus(const UnfocusMessage &msg) {
|
||||
g_engine->stopMidi();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Castle::draw() {
|
||||
auto s = getSurface();
|
||||
s.clear();
|
||||
|
||||
if (_mode <= FIRST_TASK) {
|
||||
firstTime();
|
||||
} else if (_mode == TASK_COMPLETE) {
|
||||
taskCompleted();
|
||||
} else if (_mode == TASK_INCOMPLETE) {
|
||||
taskIncomplete();
|
||||
}
|
||||
}
|
||||
|
||||
void Castle::firstTime() {
|
||||
auto s = getSurface();
|
||||
const auto &player = g_engine->_player;
|
||||
|
||||
if (_mode >= NAMING && _mode <= FIRST_TASK) {
|
||||
s.writeString(Common::Point(5, 2), "Welcome Peasant into the halls of\n"
|
||||
"the mighty Lord British. Herein thou\n"
|
||||
"may choose to dare battle with the\n"
|
||||
"evil creatures of the depths, for\n"
|
||||
"great reward!\n\n"
|
||||
"What is thy name peasant? ");
|
||||
s.setColor(C_GREY);
|
||||
s.writeString(_playerName);
|
||||
s.setColor(C_TEXT_DEFAULT);
|
||||
}
|
||||
|
||||
if (_mode >= GRAND_ADVENTURE && _mode <= FIRST_TASK)
|
||||
s.writeString(Common::Point(0, 10), "Doest thou wish for great adventure ?\n\n");
|
||||
|
||||
if (_mode == BEGONE) {
|
||||
s.writeString("Then leave and begone!");
|
||||
} else if (_mode == FIRST_TASK) {
|
||||
s.writeString("Good! Thou shalt try to become a\nKnight!!!\n\n"
|
||||
"Thy first task is to go into the\n"
|
||||
"dungeons and to return only after\n"
|
||||
"killing ");
|
||||
s.setColor(C_VIOLET);
|
||||
s.writeString(getTaskName(player._task));
|
||||
|
||||
pressAnyKey();
|
||||
}
|
||||
}
|
||||
|
||||
void Castle::taskCompleted() {
|
||||
auto &player = g_engine->_player;
|
||||
auto s = getSurface();
|
||||
|
||||
s.writeString(Common::Point(0, 3), "Aaaahhhh.... ");
|
||||
s.writeString(player._name);
|
||||
s.writeString("\n\nThou has accomplished\nthy quest.\n\n");
|
||||
|
||||
if (player._task == MAX_MONSTERS) {
|
||||
s.writeString("Thou hast proved thyself worthy of\n"
|
||||
"Knighthood, continue if thou doth wish\n"
|
||||
"but thou hast accomplished the\n"
|
||||
"main objective of the game.\n\n"
|
||||
"Now, maybe thou art foolhardy enough to\n"
|
||||
"try difficulty level ");
|
||||
s.writeString(Common::String::format("%d.", player._skill + 1));
|
||||
} else {
|
||||
// LB gives you extra attributes
|
||||
for (int i = 0; i < MAX_ATTR; i++)
|
||||
player._attr[i]++;
|
||||
|
||||
// Choose the next task
|
||||
nextTask();
|
||||
|
||||
s.writeString("Unfortunately, this is not enough to\n"
|
||||
"become a knight.\n\n");
|
||||
s.writeString("Thou must now kill ");
|
||||
s.setColor(C_VIOLET);
|
||||
s.writeString(getTaskName(player._task));
|
||||
|
||||
s.setColor(C_TEXT_DEFAULT);
|
||||
s.writeString("\n\n");
|
||||
s.writeString(GO_FORTH);
|
||||
|
||||
pressAnyKey();
|
||||
}
|
||||
}
|
||||
|
||||
void Castle::taskIncomplete() {
|
||||
const auto &player = g_engine->_player;
|
||||
auto s = getSurface();
|
||||
|
||||
s.writeString(Common::Point(0, 3),
|
||||
"Why hast thou returned ?\n"
|
||||
"Thou must kill ");
|
||||
s.setColor(C_VIOLET);
|
||||
s.writeString(getTaskName(player._task));
|
||||
|
||||
s.setColor(C_TEXT_DEFAULT);
|
||||
s.writeString("\n\nGo now and complete thy quest");
|
||||
}
|
||||
|
||||
void Castle::pressAnyKey() {
|
||||
auto s = getSurface();
|
||||
s.writeString(Common::Point(20, 23), "Press any Key to Continue",
|
||||
Graphics::kTextAlignCenter);
|
||||
}
|
||||
|
||||
bool Castle::msgKeypress(const KeypressMessage &msg) {
|
||||
auto &player = g_engine->_player;
|
||||
|
||||
switch (_mode) {
|
||||
case NAMING:
|
||||
if (msg.keycode == Common::KEYCODE_BACKSPACE && !_playerName.empty()) {
|
||||
_playerName.deleteLastChar();
|
||||
} else if (msg.keycode == Common::KEYCODE_RETURN && !_playerName.empty()) {
|
||||
Common::strcpy_s(player._name, _playerName.c_str());
|
||||
_mode = GRAND_ADVENTURE;
|
||||
} else if (Common::isAlpha(msg.ascii) && _playerName.size() < MAX_NAME) {
|
||||
_playerName += msg.ascii;
|
||||
}
|
||||
redraw();
|
||||
break;
|
||||
|
||||
case GRAND_ADVENTURE:
|
||||
if (msg.keycode == Common::KEYCODE_y) {
|
||||
nextTask();
|
||||
_mode = FIRST_TASK;
|
||||
} else if (msg.keycode == Common::KEYCODE_n) {
|
||||
_mode = BEGONE;
|
||||
}
|
||||
redraw();
|
||||
break;
|
||||
|
||||
default:
|
||||
// All other modes exit the castle
|
||||
replaceView("WorldMap");
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Castle::msgAction(const ActionMessage &msg) {
|
||||
if (_mode >= FIRST_TASK) {
|
||||
replaceView("WorldMap");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Castle::nextTask() {
|
||||
auto &player = g_engine->_player;
|
||||
|
||||
player._task = CLIP(player._attr[AT_WISDOM] / 3, 1, 10);
|
||||
player._taskCompleted = false;
|
||||
}
|
||||
|
||||
Common::String Castle::getTaskName(int taskNum) const {
|
||||
Common::String mons = MONSTER_INFO[taskNum]._name;
|
||||
|
||||
return Common::String::format("%s %s",
|
||||
strchr("aeiou", tolower(mons.firstChar())) != nullptr ? "an" : "a",
|
||||
mons.c_str());
|
||||
}
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
61
engines/ultima/ultima0/views/castle.h
Normal file
61
engines/ultima/ultima0/views/castle.h
Normal 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ULTIMA0_VIEWS_CASTLE_H
|
||||
#define ULTIMA0_VIEWS_CASTLE_H
|
||||
|
||||
#include "ultima/ultima0/views/view.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
class Castle : public View {
|
||||
private:
|
||||
enum Mode {
|
||||
NAMING, GRAND_ADVENTURE, BEGONE, FIRST_TASK, TASK_COMPLETE, TASK_INCOMPLETE
|
||||
};
|
||||
Mode _mode = NAMING;
|
||||
Common::String _playerName;
|
||||
|
||||
void firstTime();
|
||||
void taskCompleted();
|
||||
void taskIncomplete();
|
||||
void nextTask();
|
||||
void pressAnyKey();
|
||||
Common::String getTaskName(int taskNum) const;
|
||||
|
||||
public:
|
||||
Castle() : View("Castle") {}
|
||||
~Castle() override {}
|
||||
|
||||
bool msgFocus(const FocusMessage &msg) override;
|
||||
bool msgUnfocus(const UnfocusMessage &msg) override;
|
||||
void draw() override;
|
||||
bool msgKeypress(const KeypressMessage &msg) override;
|
||||
bool msgAction(const ActionMessage &msg) override;
|
||||
};
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
|
||||
#endif
|
||||
136
engines/ultima/ultima0/views/create_character.cpp
Normal file
136
engines/ultima/ultima0/views/create_character.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
/* 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/ultima0/views/create_character.h"
|
||||
#include "ultima/ultima0/ultima0.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
bool CreateCharacter::msgFocus(const FocusMessage &msg) {
|
||||
g_engine->_player.init();
|
||||
_mode = LUCKY_NUMBER;
|
||||
_input = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
void CreateCharacter::draw() {
|
||||
auto s = getSurface();
|
||||
const auto &player = g_engine->_player;
|
||||
s.clear();
|
||||
|
||||
// Lucky number
|
||||
s.writeString(Common::Point(1, 4), "Type thy Lucky Number.....");
|
||||
if (_mode == LUCKY_NUMBER)
|
||||
s.writeString(_input);
|
||||
else
|
||||
s.writeString(Common::String::format("%d", player._luckyNumber));
|
||||
|
||||
// Level of play
|
||||
if (_mode >= LEVEL) {
|
||||
s.writeString(Common::Point(1, 6), "Level of play (1-10)......");
|
||||
if (_mode == LEVEL)
|
||||
s.writeString(_input);
|
||||
else
|
||||
s.writeString(Common::String::format("%d", player._skill));
|
||||
}
|
||||
|
||||
// Stats
|
||||
if (_mode >= STATS) {
|
||||
for (int i = 0; i < MAX_ATTR; ++i) {
|
||||
Common::String line = ATTRIB_NAMES[i];
|
||||
while (line.size() < 15)
|
||||
line += ".";
|
||||
line += Common::String::format("%d", player._attr[i]);
|
||||
s.writeString(Common::Point(1, 9 + i), line);
|
||||
}
|
||||
|
||||
s.writeString(Common::Point(0, 16), "Shallt thou play with these qualities?");
|
||||
}
|
||||
|
||||
// Class selection
|
||||
if (_mode == CLASS) {
|
||||
s.writeString(Common::Point(0, 18), "And shalt thou be a Fighter or a Mage?");
|
||||
}
|
||||
}
|
||||
|
||||
bool CreateCharacter::msgKeypress(const KeypressMessage &msg) {
|
||||
auto &player = g_engine->_player;
|
||||
|
||||
if (_mode == LUCKY_NUMBER || _mode == LEVEL) {
|
||||
if (Common::isDigit(msg.ascii) && _input.size() < 6) {
|
||||
_input += msg.ascii;
|
||||
redraw();
|
||||
} else if (msg.keycode == Common::KEYCODE_BACKSPACE && _input.size() > 0) {
|
||||
_input.deleteLastChar();
|
||||
redraw();
|
||||
} else if (msg.keycode == Common::KEYCODE_RETURN && !_input.empty()) {
|
||||
if (_mode == LUCKY_NUMBER) {
|
||||
player._luckyNumber = atoi(_input.c_str());
|
||||
_input.clear();
|
||||
_mode = LEVEL;
|
||||
redraw();
|
||||
} else {
|
||||
player._skill = atoi(_input.c_str());
|
||||
if (player._skill >= 1 && player._skill <= 10) {
|
||||
_input.clear();
|
||||
_mode = STATS;
|
||||
player.rollAttributes();
|
||||
redraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (msg.keycode == Common::KEYCODE_y) {
|
||||
_mode = CLASS;
|
||||
redraw();
|
||||
} else if (msg.keycode == Common::KEYCODE_n) {
|
||||
player.rollAttributes();
|
||||
redraw();
|
||||
} else if (_mode == CLASS && (msg.keycode == Common::KEYCODE_f ||
|
||||
msg.keycode == Common::KEYCODE_m)) {
|
||||
player._class = toupper(msg.ascii);
|
||||
characterDone();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CreateCharacter::msgAction(const ActionMessage &msg) {
|
||||
if (msg._action == KEYBIND_ESCAPE) {
|
||||
replaceView("Title");
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CreateCharacter::characterDone() {
|
||||
// Generate the world map
|
||||
g_engine->_worldMap.init(g_engine->_player);
|
||||
|
||||
// Enter the town
|
||||
replaceView("Town");
|
||||
}
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
53
engines/ultima/ultima0/views/create_character.h
Normal file
53
engines/ultima/ultima0/views/create_character.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/* 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 ULTIMA0_VIEWS_CREATE_CHARACTER_H
|
||||
#define ULTIMA0_VIEWS_CREATE_CHARACTER_H
|
||||
|
||||
#include "ultima/ultima0/views/view.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
class CreateCharacter : public View {
|
||||
private:
|
||||
enum Mode { LUCKY_NUMBER, LEVEL, STATS, CLASS };
|
||||
Mode _mode = LUCKY_NUMBER;
|
||||
Common::String _input;
|
||||
|
||||
void characterDone();
|
||||
|
||||
public:
|
||||
CreateCharacter() : View("CreateCharacter") {}
|
||||
~CreateCharacter() override {}
|
||||
|
||||
bool msgFocus(const FocusMessage &msg) override;
|
||||
void draw() override;
|
||||
bool msgKeypress(const KeypressMessage &msg) override;
|
||||
bool msgAction(const ActionMessage &msg) override;
|
||||
};
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
|
||||
#endif
|
||||
51
engines/ultima/ultima0/views/dead.cpp
Normal file
51
engines/ultima/ultima0/views/dead.cpp
Normal 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ultima/ultima0/views/dead.h"
|
||||
#include "ultima/ultima0/gfx/font.h"
|
||||
#include "ultima/ultima0/ultima0.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
Dead::Dead() : View("Dead") {
|
||||
setBounds(Common::Rect(0, DEFAULT_SCY - 4 * Gfx::GLYPH_HEIGHT, DEFAULT_SCX, DEFAULT_SCY));
|
||||
}
|
||||
|
||||
void Dead::draw() {
|
||||
const auto &player = g_engine->_player;
|
||||
auto s = getSurface();
|
||||
s.clear();
|
||||
|
||||
const char *name = player._name;
|
||||
if (*name == '\0')
|
||||
name = "the peasant";
|
||||
|
||||
s.writeString(Common::Point(20, 0), "We mourn the passing of", Graphics::kTextAlignCenter);
|
||||
s.writeString(Common::Point(20, 1), Common::String::format("%s and his Computer", name), Graphics::kTextAlignCenter);
|
||||
s.writeString(Common::Point(20, 2), "To invoke a miracle of resurrection", Graphics::kTextAlignCenter);
|
||||
s.writeString(Common::Point(20, 3), "Press a Key", Graphics::kTextAlignCenter);
|
||||
}
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
60
engines/ultima/ultima0/views/dead.h
Normal file
60
engines/ultima/ultima0/views/dead.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/* 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 ULTIMA0_VIEWS_DEAD_H
|
||||
#define ULTIMA0_VIEWS_DEAD_H
|
||||
|
||||
#include "ultima/ultima0/views/view.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
class Dead : public View {
|
||||
private:
|
||||
void showTitle() {
|
||||
replaceView("Title");
|
||||
}
|
||||
public:
|
||||
Dead();
|
||||
~Dead() override {}
|
||||
|
||||
void draw() override;
|
||||
|
||||
bool msgKeypress(const KeypressMessage &msg) override {
|
||||
showTitle();
|
||||
return true;
|
||||
}
|
||||
bool msgMouseDown(const MouseDownMessage &msg) override {
|
||||
showTitle();
|
||||
return true;
|
||||
}
|
||||
bool msgAction(const ActionMessage &msg) override {
|
||||
showTitle();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
|
||||
#endif
|
||||
300
engines/ultima/ultima0/views/dungeon.cpp
Normal file
300
engines/ultima/ultima0/views/dungeon.cpp
Normal file
@@ -0,0 +1,300 @@
|
||||
/* 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/ultima0/views/dungeon.h"
|
||||
#include "ultima/ultima0/ultima0.h"
|
||||
#include "ultima/ultima0/metaengine.h"
|
||||
#include "ultima/ultima0/gfx/font.h"
|
||||
#include "ultima/ultima0/gfx/dungeon.h"
|
||||
#include "ultima/ultima0/data/monster_logic.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
Dungeon::Dungeon() : View("Dungeon") {
|
||||
}
|
||||
|
||||
bool Dungeon::msgFocus(const FocusMessage &msg) {
|
||||
showMessage("");
|
||||
showLines("");
|
||||
MetaEngine::setKeybindingMode(KBMODE_DUNGEONS);
|
||||
|
||||
if (!g_engine->isMidiPlaying())
|
||||
g_engine->playMidi("dungeon.mid");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Dungeon::msgUnfocus(const UnfocusMessage &msg) {
|
||||
MetaEngine::setKeybindingMode(KBMODE_MINIMAL);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Dungeon::draw() {
|
||||
auto s = getSurface();
|
||||
s.clear();
|
||||
|
||||
// Draw the dungeon view
|
||||
Graphics::ManagedSurface dungArea(s, Common::Rect(0, 0, s.w, s.h - Gfx::GLYPH_HEIGHT * 4));
|
||||
Gfx::Dungeon::draw(&dungArea);
|
||||
|
||||
// Allow the status area to draw
|
||||
View::draw();
|
||||
|
||||
if (g_engine->_showMinimap) {
|
||||
s.frameRect(Common::Rect(s.w - DUNGEON_MINIMAP_SIZE - 4, 0, s.w, DUNGEON_MINIMAP_SIZE + 4), C_GREY);
|
||||
s.frameRect(Common::Rect(s.w - DUNGEON_MINIMAP_SIZE - 3, 1, s.w - 1, DUNGEON_MINIMAP_SIZE + 3), C_GREY);
|
||||
Graphics::ManagedSurface minimapArea(s, Common::Rect(s.w - DUNGEON_MINIMAP_SIZE - 2, 2, s.w - 2, DUNGEON_MINIMAP_SIZE + 2));
|
||||
drawMinimap(minimapArea);
|
||||
}
|
||||
}
|
||||
|
||||
void Dungeon::drawMinimap(Graphics::ManagedSurface &mapArea) {
|
||||
const auto &player = g_engine->_player;
|
||||
const auto &dungeon = g_engine->_dungeon;
|
||||
int tile;
|
||||
|
||||
for (int y = 0; y < DUNGEON_MAP_SIZE; ++y) {
|
||||
for (int x = 0; x < DUNGEON_MAP_SIZE; ++x) {
|
||||
const Common::Rect r(x * MINIMAP_TILE_SIZE, y * MINIMAP_TILE_SIZE,
|
||||
(x + 1) * MINIMAP_TILE_SIZE, (y + 1) * MINIMAP_TILE_SIZE);
|
||||
if (x == player._dungeonPos.x && y == player._dungeonPos.y) {
|
||||
mapArea.fillRect(r, C_CYAN);
|
||||
} else if (dungeon.findMonster(Common::Point(x, y)) >= 0) {
|
||||
mapArea.fillRect(r, C_RED);
|
||||
} else {
|
||||
tile = dungeon._map[x][y];
|
||||
|
||||
if (tile == DT_SPACE || tile == DT_DOOR || tile == DT_HIDDENDOOR)
|
||||
mapArea.fillRect(r, C_BLACK);
|
||||
else if (tile == DT_SOLID)
|
||||
mapArea.fillRect(r, C_WHITE);
|
||||
else if (tile == DT_LADDERUP || tile == DT_LADDERDN)
|
||||
mapArea.fillRect(r, C_GREEN);
|
||||
else
|
||||
mapArea.fillRect(r, C_ROSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Dungeon::msgAction(const ActionMessage &msg) {
|
||||
auto &player = g_engine->_player;
|
||||
|
||||
if (isDelayActive())
|
||||
return false;
|
||||
|
||||
switch (msg._action) {
|
||||
case KEYBIND_UP:
|
||||
showMessage("Move Forward");
|
||||
moveForward();
|
||||
break;
|
||||
case KEYBIND_DOWN:
|
||||
showMessage("Turn Around");
|
||||
player.dungeonTurnLeft();
|
||||
player.dungeonTurnLeft();
|
||||
break;
|
||||
case KEYBIND_LEFT:
|
||||
showMessage("Turn Left");
|
||||
player.dungeonTurnLeft();
|
||||
break;
|
||||
case KEYBIND_RIGHT:
|
||||
showMessage("Turn Right");
|
||||
player.dungeonTurnRight();
|
||||
break;
|
||||
case KEYBIND_INFO:
|
||||
// Show character info screen
|
||||
showMessage("");
|
||||
replaceView("Info");
|
||||
break;
|
||||
case KEYBIND_ENTER:
|
||||
interact();
|
||||
break;
|
||||
case KEYBIND_PASS:
|
||||
showMessage("");
|
||||
break;
|
||||
case KEYBIND_ATTACK:
|
||||
showMessage(" \x9""Attack!");
|
||||
_status.draw(); // Render the message before we switch views
|
||||
addView("Attack");
|
||||
break;
|
||||
case KEYBIND_QUIT:
|
||||
// "Quit" in the original which merely saves the game. For ScummVM,
|
||||
// we open the GMM, allowing the user to either save or quit
|
||||
g_engine->openMainMenuDialog();
|
||||
return true;
|
||||
case KEYBIND_MINIMAP:
|
||||
g_engine->_showMinimap = !g_engine->_showMinimap;
|
||||
redraw();
|
||||
break;
|
||||
default:
|
||||
showMessage("Huh???");
|
||||
break;
|
||||
}
|
||||
|
||||
endOfTurn();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Dungeon::msgKeypress(const KeypressMessage &msg) {
|
||||
if (isDelayActive())
|
||||
return false;
|
||||
|
||||
showMessage("Huh???");
|
||||
endOfTurn();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Dungeon::endOfTurn() {
|
||||
auto &player = g_engine->_player;
|
||||
auto &dungeon = g_engine->_dungeon;
|
||||
|
||||
if (player._attr[AT_HP] <= 0) {
|
||||
g_engine->stopMidi();
|
||||
replaceView("Dead");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for monster attacks
|
||||
MonsterLogic::checkForAttacks(player, dungeon);
|
||||
|
||||
player._object[OB_FOOD] = MAX(player._object[OB_FOOD] - 0.1, 0.0);
|
||||
if (player._object[OB_FOOD] == 0) {
|
||||
showMessage("You have starved...");
|
||||
g_engine->stopMidi();
|
||||
delaySeconds(1);
|
||||
}
|
||||
|
||||
redraw();
|
||||
}
|
||||
|
||||
void Dungeon::moveForward() {
|
||||
auto &dungeon = g_engine->_dungeon;
|
||||
auto &player = g_engine->_player;
|
||||
Common::Point newPos = player._dungeonPos + player._dungeonDir;
|
||||
|
||||
if (!ISWALKTHRU(dungeon._map[newPos.x][newPos.y]) || dungeon.findMonster(newPos) >= 0)
|
||||
return;
|
||||
|
||||
// Set new position
|
||||
player._dungeonPos = newPos;
|
||||
|
||||
// What's here ?
|
||||
int n = dungeon._map[player._dungeonPos.x][player._dungeonPos.y];
|
||||
|
||||
if (n == DT_PIT) {
|
||||
// Fell in a pit
|
||||
player._level++; // Down a level
|
||||
showMessage("Aaarrrgghhh! A Trap !");
|
||||
showLines(Common::String::format("Falling to Level %d.", player._level));
|
||||
|
||||
player._attr[AT_HP] -= (3 + urand() % (3 * player._level));
|
||||
dungeon.create(player); // Create the new level
|
||||
} else if (n == DT_GOLD) {
|
||||
// Gold here
|
||||
// Remove the gold
|
||||
dungeon._map[player._dungeonPos.x][player._dungeonPos.y] = DT_SPACE;
|
||||
int gold = (urand() % (5 * player._level)) + player._level; // Calculate amount
|
||||
|
||||
showMessage("Gold !!!!!");
|
||||
Common::String msg = Common::String::format("%d pieces of eight ", gold);
|
||||
player._attr[AT_GOLD] = MIN<int>(player._attr[AT_GOLD] + gold, 9999); // Add to total
|
||||
|
||||
if (gold > 0) {
|
||||
int objNum = urand() % MAX_OBJ; // Decide which object
|
||||
const char *name = OBJECT_INFO[objNum]._name;
|
||||
const char *prefix = "a"; // Decide a,an or some
|
||||
if (strchr("aeiou", tolower(*name)))
|
||||
prefix = "an";
|
||||
if (objNum == 0)
|
||||
prefix = "some";
|
||||
|
||||
msg += Common::String::format("\nand %s %s.", prefix, name);
|
||||
player._object[objNum] = MIN<int>(player._object[objNum] + 1, 9999); // Bump the total
|
||||
}
|
||||
|
||||
showLines(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void Dungeon::interact() {
|
||||
auto &dungeon = g_engine->_dungeon;
|
||||
auto &player = g_engine->_player;
|
||||
|
||||
// Identify what's there
|
||||
int t = dungeon._map[player._dungeonPos.x][player._dungeonPos.y];
|
||||
bool done = false;
|
||||
|
||||
if (t == DT_LADDERUP) {
|
||||
// Climbing up a ladder
|
||||
player._level--;
|
||||
done = true;
|
||||
|
||||
if (player._level == 0) {
|
||||
showMessage("Leave Dungeon.");
|
||||
if (player._hpGain > 0)
|
||||
showLines(Common::String::format("Thou has gained %d HP", player._hpGain));
|
||||
player._attr[AT_HP] += player._hpGain;
|
||||
player._hpGain = 0;
|
||||
delaySeconds(1); // Brief delay to show text before leaving dungeon
|
||||
|
||||
} else {
|
||||
showMessage("Use Ladder");
|
||||
showLines(Common::String::format("Go up to Level %d.", player._level));
|
||||
}
|
||||
} else if (t == DT_LADDERDN) {
|
||||
// Climbing down a ladder
|
||||
player._level++;
|
||||
done = true;
|
||||
|
||||
showMessage("Use Ladder");
|
||||
showLines(Common::String::format("Go down to Level %d.\n", player._level));
|
||||
}
|
||||
|
||||
if (done) {
|
||||
if (player._level > 0)
|
||||
// New Dungeon Map Required
|
||||
dungeon.create(player);
|
||||
} else {
|
||||
showMessage("Huh???");
|
||||
}
|
||||
}
|
||||
|
||||
bool Dungeon::msgGame(const GameMessage &msg) {
|
||||
if (msg._name == "ENDOFTURN") {
|
||||
endOfTurn();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Dungeon::timeout() {
|
||||
const auto &player = g_engine->_player;
|
||||
g_engine->stopMidi();
|
||||
|
||||
replaceView((player._level == 0) ? "WorldMap" : "Dead");
|
||||
}
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
64
engines/ultima/ultima0/views/dungeon.h
Normal file
64
engines/ultima/ultima0/views/dungeon.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/* 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 ULTIMA0_VIEWS_DUNGEON_H
|
||||
#define ULTIMA0_VIEWS_DUNGEON_H
|
||||
|
||||
#include "ultima/ultima0/views/view.h"
|
||||
#include "ultima/ultima0/views/status.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
class Dungeon : public View {
|
||||
private:
|
||||
DungeonStatus _status = DungeonStatus(this);
|
||||
|
||||
void drawMinimap(Graphics::ManagedSurface &mapArea);
|
||||
void moveForward();
|
||||
void interact();
|
||||
void endOfTurn();
|
||||
void showMessage(const Common::String &msg) {
|
||||
_status.send(GameMessage("MSG", msg));
|
||||
}
|
||||
void showLines(const Common::String &msg) {
|
||||
_status.send(GameMessage("LINES", msg));
|
||||
}
|
||||
|
||||
public:
|
||||
Dungeon();
|
||||
~Dungeon() override {}
|
||||
|
||||
bool msgFocus(const FocusMessage &msg) override;
|
||||
bool msgUnfocus(const UnfocusMessage &msg) override;
|
||||
void draw() override;
|
||||
bool msgAction(const ActionMessage &msg) override;
|
||||
bool msgKeypress(const KeypressMessage &msg) override;
|
||||
bool msgGame(const GameMessage &msg) override;
|
||||
void timeout() override;
|
||||
};
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
|
||||
#endif
|
||||
146
engines/ultima/ultima0/views/info.cpp
Normal file
146
engines/ultima/ultima0/views/info.cpp
Normal file
@@ -0,0 +1,146 @@
|
||||
/* 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/ultima0/views/info.h"
|
||||
#include "ultima/ultima0/ultima0.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
Info::Info(const char *viewName) : View(viewName) {
|
||||
}
|
||||
|
||||
bool Info::msgFocus(const FocusMessage &msg) {
|
||||
MetaEngine::setKeybindingMode(KBMODE_MENUS);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Info::msgUnfocus(const UnfocusMessage &msg) {
|
||||
MetaEngine::setKeybindingMode(KBMODE_MINIMAL);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Info::draw() {
|
||||
const auto &player = g_engine->_player;
|
||||
auto s = getSurface();
|
||||
int i;
|
||||
|
||||
s.clear();
|
||||
View::draw();
|
||||
|
||||
// Stats
|
||||
for (i = 0; i < MAX_ATTR; ++i) {
|
||||
Common::String line = ATTRIB_NAMES[i];
|
||||
while (line.size() < 15)
|
||||
line += '.';
|
||||
s.writeString(Common::Point(0, 4 + i), line);
|
||||
}
|
||||
|
||||
// Price/Damage/Item
|
||||
for (i = 0; i < MAX_OBJ; ++i) {
|
||||
s.writeString(Common::Point(5, 18 + i),
|
||||
Common::String::format("%d", OBJECT_INFO[i]._cost));
|
||||
|
||||
if (i == 0) {
|
||||
s.writeString(" For 10");
|
||||
s.writeString(Common::Point(15, 18 + i), "N/A");
|
||||
} else if (i == 5) {
|
||||
s.writeString(Common::Point(15, 18 + i), "?????");
|
||||
} else {
|
||||
s.writeString(Common::Point(15, 18 + i),
|
||||
Common::String::format("1-%d", OBJECT_INFO[i]._maxDamage));
|
||||
}
|
||||
|
||||
s.writeString(Common::Point(25, 18 + i), OBJECT_INFO[i]._name);
|
||||
}
|
||||
|
||||
// Headers
|
||||
s.setColor(255, 0, 128);
|
||||
s.writeString(Common::Point(6, 2), "Stat's");
|
||||
s.writeString(Common::Point(21, 2), "Weapons");
|
||||
s.writeString(Common::Point(5, 16), "Price Damage Item");
|
||||
|
||||
// Amounts
|
||||
s.setColor(C_VIOLET);
|
||||
for (i = 0; i < MAX_ATTR; ++i)
|
||||
s.writeString(Common::Point(15, 4 + i),
|
||||
Common::String::format("%d", player._attr[i]));
|
||||
for (i = 0; i < MAX_OBJ; ++i)
|
||||
s.writeString(Common::Point(21, 4 + i),
|
||||
Common::String::format("%4d-", (int)player._object[i]));
|
||||
s.writeString(Common::Point(18, 10), "Q-Quit");
|
||||
}
|
||||
|
||||
void Info::leave() {
|
||||
const auto &player = g_engine->_player;
|
||||
replaceView(player._level == 0 ? "WorldMap" : "DungeonMap");
|
||||
}
|
||||
|
||||
bool Info::msgAction(const ActionMessage &msg) {
|
||||
if (isDelayActive())
|
||||
return false;
|
||||
|
||||
if (msg._action == KEYBIND_ESCAPE || msg._action == KEYBIND_QUIT) {
|
||||
leave();
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_OBJ; ++i) {
|
||||
if (msg._action == OBJECT_INFO[i]._action) {
|
||||
selectObject(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Info::msgGame(const GameMessage &msg) {
|
||||
if (msg._name == "SELECTION") {
|
||||
selectObject(msg._value);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
Info::InfoObject::InfoObject(Info *parent, const Common::Point &pt, int id,
|
||||
const Common::String &text) :
|
||||
UIElement("InfoObject", parent), _id(id), _text(text) {
|
||||
setBounds(Gfx::TextRect(pt.x, pt.y, pt.x + text.size(), pt.y));
|
||||
}
|
||||
|
||||
void Info::InfoObject::draw() {
|
||||
auto s = getSurface();
|
||||
s.writeString(_text);
|
||||
}
|
||||
|
||||
bool Info::InfoObject::msgMouseDown(const MouseDownMessage &msg) {
|
||||
_parent->send(GameMessage("SELECTION", _id));
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
73
engines/ultima/ultima0/views/info.h
Normal file
73
engines/ultima/ultima0/views/info.h
Normal 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 ULTIMA0_VIEWS_INFO_H
|
||||
#define ULTIMA0_VIEWS_INFO_H
|
||||
|
||||
#include "ultima/ultima0/views/view.h"
|
||||
#include "ultima/ultima0/data/data.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
class Info : public View {
|
||||
class InfoObject : public UIElement {
|
||||
public:
|
||||
Common::String _text;
|
||||
int _id;
|
||||
public:
|
||||
InfoObject(Info *parent, const Common::Point &pt, int id, const Common::String &text);
|
||||
void draw() override;
|
||||
bool msgMouseDown(const MouseDownMessage &msg) override;
|
||||
};
|
||||
|
||||
private:
|
||||
InfoObject _options[6] = {
|
||||
InfoObject(this, Common::Point(26, 4), 0, OBJECT_INFO[0]._name),
|
||||
InfoObject(this, Common::Point(26, 5), 1, OBJECT_INFO[1]._name),
|
||||
InfoObject(this, Common::Point(26, 6), 2, OBJECT_INFO[2]._name),
|
||||
InfoObject(this, Common::Point(26, 7), 3, OBJECT_INFO[3]._name),
|
||||
InfoObject(this, Common::Point(26, 8), 4, OBJECT_INFO[4]._name),
|
||||
InfoObject(this, Common::Point(26, 9), 5, OBJECT_INFO[5]._name)
|
||||
};
|
||||
|
||||
protected:
|
||||
virtual void selectObject(int item) {
|
||||
}
|
||||
virtual void leave();
|
||||
|
||||
public:
|
||||
Info(const char *viewName = "Info");
|
||||
~Info() override {}
|
||||
|
||||
bool msgFocus(const FocusMessage &msg) override;
|
||||
bool msgUnfocus(const UnfocusMessage &msg) override;
|
||||
void draw() override;
|
||||
bool msgAction(const ActionMessage &msg) override;
|
||||
bool msgGame(const GameMessage &msg) override;
|
||||
};
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
|
||||
#endif
|
||||
124
engines/ultima/ultima0/views/intro.cpp
Normal file
124
engines/ultima/ultima0/views/intro.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ultima/ultima0/views/intro.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
bool Intro::msgFocus(const FocusMessage &msg) {
|
||||
_page = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Intro::draw() {
|
||||
auto s = getSurface();
|
||||
s.clear();
|
||||
|
||||
switch (_page) {
|
||||
case 0:
|
||||
s.writeString(Common::Point(5, 1), "Many, many, many years ago the");
|
||||
s.writeString(Common::Point(0, 3), "Dark Lord Mondain, Archfoe of British,");
|
||||
s.writeString(Common::Point(0, 5), "traversed the lands of Akalabeth,");
|
||||
s.writeString(Common::Point(0, 7), "spreading evil and death as he passed.");
|
||||
s.writeString(Common::Point(0, 9), "By the time Mondain was driven from the");
|
||||
s.writeString(Common::Point(0, 11), "land by British, bearer of the White");
|
||||
s.writeString(Common::Point(0, 13), "Light, he had done much damage unto");
|
||||
s.writeString(Common::Point(0, 15), "the lands.");
|
||||
s.writeString(Common::Point(0, 17), "`Tis thy duty to help rid Akalabeth of");
|
||||
s.writeString(Common::Point(0, 19), "the foul beasts which infest it,");
|
||||
s.writeString(Common::Point(0, 21), "while trying to stay alive!!!");
|
||||
break;
|
||||
|
||||
case 1:
|
||||
s.writeString(Common::Point(0, 0), "The Player's Stats:");
|
||||
s.writeString(Common::Point(0, 2), "Hit Points- Amount of Damage a Player");
|
||||
s.writeString(Common::Point(0, 4), " can absorb before Death");
|
||||
s.writeString(Common::Point(0, 6), "Strength--- Related to Damage Inflicted");
|
||||
s.writeString(Common::Point(0, 8), " by Player against Monsters.");
|
||||
s.writeString(Common::Point(0, 10), "Dexterity-- Related to the Probability");
|
||||
s.writeString(Common::Point(0, 12), " of a Player hitting a Monst.");
|
||||
s.writeString(Common::Point(0, 14), "Stamina---- Related to Player Defense");
|
||||
s.writeString(Common::Point(0, 16), " against Monsters");
|
||||
s.writeString(Common::Point(0, 18), "Wisdom----- This Attribute is used");
|
||||
s.writeString(Common::Point(0, 20), " in Special (Quest!) Routines");
|
||||
s.writeString(Common::Point(0, 22), "Gold------- Money!! Cash!! Assets!!");
|
||||
break;
|
||||
|
||||
case 2:
|
||||
s.writeString(Common::Point(0, 0), "The Towns and Buying Items:");
|
||||
s.writeString(Common::Point(0, 2), " To buy any items one need only");
|
||||
s.writeString(Common::Point(0, 4), "type the first letter of the item");
|
||||
s.writeString(Common::Point(0, 6), "wanted. The cost of the respective");
|
||||
s.writeString(Common::Point(0, 8), "items is displayed while in the town.");
|
||||
s.writeString(Common::Point(0, 10), "The Game is started in a town somewhere");
|
||||
s.writeString(Common::Point(0, 12), "on the 20x20 map");
|
||||
s.writeString(Common::Point(20, 14), "Fighters and Magi", Graphics::kTextAlignCenter);
|
||||
s.writeString(Common::Point(0, 16), " The disadvantage of being a");
|
||||
s.writeString(Common::Point(0, 18), "fighter is the lack of the ability to");
|
||||
s.writeString(Common::Point(0, 20), "control the magic amulet, whereas magi");
|
||||
s.writeString(Common::Point(0, 22), "can not use rapier and bows.");
|
||||
break;
|
||||
|
||||
case 3:
|
||||
s.writeString(Common::Point(1, 0), "Movement:");
|
||||
s.writeString(Common::Point(1, 2), "-Key- Outdoors Dungeon");
|
||||
s.writeString(Common::Point(1, 4), " UP Move North Move Forward");
|
||||
s.writeString(Common::Point(1, 6), " LEFT Move West Turn Left");
|
||||
s.writeString(Common::Point(1, 8), "RIGHT Move East Turn Right");
|
||||
s.writeString(Common::Point(1, 10), " DOWN Move South Turn Around");
|
||||
s.writeString(Common::Point(1, 12), " Z Statistics Statistics");
|
||||
s.writeString(Common::Point(1, 14), " A N/A Attack");
|
||||
s.writeString(Common::Point(1, 16), " P Pause Pause");
|
||||
s.writeString(Common::Point(1, 18), " E Go Into Town Climb Ladder");
|
||||
s.writeString(Common::Point(1, 20), " E Go Castle Go Hole");
|
||||
s.writeString(Common::Point(1, 22), "SPACE Pass Pass");
|
||||
break;
|
||||
|
||||
case 4:
|
||||
s.writeString(Common::Point(0, 2), " Thou doest know the basics of");
|
||||
s.writeString(Common::Point(0, 4), "the game, experiment with the commands.");
|
||||
s.writeString(Common::Point(0, 6), "There is much left unsaid for");
|
||||
s.writeString(Common::Point(0, 8), "thee to discover in the future...");
|
||||
s.writeString(Common::Point(0, 10), "Go now unto the world and seek");
|
||||
s.writeString(Common::Point(0, 12), "adventure where thou might!!!");
|
||||
s.writeString(Common::Point(0, 14), "P.S.-Search out the Castle of");
|
||||
s.writeString(Common::Point(0, 16), "Lord British, Use the -E- Key to go in!");
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
s.writeString(Common::Point(20, (_page == 4) ? 18 : 24), "Press any Key to Continue",
|
||||
Graphics::kTextAlignCenter);
|
||||
}
|
||||
|
||||
void Intro::nextPage() {
|
||||
if (++_page < 5)
|
||||
redraw();
|
||||
else
|
||||
replaceView("Title");
|
||||
}
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
62
engines/ultima/ultima0/views/intro.h
Normal file
62
engines/ultima/ultima0/views/intro.h
Normal 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ULTIMA0_VIEWS_INTRO_H
|
||||
#define ULTIMA0_VIEWS_INTRO_H
|
||||
|
||||
#include "ultima/ultima0/views/view.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
class Intro : public View {
|
||||
private:
|
||||
int _page = 0;
|
||||
|
||||
void nextPage();
|
||||
|
||||
public:
|
||||
Intro() : View("Intro") {}
|
||||
~Intro() override {}
|
||||
|
||||
bool msgFocus(const FocusMessage &msg) override;
|
||||
void draw() override;
|
||||
|
||||
bool msgKeypress(const KeypressMessage &msg) override {
|
||||
nextPage();
|
||||
return true;
|
||||
}
|
||||
bool msgMouseDown(const MouseDownMessage &msg) override {
|
||||
nextPage();
|
||||
return true;
|
||||
}
|
||||
bool msgAction(const ActionMessage &msg) override {
|
||||
nextPage();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
|
||||
#endif
|
||||
37
engines/ultima/ultima0/views/startup.cpp
Normal file
37
engines/ultima/ultima0/views/startup.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
/* 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/ultima0/views/startup.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
void Startup::draw() {
|
||||
auto s = getSurface();
|
||||
s.clear();
|
||||
s.writeString(Common::Point(5, 10), "Ultima 0 - Akalabeth!");
|
||||
s.writeString(Common::Point(2, 19), "Ready?");
|
||||
}
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
60
engines/ultima/ultima0/views/startup.h
Normal file
60
engines/ultima/ultima0/views/startup.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/* 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 ULTIMA0_VIEWS_STARTUP_H
|
||||
#define ULTIMA0_VIEWS_STARTUP_H
|
||||
|
||||
#include "ultima/ultima0/views/view.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
class Startup : public View {
|
||||
private:
|
||||
void showTitle() {
|
||||
replaceView("Title");
|
||||
}
|
||||
public:
|
||||
Startup() : View("Startup") {}
|
||||
~Startup() override {}
|
||||
|
||||
void draw() override;
|
||||
|
||||
bool msgKeypress(const KeypressMessage &msg) override {
|
||||
showTitle();
|
||||
return true;
|
||||
}
|
||||
bool msgMouseDown(const MouseDownMessage &msg) override {
|
||||
showTitle();
|
||||
return true;
|
||||
}
|
||||
bool msgAction(const ActionMessage &msg) override {
|
||||
showTitle();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
|
||||
#endif
|
||||
114
engines/ultima/ultima0/views/status.cpp
Normal file
114
engines/ultima/ultima0/views/status.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
/* 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/ultima0/views/status.h"
|
||||
#include "ultima/ultima0/ultima0.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
Status::Status(const Common::String &name, UIElement *parent) : View(name, parent) {
|
||||
setBounds(Common::Rect(0, DEFAULT_SCY - 4 * Gfx::GLYPH_HEIGHT, DEFAULT_SCX, DEFAULT_SCY));
|
||||
}
|
||||
|
||||
bool Status::msgFocus(const FocusMessage &msg) {
|
||||
_message.clear();
|
||||
return View::msgFocus(msg);
|
||||
}
|
||||
|
||||
void Status::draw() {
|
||||
const auto &player = g_engine->_player;
|
||||
auto s = getSurface();
|
||||
s.clear();
|
||||
|
||||
if (!_message.empty())
|
||||
s.writeString(Common::Point(1, 0), _message);
|
||||
|
||||
s.writeString(Common::Point(28, 1), "Food=");
|
||||
s.writeString(Common::Point(28, 2), "H.P.=");
|
||||
s.writeString(Common::Point(28, 3), "Gold=");
|
||||
s.setColor(C_VIOLET);
|
||||
s.writeString(Common::Point(33, 1), Common::String::format("%d", (int)player._object[OB_FOOD]));
|
||||
s.writeString(Common::Point(33, 2), Common::String::format("%d", player._attr[AT_HP]));
|
||||
s.writeString(Common::Point(33, 3), Common::String::format("%d", player._attr[AT_GOLD]));
|
||||
}
|
||||
|
||||
bool Status::msgGame(const GameMessage &msg) {
|
||||
if (msg._name == "MSG") {
|
||||
_message = msg._stringValue;
|
||||
redraw();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
bool DungeonStatus::msgFocus(const FocusMessage &msg) {
|
||||
_lines.clear();
|
||||
return Status::msgFocus(msg);
|
||||
}
|
||||
|
||||
void DungeonStatus::draw() {
|
||||
Status::draw();
|
||||
|
||||
const auto &player = g_engine->_player;
|
||||
auto s = getSurface();
|
||||
|
||||
// Display the current direction
|
||||
if (player._level > 0)
|
||||
s.writeString(Common::Point(15, 0), DIRECTION_NAMES[player.dungeonDir()]);
|
||||
|
||||
// Draw any extra lines
|
||||
for (uint i = 0; i < _lines.size(); ++i)
|
||||
s.writeString(Common::Point(1, 1 + i), _lines[i]);
|
||||
}
|
||||
|
||||
bool DungeonStatus::msgGame(const GameMessage &msg) {
|
||||
if (msg._name == "LINES") {
|
||||
_lines.clear();
|
||||
|
||||
Common::String str = msg._stringValue;
|
||||
uint p;
|
||||
while ((p = str.findFirstOf('\n')) != Common::String::npos) {
|
||||
_lines.push_back(Common::String(str.c_str(), str.c_str() + p));
|
||||
str = Common::String(str.c_str() + p + 1);
|
||||
}
|
||||
if (!str.empty())
|
||||
_lines.push_back(str);
|
||||
|
||||
redraw();
|
||||
return true;
|
||||
|
||||
} else {
|
||||
if (msg._name == "MSG")
|
||||
// Changing message also resets any message lines
|
||||
_lines.clear();
|
||||
|
||||
return Status::msgGame(msg);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
68
engines/ultima/ultima0/views/status.h
Normal file
68
engines/ultima/ultima0/views/status.h
Normal 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 ULTIMA0_VIEWS_STATUS_H
|
||||
#define ULTIMA0_VIEWS_STATUS_H
|
||||
|
||||
#include "ultima/ultima0/views/view.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
class Status : public View {
|
||||
private:
|
||||
Common::String _message;
|
||||
Common::String _direction;
|
||||
|
||||
public:
|
||||
Status(const Common::String &name, UIElement *parent);
|
||||
~Status() override {}
|
||||
|
||||
bool msgFocus(const FocusMessage &msg) override;
|
||||
void draw() override;
|
||||
bool msgGame(const GameMessage &msg) override;
|
||||
};
|
||||
|
||||
class OverworldStatus : public Status {
|
||||
public:
|
||||
OverworldStatus(UIElement *parent) : Status("OverworldStatus", parent) {
|
||||
}
|
||||
};
|
||||
|
||||
class DungeonStatus : public Status {
|
||||
private:
|
||||
Common::StringArray _lines;
|
||||
|
||||
public:
|
||||
DungeonStatus(UIElement *parent) : Status("DungeonStatus", parent) {
|
||||
}
|
||||
|
||||
bool msgFocus(const FocusMessage &msg) override;
|
||||
void draw() override;
|
||||
bool msgGame(const GameMessage &msg) override;
|
||||
};
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
|
||||
#endif
|
||||
144
engines/ultima/ultima0/views/title.cpp
Normal file
144
engines/ultima/ultima0/views/title.cpp
Normal file
@@ -0,0 +1,144 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ultima/ultima0/views/title.h"
|
||||
#include "ultima/ultima0/ultima0.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
Title::Title() : View("Title") {
|
||||
}
|
||||
|
||||
bool Title::msgFocus(const FocusMessage &msg) {
|
||||
_highlightedOption = 0;
|
||||
updateSelections();
|
||||
MetaEngine::setKeybindingMode(KBMODE_MENUS);
|
||||
|
||||
|
||||
Common::String priorView = msg._priorView->getName();
|
||||
if (priorView == "Startup" || priorView == "Dead") {
|
||||
g_engine->playMidi("intro.mid");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Title::msgUnfocus(const UnfocusMessage &msg) {
|
||||
MetaEngine::setKeybindingMode(KBMODE_MINIMAL);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Title::updateSelections() {
|
||||
const int selected = getColor(255, 0, 128);
|
||||
const int white = getColor(255, 255, 255);
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
auto &opt = _options[i];
|
||||
opt._color = opt._index == _highlightedOption ? selected : white;
|
||||
opt.redraw();
|
||||
}
|
||||
}
|
||||
|
||||
void Title::draw() {
|
||||
auto s = getSurface();
|
||||
s.clear();
|
||||
|
||||
View::draw();
|
||||
|
||||
s.writeString(Common::Point(20, 8), "Ultima 0 - Akalabeth!", Graphics::kTextAlignCenter);
|
||||
}
|
||||
|
||||
bool Title::msgAction(const ActionMessage &msg) {
|
||||
switch (msg._action) {
|
||||
case KEYBIND_UP:
|
||||
_highlightedOption = _highlightedOption ? _highlightedOption - 1 : 3;
|
||||
updateSelections();
|
||||
break;
|
||||
case KEYBIND_DOWN:
|
||||
_highlightedOption = (_highlightedOption + 1) % 4;
|
||||
updateSelections();
|
||||
break;
|
||||
case KEYBIND_SELECT:
|
||||
selectOption();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Title::msgGame(const GameMessage &msg) {
|
||||
if (msg._name == "SELECTION") {
|
||||
_highlightedOption = msg._value;
|
||||
updateSelections();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Title::msgMouseDown(const MouseDownMessage &msg) {
|
||||
selectOption();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Title::selectOption() {
|
||||
if (_highlightedOption == 1 || _highlightedOption == 3)
|
||||
g_engine->stopMidi();
|
||||
|
||||
if (_highlightedOption == 3) {
|
||||
if (g_engine->savegamesExist()) {
|
||||
g_engine->loadGameDialog();
|
||||
} else {
|
||||
// Otherwise to go the Create Character view
|
||||
replaceView("CreateCharacter");
|
||||
}
|
||||
} else {
|
||||
const char *VIEW_NAMES[4] = { "Intro", "CreateCharacter", "Acknowledgements" };
|
||||
replaceView(VIEW_NAMES[_highlightedOption]);
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
Title::TitleOption::TitleOption(Title *parent, int index, const Common::String &text, int row) :
|
||||
UIElement("TitleOption", parent), _index(index), _text(text) {
|
||||
int xs = 20 - text.size() / 2;
|
||||
setBounds(Gfx::TextRect(xs, row, xs + text.size(), row));
|
||||
}
|
||||
|
||||
void Title::TitleOption::draw() {
|
||||
auto s = getSurface();
|
||||
s.setColor(_color);
|
||||
s.writeString(_text);
|
||||
}
|
||||
|
||||
bool Title::TitleOption::msgMouseEnter(const MouseEnterMessage &msg) {
|
||||
_parent->send(GameMessage("SELECTION", _index));
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
71
engines/ultima/ultima0/views/title.h
Normal file
71
engines/ultima/ultima0/views/title.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/* 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 ULTIMA0_VIEWS_TITLE_H
|
||||
#define ULTIMA0_VIEWS_TITLE_H
|
||||
|
||||
#include "ultima/ultima0/views/view.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
class Title : public View {
|
||||
class TitleOption : public UIElement {
|
||||
public:
|
||||
int _index;
|
||||
Common::String _text;
|
||||
byte _color = 0;
|
||||
public:
|
||||
TitleOption(Title *parent, int index, const Common::String &text, int row);
|
||||
void draw() override;
|
||||
bool msgMouseEnter(const MouseEnterMessage &msg) override;
|
||||
};
|
||||
|
||||
private:
|
||||
TitleOption _options[4] = {
|
||||
TitleOption(this, 0, "Introduction", 16),
|
||||
TitleOption(this, 1, "Create a Character", 17),
|
||||
TitleOption(this, 2, "Acknowledgements", 18),
|
||||
TitleOption(this, 3, "Journey Onwards", 19)
|
||||
};
|
||||
int _highlightedOption = 0;
|
||||
|
||||
void updateSelections();
|
||||
void selectOption();
|
||||
|
||||
public:
|
||||
Title();
|
||||
~Title() override {}
|
||||
|
||||
bool msgFocus(const FocusMessage &msg) override;
|
||||
bool msgUnfocus(const UnfocusMessage &msg) override;
|
||||
void draw() override;
|
||||
bool msgAction(const ActionMessage &msg) override;
|
||||
bool msgGame(const GameMessage &msg) override;
|
||||
bool msgMouseDown(const MouseDownMessage &msg) override;
|
||||
};
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
|
||||
#endif
|
||||
97
engines/ultima/ultima0/views/town.cpp
Normal file
97
engines/ultima/ultima0/views/town.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
/* 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/ultima0/views/town.h"
|
||||
#include "ultima/ultima0/ultima0.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
static const char *WELCOME = "Welcome to the Adventure Shop";
|
||||
static const char *THANK_YOU = "Thank you m'lord";
|
||||
//static const char *DONT_HAVE_THAT = "I'm Sorry We Don't have that.";
|
||||
static const char *NOT_ENOUGH = "M'Lord thou can not afford that item.";
|
||||
static const char *MAGES_CANT_USE = "I'm sorry, Mages can't use that.";
|
||||
static const char *BYE = "Bye";
|
||||
|
||||
Town::Town() : Info("Town") {
|
||||
}
|
||||
|
||||
bool Town::msgFocus(const FocusMessage &msg) {
|
||||
_message = WELCOME;
|
||||
g_engine->playMidi("shop.mid");
|
||||
return Info::msgFocus(msg);
|
||||
}
|
||||
|
||||
bool Town::msgUnfocus(const UnfocusMessage &msg) {
|
||||
g_engine->stopMidi();
|
||||
return Info::msgUnfocus(msg);
|
||||
}
|
||||
|
||||
void Town::draw() {
|
||||
Info::draw();
|
||||
|
||||
// General message
|
||||
auto s = getSurface();
|
||||
s.writeString(Common::Point(1, 12), _message.empty() ? THANK_YOU : _message);
|
||||
s.writeString(Common::Point(1, 13), "Which item shallt thou buy");
|
||||
_message.clear();
|
||||
}
|
||||
|
||||
void Town::selectObject(int item) {
|
||||
auto &player = g_engine->_player;
|
||||
const auto &obj = OBJECT_INFO[item];
|
||||
|
||||
// Some things mages can't use
|
||||
if (player._class == 'M') {
|
||||
if (item == OB_BOW || item == OB_RAPIER) {
|
||||
_message = MAGES_CANT_USE;
|
||||
redraw();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (obj._cost > player._attr[AT_GOLD]) {
|
||||
_message = NOT_ENOUGH;
|
||||
|
||||
} else {
|
||||
player._attr[AT_GOLD] -= obj._cost; // Lose the money
|
||||
player._object[item] = MIN<int>(player._object[item] + (item == OB_FOOD ? 10 : 1), 999);
|
||||
_message = THANK_YOU;
|
||||
}
|
||||
|
||||
redraw();
|
||||
}
|
||||
|
||||
void Town::leave() {
|
||||
_message = BYE;
|
||||
delaySeconds(1);
|
||||
redraw();
|
||||
}
|
||||
|
||||
void Town::timeout() {
|
||||
replaceView("WorldMap");
|
||||
}
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
54
engines/ultima/ultima0/views/town.h
Normal file
54
engines/ultima/ultima0/views/town.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/* 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 ULTIMA0_VIEWS_TOWN_H
|
||||
#define ULTIMA0_VIEWS_TOWN_H
|
||||
|
||||
#include "ultima/ultima0/views/info.h"
|
||||
#include "ultima/ultima0/data/data.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
class Town : public Info {
|
||||
private:
|
||||
Common::String _message;
|
||||
|
||||
protected:
|
||||
void selectObject(int item) override;
|
||||
void leave() override;
|
||||
|
||||
public:
|
||||
Town();
|
||||
~Town() override {}
|
||||
|
||||
bool msgFocus(const FocusMessage &msg) override;
|
||||
bool msgUnfocus(const UnfocusMessage &msg) override;
|
||||
void draw() override;
|
||||
void timeout() override;
|
||||
};
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
|
||||
#endif
|
||||
90
engines/ultima/ultima0/views/view.cpp
Normal file
90
engines/ultima/ultima0/views/view.cpp
Normal 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/ultima0/views/view.h"
|
||||
#include "ultima/ultima0/ultima0.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
void View::checkFocusedControl(const Common::Point &mousePos) {
|
||||
if (_focusedElement) {
|
||||
if (!_focusedElement->getBounds().contains(mousePos)) {
|
||||
_focusedElement->send(MouseLeaveMessage());
|
||||
_focusedElement = nullptr;
|
||||
}
|
||||
|
||||
} else {
|
||||
for (UIElement *child : _children) {
|
||||
if (child->getBounds().contains(mousePos)) {
|
||||
_focusedElement = child;
|
||||
child->send(MouseEnterMessage());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UIElement *View::getElementAtPos(const Common::Point &pos) const {
|
||||
for (UIElement *child : _children) {
|
||||
if (child->getBounds().contains(pos))
|
||||
return child;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
bool View::msgFocus(const FocusMessage &msg) {
|
||||
_focusedElement = nullptr;
|
||||
return UIElement::msgFocus(msg);
|
||||
}
|
||||
|
||||
bool View::msgUnfocus(const UnfocusMessage &msg) {
|
||||
if (_focusedElement)
|
||||
_focusedElement->send(MouseLeaveMessage());
|
||||
|
||||
return UIElement::msgUnfocus(msg);
|
||||
}
|
||||
|
||||
bool View::msgMouseMove(const MouseMoveMessage &msg) {
|
||||
checkFocusedControl(msg._pos);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool View::msgMouseDown(const MouseDownMessage &msg) {
|
||||
UIElement *child = getElementAtPos(msg._pos);
|
||||
return child ? child->send(msg) : false;
|
||||
}
|
||||
|
||||
bool View::msgMouseUp(const MouseUpMessage &msg) {
|
||||
UIElement *child = getElementAtPos(msg._pos);
|
||||
return child ? child->send(msg) : false;
|
||||
}
|
||||
|
||||
byte View::getColor(byte r, byte g, byte b) {
|
||||
return g_engine->_palette.findBestColor(r, g, b);
|
||||
}
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
80
engines/ultima/ultima0/views/view.h
Normal file
80
engines/ultima/ultima0/views/view.h
Normal 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 ULTIMA0_VIEWS_VIEW_H
|
||||
#define ULTIMA0_VIEWS_VIEW_H
|
||||
|
||||
#include "ultima/ultima0/events.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
/**
|
||||
* Base view class for screens and dialogs that appear on-screen.
|
||||
* The View class takes care of two important things:
|
||||
* 1) By default events get sent to all controls on a view until one
|
||||
* handles it. For mouse events, we instead want only the control the
|
||||
* mouse cursor is over to receive the events, saving the individual
|
||||
* controls from having to check if the mouse is within their bounds.
|
||||
* 2) Individual elements will get a Focus/Unfocus message as the
|
||||
* mouse enters and leaves them. This allows, for example, buttons
|
||||
* that have been pressed to de-select if the mouse leaves their bounds.
|
||||
*/
|
||||
class View : public UIElement {
|
||||
private:
|
||||
UIElement *_focusedElement = nullptr;
|
||||
|
||||
/**
|
||||
* Checks if a control is entered or left
|
||||
*/
|
||||
void checkFocusedControl(const Common::Point &mousePos);
|
||||
|
||||
/**
|
||||
* Check for an element at the given position
|
||||
*/
|
||||
UIElement *getElementAtPos(const Common::Point &pos) const;
|
||||
|
||||
protected:
|
||||
byte getColor(byte r, byte g, byte b);
|
||||
|
||||
public:
|
||||
View(const Common::String &name, UIElement *uiParent) :
|
||||
UIElement(name, uiParent) {
|
||||
}
|
||||
View(const Common::String &name) :
|
||||
UIElement(name) {
|
||||
}
|
||||
virtual ~View() {
|
||||
}
|
||||
|
||||
bool msgFocus(const FocusMessage &msg) override;
|
||||
bool msgUnfocus(const UnfocusMessage &msg) override;
|
||||
bool msgMouseMove(const MouseMoveMessage &msg) override;
|
||||
bool msgMouseDown(const MouseDownMessage &msg) override;
|
||||
bool msgMouseUp(const MouseUpMessage &msg) override;
|
||||
};
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
|
||||
#endif
|
||||
61
engines/ultima/ultima0/views/views.h
Normal file
61
engines/ultima/ultima0/views/views.h
Normal 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ULTIMA0_VIEWS_H
|
||||
#define ULTIMA0_VIEWS_H
|
||||
|
||||
#include "ultima/ultima0/views/acknowledgements.h"
|
||||
#include "ultima/ultima0/views/attack.h"
|
||||
#include "ultima/ultima0/views/castle.h"
|
||||
#include "ultima/ultima0/views/create_character.h"
|
||||
#include "ultima/ultima0/views/dead.h"
|
||||
#include "ultima/ultima0/views/dungeon.h"
|
||||
#include "ultima/ultima0/views/info.h"
|
||||
#include "ultima/ultima0/views/intro.h"
|
||||
#include "ultima/ultima0/views/startup.h"
|
||||
#include "ultima/ultima0/views/title.h"
|
||||
#include "ultima/ultima0/views/town.h"
|
||||
#include "ultima/ultima0/views/world_map.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
struct Views {
|
||||
Acknowledgements _acknowledgements;
|
||||
Attack _attack;
|
||||
Castle _castle;
|
||||
CreateCharacter _createCharacter;
|
||||
Dead _dead;
|
||||
Dungeon _dungeon;
|
||||
Info _info;
|
||||
Intro _intro;
|
||||
Startup _startup;
|
||||
Title _title;
|
||||
Town _town;
|
||||
WorldMap _worldMap;
|
||||
};
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
|
||||
#endif
|
||||
223
engines/ultima/ultima0/views/world_map.cpp
Normal file
223
engines/ultima/ultima0/views/world_map.cpp
Normal file
@@ -0,0 +1,223 @@
|
||||
/* 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/ultima0/views/world_map.h"
|
||||
#include "ultima/ultima0/ultima0.h"
|
||||
#include "ultima/ultima0/metaengine.h"
|
||||
#include "ultima/ultima0/gfx/font.h"
|
||||
#include "ultima/ultima0/gfx/map.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
WorldMap::WorldMap() : View("WorldMap") {
|
||||
}
|
||||
|
||||
bool WorldMap::msgFocus(const FocusMessage &msg) {
|
||||
showMessage("");
|
||||
MetaEngine::setKeybindingMode(KBMODE_OVERWORLD);
|
||||
|
||||
if (!g_engine->isMidiPlaying())
|
||||
g_engine->playMidi("over.mid");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WorldMap::msgUnfocus(const UnfocusMessage &msg) {
|
||||
MetaEngine::setKeybindingMode(KBMODE_MINIMAL);
|
||||
return true;
|
||||
}
|
||||
|
||||
void WorldMap::draw() {
|
||||
auto s = getSurface();
|
||||
|
||||
// Draw the map
|
||||
Graphics::ManagedSurface mapArea(s, Common::Rect(0, 0, s.w, s.h - Gfx::GLYPH_HEIGHT * 4));
|
||||
Gfx::Map::draw(&mapArea);
|
||||
|
||||
// Allow the status area to draw
|
||||
View::draw();
|
||||
|
||||
if (g_engine->_showMinimap) {
|
||||
s.frameRect(Common::Rect(s.w - WORLD_MINIMAP_SIZE - 4, 0, s.w, WORLD_MINIMAP_SIZE + 4), C_GREY);
|
||||
s.frameRect(Common::Rect(s.w - WORLD_MINIMAP_SIZE - 3, 1, s.w - 1, WORLD_MINIMAP_SIZE + 3), C_GREY);
|
||||
Graphics::ManagedSurface minimapArea(s, Common::Rect(s.w - WORLD_MINIMAP_SIZE - 2, 2, s.w - 2, WORLD_MINIMAP_SIZE + 2));
|
||||
Gfx::Map::draw(&minimapArea, true);
|
||||
}
|
||||
}
|
||||
|
||||
bool WorldMap::msgAction(const ActionMessage &msg) {
|
||||
if (isDelayActive())
|
||||
return false;
|
||||
|
||||
switch (msg._action) {
|
||||
case KEYBIND_UP:
|
||||
showMessage("North");
|
||||
move(0, -1);
|
||||
break;
|
||||
case KEYBIND_DOWN:
|
||||
showMessage("South");
|
||||
move(0, 1);
|
||||
break;
|
||||
case KEYBIND_LEFT:
|
||||
showMessage("West");
|
||||
move(-1, 0);
|
||||
break;
|
||||
case KEYBIND_RIGHT:
|
||||
showMessage("East");
|
||||
move(1, 0);
|
||||
break;
|
||||
case KEYBIND_INFO:
|
||||
// Show character info screen
|
||||
showMessage("");
|
||||
replaceView("Info");
|
||||
break;
|
||||
case KEYBIND_ENTER:
|
||||
enter();
|
||||
break;
|
||||
case KEYBIND_PASS:
|
||||
showMessage("");
|
||||
break;
|
||||
case KEYBIND_QUIT:
|
||||
// "Quit" in the original which merely saves the game. For ScummVM,
|
||||
// we open the GMM, allowing the user to either save or quit
|
||||
g_engine->openMainMenuDialog();
|
||||
return true;
|
||||
case KEYBIND_MINIMAP:
|
||||
g_engine->_showMinimap = !g_engine->_showMinimap;
|
||||
redraw();
|
||||
break;
|
||||
default:
|
||||
showMessage("");
|
||||
break;
|
||||
}
|
||||
|
||||
endOfTurn();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WorldMap::msgKeypress(const KeypressMessage &msg) {
|
||||
if (isDelayActive())
|
||||
return false;
|
||||
|
||||
endOfTurn();
|
||||
return true;
|
||||
}
|
||||
|
||||
void WorldMap::endOfTurn() {
|
||||
auto &player = g_engine->_player;
|
||||
|
||||
if (player._attr[AT_HP] <= 0) {
|
||||
g_engine->stopMidi();
|
||||
replaceView("Dead");
|
||||
|
||||
} else {
|
||||
player._object[OB_FOOD] = MAX(player._object[OB_FOOD] - 1.0, 0.0);
|
||||
if (player._object[OB_FOOD] == 0) {
|
||||
showMessage("You have starved...");
|
||||
delaySeconds(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WorldMap::timeout() {
|
||||
const auto &map = g_engine->_worldMap;
|
||||
auto &player = g_engine->_player;
|
||||
auto &dungeon = g_engine->_dungeon;
|
||||
|
||||
g_engine->stopMidi();
|
||||
|
||||
if (player._attr[AT_HP] <= 0 || player._object[OB_FOOD] <= 0) {
|
||||
// Timeout from displaying player was killed
|
||||
replaceView("Dead");
|
||||
} else {
|
||||
// Otherwise a timeout from entering a location
|
||||
int t = map.read(player._worldPos.x, player._worldPos.y);
|
||||
switch (t) {
|
||||
case WT_TOWN:
|
||||
replaceView("Town");
|
||||
break;
|
||||
case WT_DUNGEON:
|
||||
player._level = 1; // Go to level 1
|
||||
player._dungeonPos.x = 1; // Set initial position
|
||||
player._dungeonPos.y = 1;
|
||||
player._dungeonDir.x = 1; // And direction
|
||||
player._dungeonDir.y = 0;
|
||||
dungeon.create(player);
|
||||
|
||||
replaceView("Dungeon");
|
||||
break;
|
||||
case WT_BRITISH:
|
||||
replaceView("Castle");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WorldMap::move(int xi, int yi) {
|
||||
auto &player = g_engine->_player;
|
||||
auto &map = g_engine->_worldMap;
|
||||
|
||||
// Calculate new position
|
||||
int x1 = player._worldPos.x + xi;
|
||||
int y1 = player._worldPos.y + yi;
|
||||
|
||||
if (map.read(x1, y1) == WT_MOUNTAIN) {
|
||||
showMessage("You can't pass the mountains.");
|
||||
} else {
|
||||
// Move
|
||||
player._worldPos.x = x1;
|
||||
player._worldPos.y = y1;
|
||||
redraw();
|
||||
}
|
||||
}
|
||||
|
||||
void WorldMap::enter() {
|
||||
const auto &player = g_engine->_player;
|
||||
const auto &map = g_engine->_worldMap;
|
||||
|
||||
int t = map.read(player._worldPos.x, player._worldPos.y);
|
||||
switch (t) {
|
||||
case WT_TOWN:
|
||||
showMessage("Enter Town.");
|
||||
delaySeconds(1);
|
||||
break;
|
||||
case WT_DUNGEON:
|
||||
showMessage("Enter Dungeon.");
|
||||
delaySeconds(1);
|
||||
break;
|
||||
case WT_BRITISH:
|
||||
showMessage("Enter Castle.");
|
||||
delaySeconds(1);
|
||||
break;
|
||||
default:
|
||||
// Nope....
|
||||
showMessage("Huh???");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
59
engines/ultima/ultima0/views/world_map.h
Normal file
59
engines/ultima/ultima0/views/world_map.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/* 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 ULTIMA0_VIEWS_WORLD_MAP_H
|
||||
#define ULTIMA0_VIEWS_WORLD_MAP_H
|
||||
|
||||
#include "ultima/ultima0/views/view.h"
|
||||
#include "ultima/ultima0/views/status.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima0 {
|
||||
namespace Views {
|
||||
|
||||
class WorldMap : public View {
|
||||
private:
|
||||
OverworldStatus _status = OverworldStatus(this);
|
||||
|
||||
void move(int xi, int yi);
|
||||
void enter();
|
||||
void endOfTurn();
|
||||
void showMessage(const Common::String &msg) {
|
||||
_status.send(GameMessage("MSG", msg));
|
||||
}
|
||||
|
||||
public:
|
||||
WorldMap();
|
||||
~WorldMap() override {}
|
||||
|
||||
bool msgFocus(const FocusMessage &msg) override;
|
||||
bool msgUnfocus(const UnfocusMessage &msg) override;
|
||||
void draw() override;
|
||||
bool msgAction(const ActionMessage &msg) override;
|
||||
bool msgKeypress(const KeypressMessage &msg) override;
|
||||
void timeout() override;
|
||||
};
|
||||
|
||||
} // namespace Views
|
||||
} // namespace Ultima0
|
||||
} // namespace Ultima
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user