ULTIMA1: Basic arrow movement is now working

This commit is contained in:
Paul Gilbert 2020-01-18 15:59:39 -08:00 committed by Paul Gilbert
parent b0219c7725
commit ee65b99bd5
16 changed files with 303 additions and 16 deletions

View File

@ -49,6 +49,7 @@ MODULE_OBJS += \
ultima1/actions/move.o \
ultima1/core/map.o \
ultima1/core/resources.o \
ultima1/core/transports.o \
ultima1/gfx/drawing_support.o \
ultima1/gfx/game_view.o \
ultima1/gfx/status.o \

View File

@ -108,6 +108,26 @@ Point Map::getViewportPosition(const Point &viewportSize) {
return topLeft;
}
void Map::shiftViewport(const Point &delta) {
Point &topLeft = _viewportPos._topLeft;
topLeft += delta;
if (_fixed) {
// Shift the viewport, but constraining the map to fill up the screen
topLeft.x = CLIP(topLeft.x, (int16)0, (int16)(width() - _viewportPos._size.x));
topLeft.y = CLIP(topLeft.y, (int16)0, (int16)(height() - _viewportPos._size.y));
} else {
if (topLeft.x < 0)
topLeft.x += width();
else if (topLeft.x >= (int16)width())
topLeft.x -= width();
if (topLeft.y < 0)
topLeft.y += height();
else if (topLeft.y >= (int16)height())
topLeft.y -= height();
}
}
void Map::getTileAt(const Point &pt, MapTile *tile) {
// Get the base tile
tile->_tileNum = _data[pt.y * _size.x + pt.x];

View File

@ -31,7 +31,7 @@ namespace Ultima {
namespace Shared {
enum Direction {
DIR_UP = 1, DIR_DOWN = 2, DIR_LEFT = 3, DIR_RIGHT = 4
DIR_LEFT = 1, DIR_RIGHT = 2, DIR_UP = 3, DIR_DOWN = 4
};
class Game;
@ -115,12 +115,13 @@ protected:
byte _mapId; // The map Id
Common::Array<MapWidgetPtr> _widgets; // Party, monsteres, transports, etc.
Common::Array<int16> _data; // Data for the map
Point _position; // Current position within the map
ViewportPosition _viewportPos; // Viewport position
public:
Point _size; // X, Y size of the map
Point _tilesPerOrigTile; // For enhanced modes, number of tiles per original game tile
Point _position; // Current position within the map
Direction _direction; // Current direction being faced in the underworld
bool _fixed; // Town/city type maps that don't scroll as the player moves
ViewportPosition _viewportPos; // Viewport position
protected:
/**
* Gets a point relative to the current position
@ -144,9 +145,9 @@ public:
size_t height() const { return _size.y; }
/**
* Load a given map
* Return the current position
*/
virtual void loadMap(int mapId, uint videoMode);
Point getPosition() const { return _position; }
/**
* Set the position
@ -158,6 +159,11 @@ public:
*/
Point getViewportPosition(const Point &viewportSize);
/**
* Shifts the viewport by a given delta
*/
void shiftViewport(const Point &delta);
/**
* Gets a tile at a given position
*/
@ -167,6 +173,11 @@ public:
* Adds a widget to the map
*/
void addWidget(MapWidget *widget);
/**
* Load a given map
*/
virtual void loadMap(int mapId, uint videoMode);
};
} // End of namespace Shared

View File

@ -61,6 +61,10 @@ Map *TreeItem::getMap() {
return getGameState()->_map;
}
Gfx::VisualItem *TreeItem::getView() {
return getRoot()->getView();
}
TreeItem *TreeItem::getLastChild() const {
if (!_firstChild)
return nullptr;

View File

@ -28,6 +28,10 @@
namespace Ultima {
namespace Shared {
namespace Gfx {
class VisualItem;
} // End of namespace Gfx
class Game;
class GameManager;
class GameState;
@ -108,6 +112,11 @@ public:
*/
Map *getMap();
/**
* Returns the currently active game view
*/
Gfx::VisualItem *getView();
/**
* Get the next sibling
*/

View File

@ -251,6 +251,16 @@ MESSAGE1(CFrameMsg, uint, ticks, 0);
*/
MESSAGE1(CMoveMsg, int, direction, 0);
/**
* Adds text strings to the status area
*/
MESSAGE1(CStatusMsg, Common::String, text, "");
/**
* Signals a sound effect
*/
MESSAGE1(CSoundEffectMsg, uint, effectNum, 0);
} // End of namespace Shared
} // End of namespace Ultima

View File

@ -21,6 +21,11 @@
*/
#include "ultima/ultima1/actions/action.h"
#include "ultima/ultima1/game.h"
#include "ultima/ultima1/core/map.h"
#include "ultima/ultima1/core/resources.h"
#include "ultima/shared/engine/messages.h"
#include "ultima/shared/gfx/visual_item.h"
namespace Ultima {
namespace Ultima1 {
@ -31,6 +36,23 @@ Action::Action(TreeItem *parent) : Shared::TreeItem() {
addUnder(parent);
}
Ultima1Game *Action::getRoot() {
return static_cast<Ultima1Game *>(TreeItem::getRoot());
}
Ultima1Map *Action::getMap() {
return static_cast<Ultima1Map *>(TreeItem::getMap());
}
GameResources *Action::getRes() {
return getRoot()->_res;
}
void Action::addStatusMsg(const Common::String &text) {
Shared::CStatusMsg msg(text);
msg.execute(getView());
}
} // End of namespace Actions
} // End of namespace Ultima1
} // End of namespace Ultima

View File

@ -30,6 +30,7 @@ namespace Ultima1 {
class Ultima1Game;
class Ultima1Map;
class GameResources;
namespace Actions {
@ -54,6 +55,16 @@ public:
* Return the game's map
*/
Ultima1Map *getMap();
/**
* Gets the data resources for the game
*/
GameResources *getRes();
/**
* Adds a text string to the status area
*/
void addStatusMsg(const Common::String &text);
};
} // End of namespace Actions

View File

@ -21,6 +21,10 @@
*/
#include "ultima/ultima1/actions/move.h"
#include "ultima/ultima1/game.h"
#include "ultima/ultima1/core/map.h"
#include "ultima/ultima1/core/transports.h"
#include "ultima/ultima1/core/resources.h"
namespace Ultima {
namespace Ultima1 {
@ -30,7 +34,41 @@ BEGIN_MESSAGE_MAP(Move, Action)
ON_MESSAGE(MoveMsg)
END_MESSAGE_MAP()
bool Move::MoveMsg(Shared::CMoveMsg &msg) {
bool Move::MoveMsg(CMoveMsg &msg) {
Ultima1Map *map = getMap();
WidgetTransport *transport = map->_currentTransport;
// Figure out the new position
Point delta;
switch (msg._direction) {
case Shared::DIR_LEFT:
delta = Point(-1, 0);
break;
case Shared::DIR_RIGHT:
delta = Point(1, 0);
break;
case Shared::DIR_UP:
delta = Point(0, -1);
break;
case Shared::DIR_DOWN:
delta = Point(0, 1);
break;
}
// Check if the given transport type can move to the new position
Point newPos = map->getPosition() + delta;
if (transport->canMoveTo(newPos)) {
// Shift the viewport
map->shiftViewport(delta);
// Move to the new position
if (transport->moveTo(newPos))
addStatusMsg(getRes()->DIRECTION_NAMES[msg._direction - 1]);
} else {
// Nope, so show a blocked message
addStatusMsg(getRes()->BLOCKED);
}
return true;
}

View File

@ -21,7 +21,7 @@
*/
#include "ultima/ultima1/core/map.h"
#include "ultima/ultima1/core/widget_player.h"
#include "ultima/ultima1/core/transports.h"
#include "ultima/ultima1/game.h"
#include "ultima/shared/core/file.h"
@ -31,7 +31,8 @@ namespace Ultima1 {
using Shared::File;
Ultima1Map::Ultima1Map(Ultima1Game *game) : Shared::Map(), _mapType(MAP_OVERWORLD), _mapStyle(0), _mapIndex(0) {
addWidget(new WidgetPlayer(game, this));
_currentTransport = new TransportOnFoot(game, this);
addWidget(_currentTransport);
}
void Ultima1Map::loadMap(int mapId, uint videoMode) {

View File

@ -33,6 +33,7 @@ enum MapType {
};
class Ultima1Game;
class WidgetTransport;
class U1MapTile : public Shared::MapTile {
public:
@ -55,6 +56,7 @@ public:
uint _mapStyle; // Map style category for towns & castles
uint _mapIndex; // Map index, such as city/castle #; not to be confused with mapId
Common::String _name; // Name of map, if applicable
WidgetTransport *_currentTransport; // Current means of transport, even if on foot
public:
/**
* Constructor

View File

@ -28,6 +28,8 @@ namespace Ultima1 {
const char *const SRC_STATUS_TEXT[4] = { "Hits:", "Food:", "Exp.:", "Coin:" };
const char *const SRC_DIRECTION_NAMES[4] = { "West", "East", "North", "South" };
const char *const SRC_LOCATION_NAMES[85] = {
"?",
"Britian",
@ -119,6 +121,8 @@ const char *const SRC_LOCATION_NAMES[85] = {
"The Hole to Hades"
};
const char *const SRC_BLOCKED = "Blocked!";
/*-------------------------------------------------------------------*/
GameResources::GameResources() : LocalResourceFile("ULTIMA1/DATA") {
@ -126,12 +130,16 @@ GameResources::GameResources() : LocalResourceFile("ULTIMA1/DATA") {
GameResources::GameResources(Shared::Resources *resManager) : LocalResourceFile(resManager, "ULTIMA1/DATA") {
Common::copy(SRC_STATUS_TEXT, SRC_STATUS_TEXT + 4, STATUS_TEXT);
Common::copy(SRC_DIRECTION_NAMES, SRC_DIRECTION_NAMES + 4, DIRECTION_NAMES);
Common::copy(SRC_LOCATION_NAMES, SRC_LOCATION_NAMES + 85, LOCATION_NAMES);
BLOCKED = SRC_BLOCKED;
}
void GameResources::synchronize() {
syncStrings(STATUS_TEXT, 4);
syncStrings(DIRECTION_NAMES, 4);
syncStrings(LOCATION_NAMES, 32);
syncString(BLOCKED);
}
} // End of namespace Ultima1

View File

@ -36,7 +36,9 @@ protected:
virtual void synchronize();
public:
const char *STATUS_TEXT[4];
const char *DIRECTION_NAMES[4];
const char *LOCATION_NAMES[85];
const char *BLOCKED;
public:
GameResources();
GameResources(Shared::Resources *resManager);

View File

@ -0,0 +1,48 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "ultima/ultima1/core/transports.h"
#include "ultima/ultima1/core/map.h"
#include "common/algorithm.h"
namespace Ultima {
namespace Ultima1 {
bool TransportOnFoot::canMoveTo(const Point &destPos) {
return true;
}
bool TransportOnFoot::moveTo(const Point &destPos) {
_map->setPosition(destPos);
return true;
}
bool TransportOnFoot::isPrincessSaved() const {
return false;
}
void TransportOnFoot::princessSaved() {
}
} // End of namespace Ultima1
} // End of namespace Ultima

View File

@ -0,0 +1,100 @@
/* 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 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef ULTIMA_ULTIMA1_CORE_WIDGET_PLAYER_H
#define ULTIMA_ULTIMA1_CORE_WIDGET_PLAYER_H
#include "ultima/shared/core/map.h"
namespace Ultima {
namespace Ultima1 {
class WidgetTransport : public Shared::MapWidget {
public:
/**
* Constructor
*/
WidgetTransport(Shared::Game *game, Shared::Map *map) : Shared::MapWidget(game, map) {}
/**
* Destructor
*/
virtual ~WidgetTransport() {}
/**
* Returns true if the given transport type can move to a given position on the map
* @param destPos Specified new position
*/
virtual bool canMoveTo(const Point &destPos) = 0;
/**
* Moves to a given position
* @param destPos Specified new position
* @returns If true, the direction moved will be printed in the status area
*/
virtual bool moveTo(const Point &destPos) = 0;
};
class TransportOnFoot : public WidgetTransport {
private:
/**
* Checks for whether a princess has been saved from a castle being left
*/
bool isPrincessSaved() const;
/**
* Called for a princess being saved
*/
void princessSaved();
public:
/**
* Constructor
*/
TransportOnFoot(Shared::Game *game, Shared::Map *map) : WidgetTransport(game, map) {}
/**
* Destructor
*/
virtual ~TransportOnFoot() {}
/**
* Get the tile for the transport method
*/
virtual uint getTileNum() const { return 10; }
/**
* Returns true if the given transport type can move to a given position on the map
*/
virtual bool canMoveTo(const Point &destPos);
/**
* Moves to a given position
* @param destPos Specified new position
* @returns If true, the direction moved will be printed in the status area
*/
virtual bool moveTo(const Point &destPos);
};
} // End of namespace Ultima1
} // End of namespace Ultima
#endif

View File

@ -63,17 +63,17 @@ void GameView::draw() {
}
bool GameView::VirtualKeyCharMsg(CVirtualKeyCharMsg &msg) {
if (msg._keyState.keycode == Common::KEYCODE_UP || msg._keyState.keycode == Common::KEYCODE_KP8) {
if (msg._keyState.keycode == Common::KEYCODE_LEFT || msg._keyState.keycode == Common::KEYCODE_KP4) {
Shared::CMoveMsg move(Shared::DIR_LEFT);
move.execute(this);
} else if (msg._keyState.keycode == Common::KEYCODE_RIGHT || msg._keyState.keycode == Common::KEYCODE_KP6) {
Shared::CMoveMsg move(Shared::DIR_RIGHT);
move.execute(this);
} else if (msg._keyState.keycode == Common::KEYCODE_UP || msg._keyState.keycode == Common::KEYCODE_KP8) {
Shared::CMoveMsg move(Shared::DIR_UP);
move.execute(this);
} else if (msg._keyState.keycode == Common::KEYCODE_DOWN || msg._keyState.keycode == Common::KEYCODE_KP2) {
Shared::CMoveMsg move(Shared::DIR_LEFT);
move.execute(this);
} else if (msg._keyState.keycode == Common::KEYCODE_LEFT || msg._keyState.keycode == Common::KEYCODE_KP4) {
Shared::CMoveMsg move(Shared::DIR_LEFT);
move.execute(this);
} else if (msg._keyState.keycode == Common::KEYCODE_RIGHT || msg._keyState.keycode == Common::KEYCODE_KP6) {
Shared::CMoveMsg move(Shared::DIR_LEFT);
Shared::CMoveMsg move(Shared::DIR_DOWN);
move.execute(this);
} else {
return false;