mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-11 11:45:21 +00:00
ULTIMA4: Added support for XML-based maps
This includes the addition of a hidden ScummVM map, just as an easter egg for anyone that stumbles across it
This commit is contained in:
parent
077967fee4
commit
683959ea2d
@ -7,7 +7,7 @@
|
||||
|
||||
<!ELEMENT maps ( map+ ) >
|
||||
|
||||
<!ELEMENT map ( city | compressedchunk | dungeon | moongate | portal | shrine | label )* >
|
||||
<!ELEMENT map ( city | compressedchunk | dungeon | moongate | portal | shrine | xml | label )* >
|
||||
<!ATTLIST map id NMTOKEN #REQUIRED
|
||||
type ( city | combat | dungeon | shrine | world | u3world ) #REQUIRED
|
||||
fname NMTOKEN #REQUIRED
|
||||
|
@ -41,7 +41,9 @@
|
||||
<portal x="81" y="207" destmapid="30" startx="0" starty="0" action="enter" condition="shrine" savelocation="true" transport="footorhorse"/>
|
||||
<portal x="231" y="216" destmapid="32" startx="0" starty="0" action="enter" condition="shrine" savelocation="true" transport="footorhorse"/>
|
||||
|
||||
<moongate phase="0" x="224" y="133"/>
|
||||
<portal x="102" y="105" destmapid="101" startx="1" starty="5" action="enter" savelocation="true" transport="footorhorse" tile="5"/>
|
||||
|
||||
<moongate phase="0" x="224" y="133"/>
|
||||
<moongate phase="1" x="96" y="102"/>
|
||||
<moongate phase="2" x="38" y="224"/>
|
||||
<moongate phase="3" x="50" y="37"/>
|
||||
@ -406,4 +408,6 @@
|
||||
<map id="55" type="combat" fname="camp.dng" width="11" height="11" levels="1"
|
||||
borderbehavior="fixed" nolineofsight="true" music="8" tileset="base" tilemap="base"/>
|
||||
|
||||
<!-- Custom maps introduced under ScummVM-->
|
||||
<xi:include xmlns:xi="http://www.w3.org/2003/XInclude" href="scummvm_map.xml"/>
|
||||
</maps>
|
||||
|
17
devtools/create_ultima/files/ultima4/conf/scummvm_map.xml
Normal file
17
devtools/create_ultima/files/ultima4/conf/scummvm_map.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0"?>
|
||||
<map id="101" type="xml" fname="scummvm.xml" width="57" height="11" levels="1"
|
||||
borderbehavior="exit" showavatar="true" music="2" tileset="base" tilemap="base">
|
||||
<tiles>
|
||||
127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127
|
||||
127,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,127
|
||||
127,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,127
|
||||
127,04,04,63,63,63,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,63,04,04,04,04,04,04,63,04,63,04,04,04,04,04,63,04,04,04,04,04,04,04,127
|
||||
004,04,63,04,04,04,63,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,63,04,04,04,04,63,04,04,63,63,04,04,04,63,63,04,04,00,00,00,04,04,127
|
||||
004,04,04,63,04,04,04,04,04,63,63,63,04,63,04,04,04,63,04,63,63,04,04,63,63,04,63,63,04,04,63,63,04,04,63,04,04,04,04,63,04,04,63,04,63,04,63,04,63,04,04,23,03,23,04,04,127
|
||||
004,04,04,04,63,63,04,04,63,04,04,04,04,63,04,04,04,63,04,63,04,63,63,04,63,04,63,04,63,63,04,63,04,04,04,63,04,04,63,04,04,04,63,04,04,63,04,04,63,04,04,00,00,00,04,04,127
|
||||
127,04,63,04,04,04,63,04,63,04,04,04,04,63,04,04,63,63,04,63,04,04,04,04,63,04,63,04,04,04,04,63,04,04,04,63,04,04,63,04,04,04,63,04,04,04,04,04,63,04,04,04,04,04,04,04,127
|
||||
127,04,04,63,63,63,04,04,04,63,63,63,04,04,63,63,04,63,04,63,04,04,04,04,63,04,63,04,04,04,04,63,04,04,04,04,63,63,04,04,04,04,63,04,04,04,04,04,63,04,04,04,04,04,04,04,127
|
||||
127,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,04,127
|
||||
127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127
|
||||
</tiles>
|
||||
</map>
|
@ -208,7 +208,7 @@ void CombatController::initDungeonRoom(int room, Direction from) {
|
||||
ASSERT(g_context->_location->_prev->_context & CTX_DUNGEON, "Error: called initDungeonRoom from non-dungeon context");
|
||||
{
|
||||
Dungeon *dng = dynamic_cast<Dungeon *>(g_context->_location->_prev->_map);
|
||||
assert(dng);
|
||||
assert(dng);
|
||||
|
||||
DngRoom &dngRoom = dng->_rooms[room];
|
||||
|
||||
|
@ -1002,6 +1002,15 @@ bool Debugger::cmdSearch(int argc, const char **argv) {
|
||||
dungeonSearch();
|
||||
} else if (g_context->_party->isFlying()) {
|
||||
print("Searching...\n%cDrift only!%c", FG_GREY, FG_WHITE);
|
||||
} else if (g_context->_location->_map->_id == MAP_SCUMMVM &&
|
||||
g_context->_location->_coords == Coords(52, 5, 0)) {
|
||||
// Special hack for the ScummVM easter egg map. Searching on
|
||||
// the given tile triggers the cheat to allow teleporting
|
||||
print("Searching...\nFound teleport point!");
|
||||
g_game->exitToParentMap();
|
||||
g_music->playMapMusic();
|
||||
|
||||
return cmdGoto(argc, argv);
|
||||
} else {
|
||||
print("Searching...");
|
||||
|
||||
|
@ -62,6 +62,7 @@ struct Portal {
|
||||
Common::String _message;
|
||||
TransportContext _portalTransportRequisites;
|
||||
bool _exitPortal;
|
||||
int _tile;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -140,7 +140,8 @@ public:
|
||||
CITY,
|
||||
SHRINE,
|
||||
COMBAT,
|
||||
DUNGEON
|
||||
DUNGEON,
|
||||
XML
|
||||
};
|
||||
|
||||
enum BorderBehavior {
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "ultima/ultima4/game/portal.h"
|
||||
#include "ultima/ultima4/map/tilemap.h"
|
||||
#include "ultima/ultima4/map/tileset.h"
|
||||
#include "ultima/ultima4/map/xml_map.h"
|
||||
#include "ultima/ultima4/filesys/u4file.h"
|
||||
#include "ultima/ultima4/core/utils.h"
|
||||
#include "ultima/ultima4/gfx/image.h"
|
||||
@ -56,6 +57,7 @@ MapLoaders::MapLoaders() {
|
||||
(*this)[Map::DUNGEON] = new DngMapLoader();
|
||||
(*this)[Map::WORLD] = new WorldMapLoader();
|
||||
(*this)[Map::COMBAT] = new ConMapLoader();
|
||||
(*this)[Map::XML] = new XMLMapLoader();
|
||||
}
|
||||
|
||||
MapLoaders::~MapLoaders() {
|
||||
@ -130,6 +132,8 @@ bool MapLoader::isChunkCompressed(Map *map, int chunk) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
bool CityMapLoader::load(Map *map) {
|
||||
City *city = dynamic_cast<City *>(map);
|
||||
assert(city);
|
||||
@ -249,6 +253,8 @@ bool CityMapLoader::load(Map *map) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
bool ConMapLoader::load(Map *map) {
|
||||
int i;
|
||||
|
||||
@ -286,6 +292,8 @@ bool ConMapLoader::load(Map *map) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
bool DngMapLoader::load(Map *map) {
|
||||
Dungeon *dungeon = dynamic_cast<Dungeon *>(map);
|
||||
assert(dungeon);
|
||||
@ -372,6 +380,8 @@ bool DngMapLoader::load(Map *map) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
void DngMapLoader::initDungeonRoom(Dungeon *dng, int room) {
|
||||
dng->_roomMaps[room] = dynamic_cast<CombatMap *>(mapMgr->initMap(Map::COMBAT));
|
||||
|
||||
@ -385,6 +395,8 @@ void DngMapLoader::initDungeonRoom(Dungeon *dng, int room) {
|
||||
dng->_roomMaps[room]->_tileSet = g_tileSets->get("base");
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
bool WorldMapLoader::load(Map *map) {
|
||||
Common::File *world = u4fopen(map->_fname);
|
||||
if (!world)
|
||||
@ -395,8 +407,64 @@ bool WorldMapLoader::load(Map *map) {
|
||||
|
||||
u4fclose(world);
|
||||
|
||||
// Check for any tile overrides for the portals
|
||||
for (uint idx = 0; idx < map->_portals.size(); ++idx) {
|
||||
const Portal *p = map->_portals[idx];
|
||||
if (p->_tile != -1) {
|
||||
MapTile mt = map->translateFromRawTileIndex(p->_tile);
|
||||
map->_data[p->_coords.x + p->_coords.y * map->_width] = mt;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
bool XMLMapLoader::load(Map *map) {
|
||||
XMLMap *xmlMap = dynamic_cast<XMLMap *>(map);
|
||||
assert(xmlMap);
|
||||
Common::String text = xmlMap->_tilesText;
|
||||
text.trim();
|
||||
|
||||
// Allocate the space we need for the map data
|
||||
map->_data.clear();
|
||||
map->_data.resize(map->_width * map->_height);
|
||||
|
||||
// Split up the text lines
|
||||
Common::StringArray lines, cols;
|
||||
split(text, lines, '\n');
|
||||
assert(lines.size() == map->_height);
|
||||
|
||||
// Iterate through the lines
|
||||
for (uint y = 0; y < map->_height; ++y) {
|
||||
text = lines[y];
|
||||
text.trim();
|
||||
split(text, cols, ',');
|
||||
assert(cols.size() == map->_width);
|
||||
|
||||
for (uint x = 0; x < map->_width; ++x) {
|
||||
int id = atoi(cols[x].c_str());
|
||||
MapTile mt = map->translateFromRawTileIndex(id);
|
||||
map->_data[x + y * map->_width] = mt;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void XMLMapLoader::split(const Common::String &text, Common::StringArray &values, char c) {
|
||||
values.clear();
|
||||
|
||||
Common::String str = text;
|
||||
size_t pos;
|
||||
while ((pos = str.findFirstOf(c)) != Common::String::npos) {
|
||||
values.push_back(Common::String(str.c_str(), pos));
|
||||
str = Common::String(str.c_str() + pos + 1);
|
||||
}
|
||||
|
||||
values.push_back(str);
|
||||
}
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
|
@ -113,6 +113,16 @@ public:
|
||||
bool load(Map *map) override;
|
||||
};
|
||||
|
||||
class XMLMapLoader : public MapLoader {
|
||||
private:
|
||||
void split(const Common::String &text, Common::StringArray &values, char c);
|
||||
public:
|
||||
/**
|
||||
* Loads the data for the map from the provided Xml
|
||||
*/
|
||||
bool load(Map *map) override;
|
||||
};
|
||||
|
||||
class MapLoaders : public Std::map<Map::Type, MapLoader *, MapType_Hash> {
|
||||
public:
|
||||
/**
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "ultima/ultima4/map/shrine.h"
|
||||
#include "ultima/ultima4/map/tilemap.h"
|
||||
#include "ultima/ultima4/map/tileset.h"
|
||||
#include "ultima/ultima4/map/xml_map.h"
|
||||
#include "ultima/ultima4/core/types.h"
|
||||
#include "ultima/ultima4/filesys/u4file.h"
|
||||
#include "ultima/ultima4/core/config.h"
|
||||
@ -116,6 +117,10 @@ Map *MapMgr::initMap(Map::Type type) {
|
||||
map = new City();
|
||||
break;
|
||||
|
||||
case Map::XML:
|
||||
map = new XMLMap();
|
||||
break;
|
||||
|
||||
default:
|
||||
error("Error: invalid map type used");
|
||||
break;
|
||||
@ -149,7 +154,7 @@ void MapMgr::registerMap(Map *map) {
|
||||
|
||||
Map *MapMgr::initMapFromConf(const ConfigElement &mapConf) {
|
||||
Map *map;
|
||||
static const char *mapTypeEnumStrings[] = { "world", "city", "shrine", "combat", "dungeon", nullptr };
|
||||
static const char *mapTypeEnumStrings[] = { "world", "city", "shrine", "combat", "dungeon", "xml", nullptr };
|
||||
static const char *borderBehaviorEnumStrings[] = { "wrap", "exit", "fixed", nullptr };
|
||||
|
||||
map = initMap(static_cast<Map::Type>(mapConf.getEnum("type", mapTypeEnumStrings)));
|
||||
@ -208,6 +213,8 @@ Map *MapMgr::initMapFromConf(const ConfigElement &mapConf) {
|
||||
map->_compressedChunks.push_back(initCompressedChunkFromConf(*i));
|
||||
else if (i->getName() == "label")
|
||||
map->_labels.insert(initLabelFromConf(*i));
|
||||
else if (i->getName() == "tiles" && map->_type == Map::XML)
|
||||
static_cast<XMLMap *>(map)->_tilesText = i->getNode()->firstChild()->text();
|
||||
}
|
||||
|
||||
return map;
|
||||
@ -302,6 +309,10 @@ Portal *MapMgr::initPortalFromConf(const ConfigElement &portalConf) {
|
||||
|
||||
portal->_exitPortal = portalConf.getBool("exits");
|
||||
|
||||
// Used as a shortcut for specifying the display tile
|
||||
// for new/fan maps being added to the overworld
|
||||
portal->_tile = portalConf.exists("tile") ? portalConf.getInt("tile") : -1;
|
||||
|
||||
Std::vector<ConfigElement> children = portalConf.getChildren();
|
||||
for (Std::vector<ConfigElement>::iterator i = children.begin(); i != children.end(); i++) {
|
||||
if (i->getName() == "retroActiveDest") {
|
||||
@ -314,6 +325,7 @@ Portal *MapMgr::initPortalFromConf(const ConfigElement &portalConf) {
|
||||
portal->_retroActiveDest->_mapid = static_cast<MapId>(i->getInt("mapid"));
|
||||
}
|
||||
}
|
||||
|
||||
return portal;
|
||||
}
|
||||
|
||||
|
@ -99,6 +99,8 @@ class Shrine;
|
||||
#define MAP_SHORE_CON 53
|
||||
#define MAP_SHORSHIP_CON 54
|
||||
#define MAP_CAMP_DNG 55
|
||||
#define MAP_CASTLE_OF_LORD_BRITISH2 100
|
||||
#define MAP_SCUMMVM 101
|
||||
|
||||
/**
|
||||
* The map manager singleton that keeps track of all the maps.
|
||||
|
43
engines/ultima/ultima4/map/xml_map.h
Normal file
43
engines/ultima/ultima4/map/xml_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 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 ULTIMA4_MAP_XML_MAP_H
|
||||
#define ULTIMA4_MAP_XML_MAP_H
|
||||
|
||||
#include "ultima/ultima4/map/city.h"
|
||||
#include "ultima/shared/std/containers.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
class XMLMap : public City {
|
||||
public:
|
||||
Common::String _tilesText;
|
||||
public:
|
||||
XMLMap() : City() {}
|
||||
~XMLMap() override {};
|
||||
};
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user