mapeditor changes

master
niczkx 12 years ago
parent 8f492f7e06
commit 992cbf9d1d

@ -1,6 +1,6 @@
== MODULES == MODULES
game_shaders (with shader manager) game_shaders (with shader manager)
game_map (with save/load/options) game_map (with save/load/option)
game_minimap (with all tibia functionality) game_minimap (with all tibia functionality)
== NOTABLE FEATURES == NOTABLE FEATURES

@ -5,7 +5,7 @@
g_logger.setLogFile(g_resources.getWorkDir() .. g_app.getCompactName() .. ".log") g_logger.setLogFile(g_resources.getWorkDir() .. g_app.getCompactName() .. ".log")
-- print first terminal message -- print first terminal message
g_logger.info(g_app.getName() .. ' ' .. g_app.getVersion() .. ' rev ' .. g_app.getBuildRevision() .. ' (' .. g_app.getBuildCommit() .. ') built on ' .. g_app.getBuildDate()) g_logger.info(g_app.getName() .. ' ' .. g_app.getVersion() .. ' rev ' .. g_app.getBuildRevision() .. ' (' .. g_app.getBuildCommit() .. ') built on ' .. g_app.getBuildDate() .. ' for arch ' .. g_app.getBuildArch())
--add base folder to search path --add base folder to search path
g_resources.addToSearchPath(g_resources.getWorkDir()) g_resources.addToSearchPath(g_resources.getWorkDir())
@ -27,15 +27,15 @@ g_configs.load("/config.otml")
g_modules.discoverModules() g_modules.discoverModules()
-- core modules 0-99 -- core modules 0-99
g_modules.autoLoadModules(99); g_modules.autoLoadModules(99)
g_modules.ensureModuleLoaded("corelib") g_modules.ensureModuleLoaded("corelib")
-- client modules 100-499 -- client modules 100-499
g_modules.autoLoadModules(499); g_modules.autoLoadModules(499)
g_modules.ensureModuleLoaded("client") g_modules.ensureModuleLoaded("client")
-- game modules 500-999 -- game modules 500-999
g_modules.autoLoadModules(999); g_modules.autoLoadModules(999)
g_modules.ensureModuleLoaded("game") g_modules.ensureModuleLoaded("game")
-- addons 1000-9999 -- addons 1000-9999
@ -45,7 +45,3 @@ if g_resources.fileExists("/otclientrc.lua") then
dofile("/otclientrc.lua") dofile("/otclientrc.lua")
end end
g_things.loadOtb("/items.otb")
g_map.loadOtbm("/forgotten.otbm")

@ -71,6 +71,7 @@ public:
std::string getBuildRevision() { return BUILD_REVISION; } std::string getBuildRevision() { return BUILD_REVISION; }
std::string getBuildCommit() { return BUILD_COMMIT; } std::string getBuildCommit() { return BUILD_COMMIT; }
std::string getBuildType() { return BUILD_TYPE; } std::string getBuildType() { return BUILD_TYPE; }
std::string getBuildArch() { return BUILD_ARCH; }
std::string getStartupOptions() { return m_startupOptions; } std::string getStartupOptions() { return m_startupOptions; }
protected: protected:

@ -29,8 +29,8 @@
#define BUILD_COMPILER "gcc " __VERSION__ #define BUILD_COMPILER "gcc " __VERSION__
#define BUILD_DATE __DATE__ #define BUILD_DATE __DATE__
#ifndef BUILD_COMMIT #ifndef BUILD_COMMIT
#define BUILD_COMMIT "custom" #define BUILD_COMMIT "devel"
#endif #endif
#ifndef BUILD_REVISION #ifndef BUILD_REVISION
@ -41,6 +41,16 @@
#define BUILD_TYPE "unknown" #define BUILD_TYPE "unknown"
#endif #endif
#ifndef BUILD_ARCH
#if defined(__amd64) || defined(_M_X64)
#define BUILD_ARCH "x64"
#elif defined(__i386) || defined(_M_IX86) || defined(_X86_)
#define BUILD_ARCH "X86"
#else
#define BUILD_ARCH "unknown"
#endif
#endif
namespace Fw namespace Fw
{ {
constexpr float pi = 3.14159265; constexpr float pi = 3.14159265;
@ -207,7 +217,7 @@ namespace Fw
AnchorLeft, AnchorLeft,
AnchorRight, AnchorRight,
AnchorVerticalCenter, AnchorVerticalCenter,
AnchorHorizontalCenter, AnchorHorizontalCenter
}; };
enum FocusReason { enum FocusReason {

@ -59,6 +59,8 @@ public:
void addU32(uint32 v); void addU32(uint32 v);
void addU64(uint64 v); void addU64(uint64 v);
void addString(const std::string& v); void addString(const std::string& v);
void startNode(uint8 nodeType) { addU8(0xFE); addU8(nodeType); }
void endNode() { addU8(0xFF); }
FileStreamPtr asFileStream() { return std::static_pointer_cast<FileStream>(shared_from_this()); } FileStreamPtr asFileStream() { return std::static_pointer_cast<FileStream>(shared_from_this()); }

@ -501,6 +501,7 @@ void Application::registerLuaFunctions()
g_lua.bindSingletonFunction("g_app", "getBuildRevision", &Application::getBuildRevision, &g_app); g_lua.bindSingletonFunction("g_app", "getBuildRevision", &Application::getBuildRevision, &g_app);
g_lua.bindSingletonFunction("g_app", "getBuildCommit", &Application::getBuildCommit, &g_app); g_lua.bindSingletonFunction("g_app", "getBuildCommit", &Application::getBuildCommit, &g_app);
g_lua.bindSingletonFunction("g_app", "getBuildType", &Application::getBuildType, &g_app); g_lua.bindSingletonFunction("g_app", "getBuildType", &Application::getBuildType, &g_app);
g_lua.bindSingletonFunction("g_app", "getBuildArch", &Application::getBuildArch, &g_app);
g_lua.bindSingletonFunction("g_app", "exit", &Application::exit, &g_app); g_lua.bindSingletonFunction("g_app", "exit", &Application::exit, &g_app);
// ConfigManager // ConfigManager

@ -64,7 +64,7 @@
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
// tiny XML // tiny XML
#define TIXML_USE_STL #define TIXML_USE_STL // use std::string's instead
#include <framework/thirdparty/tinyxml.h> #include <framework/thirdparty/tinyxml.h>
#endif #endif

@ -26,6 +26,9 @@
#include "thing.h" #include "thing.h"
#include "tile.h" #include "tile.h"
#include "shadermanager.h" #include "shadermanager.h"
#include "container.h"
#include "map.h"
#include "houses.h"
#include <framework/core/clock.h> #include <framework/core/clock.h>
#include <framework/core/eventdispatcher.h> #include <framework/core/eventdispatcher.h>
@ -206,12 +209,12 @@ bool Item::isValid()
void Item::unserializeItem(const BinaryTreePtr &in) void Item::unserializeItem(const BinaryTreePtr &in)
{ {
// Yet another TODO.
while (in->canRead()) { while (in->canRead()) {
uint8 attrType = in->getU8(); uint8 attrType = in->getU8();
if (attrType == 0) if (attrType == 0)
break; break;
// fugly switch yes?
switch ((AttrTypes_t)attrType) { switch ((AttrTypes_t)attrType) {
case ATTR_COUNT: case ATTR_COUNT:
setSubType(in->getU8()); setSubType(in->getU8());
@ -228,9 +231,31 @@ void Item::unserializeItem(const BinaryTreePtr &in)
case ATTR_NAME: case ATTR_NAME:
setName(in->getString()); setName(in->getString());
break; break;
case ATTR_ARTICLE: // ? case ATTR_TEXT:
case ATTR_WRITTENBY: setText(in->getString());
break;
case ATTR_DESC: case ATTR_DESC:
m_description = in->getString();
break;
case ATTR_CONTAINER_ITEMS:
m_isContainer = true;
in->skip(4);
break;
case ATTR_HOUSEDOORID:
m_isDoor = true;
m_doorId = in->getU8();
break;
case ATTR_DEPOT_ID:
m_depotId = in->getU16();
break;
case ATTR_TELE_DEST: {
m_teleportDestination.x = in->getU16();
m_teleportDestination.y = in->getU16();
m_teleportDestination.z = in->getU8();
break;
}
case ATTR_ARTICLE:
case ATTR_WRITTENBY:
in->getString(); in->getString();
break; break;
case ATTR_ATTACK: case ATTR_ATTACK:
@ -244,28 +269,15 @@ void Item::unserializeItem(const BinaryTreePtr &in)
case ATTR_WRITTENDATE: case ATTR_WRITTENDATE:
case ATTR_SLEEPERGUID: case ATTR_SLEEPERGUID:
case ATTR_SLEEPSTART: case ATTR_SLEEPSTART:
case ATTR_CONTAINER_ITEMS:
case ATTR_ATTRIBUTE_MAP: case ATTR_ATTRIBUTE_MAP:
in->skip(4); in->skip(4);
break; break;
case ATTR_SCRIPTPROTECTED: case ATTR_SCRIPTPROTECTED:
case ATTR_DUALWIELD: case ATTR_DUALWIELD:
case ATTR_DECAYING_STATE: case ATTR_DECAYING_STATE:
case ATTR_HOUSEDOORID:
case ATTR_RUNE_CHARGES: case ATTR_RUNE_CHARGES:
in->skip(1); in->skip(1);
break; break;
case ATTR_TEXT:
setText(in->getString());
break;
case ATTR_DEPOT_ID:
in->skip(2); // trolol
break;
case ATTR_TELE_DEST:
{
Position pos(in->getU16(), in->getU16(), in->getU8());
break;
}
default: default:
stdext::throw_exception(stdext::format("invalid item attribute %d", (int)attrType)); stdext::throw_exception(stdext::format("invalid item attribute %d", (int)attrType));
} }

@ -27,7 +27,8 @@
#include "thing.h" #include "thing.h"
#include "thingtypeotb.h" #include "thingtypeotb.h"
enum AttrTypes_t { enum AttrTypes_t
{
ATTR_END = 0, ATTR_END = 0,
ATTR_TILE_FLAGS = 3, ATTR_TILE_FLAGS = 3,
ATTR_ACTION_ID = 4, ATTR_ACTION_ID = 4,
@ -82,6 +83,7 @@ public:
void setSubType(int subType) { m_countOrSubType = subType; } void setSubType(int subType) { m_countOrSubType = subType; }
void setActionId(int actionId) { m_actionId = actionId; } void setActionId(int actionId) { m_actionId = actionId; }
void setUniqueId(int uniqueId) { m_uniqueId = uniqueId; } void setUniqueId(int uniqueId) { m_uniqueId = uniqueId; }
void setDoorId(int doorId) { m_doorId = doorId; }
void setName(const std::string &name) { m_name = name; } void setName(const std::string &name) { m_name = name; }
void setText(const std::string &text) { m_text = text; } void setText(const std::string &text) { m_text = text; }
void setDescription(const std::string &description) { m_description = description; } void setDescription(const std::string &description) { m_description = description; }
@ -91,6 +93,7 @@ public:
int getCount() { return m_countOrSubType; } int getCount() { return m_countOrSubType; }
uint32 getId() { return m_id; } uint32 getId() { return m_id; }
std::string getName() { return m_name; } std::string getName() { return m_name; }
uint8 getDoorId() { return m_doorId; }
bool isValid(); bool isValid();
ItemPtr asItem() { return std::static_pointer_cast<Item>(shared_from_this()); } ItemPtr asItem() { return std::static_pointer_cast<Item>(shared_from_this()); }
@ -98,14 +101,22 @@ public:
void unserializeItem(const BinaryTreePtr &in); void unserializeItem(const BinaryTreePtr &in);
bool isMoveable(); bool isMoveable();
bool isContainer() { return m_isContainer; }
bool isDoor() { return m_isDoor; }
private: private:
uint16 m_id; uint16 m_id;
uint8 m_countOrSubType; uint8 m_countOrSubType;
uint32 m_actionId, m_uniqueId; uint32 m_actionId, m_uniqueId;
uint16 m_depotId;
uint8 m_doorId;
Boolean<false> m_isContainer;
Boolean<false> m_isDoor;
std::string m_name, m_text, m_description; std::string m_name, m_text, m_description;
PainterShaderProgramPtr m_shaderProgram; PainterShaderProgramPtr m_shaderProgram;
ThingTypeOtbPtr m_otbType; ThingTypeOtbPtr m_otbType;
Position m_teleportDestination;
}; };
#endif #endif

@ -27,14 +27,13 @@
#include "item.h" #include "item.h"
#include "missile.h" #include "missile.h"
#include "statictext.h" #include "statictext.h"
#include "houses.h"
#include "towns.h"
#include <framework/core/eventdispatcher.h> #include <framework/core/eventdispatcher.h>
#include "mapview.h" #include "mapview.h"
#include <framework/core/resourcemanager.h> #include <framework/core/resourcemanager.h>
#include <framework/core/filestream.h> #include <framework/core/filestream.h>
#include <framework/core/binarytree.h> #include <framework/core/binarytree.h>
#include <framework/application.h>
Map g_map; Map g_map;
@ -61,7 +60,7 @@ void Map::notificateTileUpdateToMapViews(const Position& pos)
mapView->onTileUpdate(pos); mapView->onTileUpdate(pos);
} }
void Map::loadOtbm(const std::string& fileName, bool /*display*/) void Map::loadOtbm(const std::string& fileName)
{ {
FileStreamPtr fin = g_resources.openFile(fileName); FileStreamPtr fin = g_resources.openFile(fileName);
if (!fin) if (!fin)
@ -75,47 +74,45 @@ void Map::loadOtbm(const std::string& fileName, bool /*display*/)
stdext::throw_exception("Unknown file version detected"); stdext::throw_exception("Unknown file version detected");
BinaryTreePtr root = fin->getBinaryTree(); BinaryTreePtr root = fin->getBinaryTree();
if (root->getU8() != 0) if (root->getU8())
stdext::throw_exception("could not read root property!"); stdext::throw_exception("could not read root property!");
uint32 headerVersion = root->getU32(); uint32 headerVersion = root->getU32();
if (!headerVersion || headerVersion > 3) if (!headerVersion || headerVersion > 3)
stdext::throw_exception(stdext::format("Unknown OTBM version detected: %u.", headerVersion)); stdext::throw_exception(stdext::format("Unknown OTBM version detected: %u.", headerVersion));
uint16 w = root->getU16(), h = root->getU16(); m_width = root->getU16();
dump << "Map size: " << w << "x" << h; m_height = root->getU16();
dump << "Map size: " << m_width << "x" << m_height;
uint32 headerMajorItems = root->getU8(); uint32 headerMajorItems = root->getU8();
if (headerMajorItems < 3) if (headerMajorItems < 3) {
stdext::throw_exception(stdext::format("This map needs to be upgraded. read %d what it's supposed to be: %u", stdext::throw_exception(stdext::format("This map needs to be upgraded. read %d what it's supposed to be: %u",
headerMajorItems, g_things.getOtbMajorVersion())); headerMajorItems, g_things.getOtbMajorVersion()));
}
if (headerMajorItems > g_things.getOtbMajorVersion()) if (headerMajorItems > g_things.getOtbMajorVersion()) {
stdext::throw_exception(stdext::format("This map was saved with different OTB version. read %d what it's supposed to be: %d", stdext::throw_exception(stdext::format("This map was saved with different OTB version. read %d what it's supposed to be: %d",
headerMajorItems, g_things.getOtbMajorVersion())); headerMajorItems, g_things.getOtbMajorVersion()));
}
root->skip(3); root->skip(3);
uint32 headerMinorItems = root->getU32(); uint32 headerMinorItems = root->getU32();
if (headerMinorItems > g_things.getOtbMinorVersion()) if (headerMinorItems > g_things.getOtbMinorVersion()) {
g_logger.warning(stdext::format("This map needs an updated OTB. read %d what it's supposed to be: %d", g_logger.warning(stdext::format("This map needs an updated OTB. read %d what it's supposed to be: %d",
headerMinorItems, g_things.getOtbMinorVersion())); headerMinorItems, g_things.getOtbMinorVersion()));
}
BinaryTreePtr node = root->getChildren()[0]; BinaryTreePtr node = root->getChildren()[0];
if (node->getU8() != OTBM_MAP_DATA) if (node->getU8() != OTBM_MAP_DATA)
stdext::throw_exception("Could not read root data node"); stdext::throw_exception("Could not read root data node");
Boolean<true> first;
while (node->canRead()) { while (node->canRead()) {
uint8 attribute = node->getU8(); uint8 attribute = node->getU8();
std::string tmp = node->getString(); std::string tmp = node->getString();
switch (attribute) { switch (attribute) {
case OTBM_ATTR_DESCRIPTION: case OTBM_ATTR_DESCRIPTION:
if (first) { m_description += tmp + "\n";
first = false;
m_description = tmp;
} else {
m_description += "\n" + tmp;
}
break; break;
case OTBM_ATTR_SPAWN_FILE: case OTBM_ATTR_SPAWN_FILE:
m_spawnFile = fileName.substr(0, fileName.rfind('/') + 1) + tmp; m_spawnFile = fileName.substr(0, fileName.rfind('/') + 1) + tmp;
@ -136,110 +133,131 @@ void Map::loadOtbm(const std::string& fileName, bool /*display*/)
for (const BinaryTreePtr &nodeTile : nodeMapData->getChildren()) { for (const BinaryTreePtr &nodeTile : nodeMapData->getChildren()) {
uint8 type = nodeTile->getU8(); uint8 type = nodeTile->getU8();
if (type == OTBM_TILE || type == OTBM_HOUSETILE) { if (type != OTBM_TILE && type != OTBM_HOUSETILE)
TilePtr tile = nullptr; stdext::throw_exception(stdext::format("invalid node tile type %d", (int)type));
ItemPtr ground = nullptr;
HousePtr house = nullptr; TilePtr tile = nullptr;
uint32 flags = 0; ItemPtr ground = nullptr;
HousePtr house = nullptr;
uint16 px = baseX + nodeTile->getU8(), py = baseY + nodeTile->getU8(); uint32 flags = TILESTATE_NONE;
Position pos(px, py, pz);
uint16 px = baseX + nodeTile->getU8(), py = baseY + nodeTile->getU8();
if (type == OTBM_HOUSETILE) { Position pos(px, py, pz);
uint32 hId = nodeTile->getU32();
tile = createTile(pos); if (type == OTBM_HOUSETILE) {
if (!(house = g_houses.getHouse(hId))) uint32 hId = nodeTile->getU32();
house = HousePtr(new House(hId)); tile = createTile(pos);
house->setTile(tile); if (!(house = m_houses.getHouse(hId))) {
house = HousePtr(new House(hId));
m_houses.addHouse(house);
} }
house->setTile(tile);
}
while (nodeTile->canRead()) { while (nodeTile->canRead()) {
uint8 tileAttr = nodeTile->getU8(); uint8 tileAttr = nodeTile->getU8();
switch (tileAttr) { switch (tileAttr) {
case OTBM_ATTR_TILE_FLAGS: { case OTBM_ATTR_TILE_FLAGS: {
uint32 _flags = nodeTile->getU32(); uint32 _flags = nodeTile->getU32();
if ((_flags & TILESTATE_PROTECTIONZONE) == TILESTATE_PROTECTIONZONE) if ((_flags & TILESTATE_PROTECTIONZONE) == TILESTATE_PROTECTIONZONE)
flags |= TILESTATE_PROTECTIONZONE; flags |= TILESTATE_PROTECTIONZONE;
else if ((_flags & TILESTATE_OPTIONALZONE) == TILESTATE_OPTIONALZONE) else if ((_flags & TILESTATE_OPTIONALZONE) == TILESTATE_OPTIONALZONE)
flags |= TILESTATE_OPTIONALZONE; flags |= TILESTATE_OPTIONALZONE;
else if ((_flags & TILESTATE_HARDCOREZONE) == TILESTATE_HARDCOREZONE) else if ((_flags & TILESTATE_HARDCOREZONE) == TILESTATE_HARDCOREZONE)
flags |= TILESTATE_HARDCOREZONE; flags |= TILESTATE_HARDCOREZONE;
if ((_flags & TILESTATE_NOLOGOUT) == TILESTATE_NOLOGOUT) if ((_flags & TILESTATE_NOLOGOUT) == TILESTATE_NOLOGOUT)
flags |= TILESTATE_NOLOGOUT; flags |= TILESTATE_NOLOGOUT;
if ((_flags & TILESTATE_REFRESH) == TILESTATE_REFRESH) if ((_flags & TILESTATE_REFRESH) == TILESTATE_REFRESH)
flags |= TILESTATE_REFRESH; flags |= TILESTATE_REFRESH;
break; break;
}
case OTBM_ATTR_ITEM: {
ItemPtr item = Item::createFromOtb(nodeTile->getU16());
if (tile)
tile->addThing(item);
else if (item->isGround())
ground = item;
else {
tile = createTile(pos, ground);
tile->addThing(item);
}
break;
}
default:
stdext::throw_exception(stdext::format("invalid tile attribute %d at pos %d, %d, %d",
(int)tileAttr, px, py, pz));
} }
case OTBM_ATTR_ITEM: {
ItemPtr item = Item::createFromOtb(nodeTile->getU16());
if (tile)
addThing(item, pos, 255);
else if (item->isGround())
ground = item;
else
tile = createTileEx(pos, ground, item);
break;
}
default:
stdext::throw_exception(stdext::format("invalid tile attribute %d at pos %d, %d, %d",
(int)tileAttr, px, py, pz));
} }
}
for (const BinaryTreePtr &nodeItem : nodeTile->getChildren()) { for (const BinaryTreePtr &nodeItem : nodeTile->getChildren()) {
if (nodeItem->getU8() == OTBM_ITEM) { if (nodeItem->getU8() != OTBM_ITEM)
ItemPtr item = Item::createFromOtb(nodeItem->getU16()); stdext::throw_exception("invalid item node");
item->unserializeItem(nodeItem);
if (house && item->isMoveable()) { ItemPtr item = Item::createFromOtb(nodeItem->getU16());
g_logger.warning(stdext::format("Moveable item found in house: %d at pos %d %d %d", item->getId(), item->unserializeItem(nodeItem);
px, py, pz)); if (item->isContainer()) {
item = nullptr; // This is a temporary way for reading container items.
} else if (tile) { MapContainerPtr mapContainer(new MapContainer);
tile->addThing(item); for (const BinaryTreePtr &insideItem : nodeItem->getChildren()) {
} else if (item->isGround()) { if (insideItem->getU8() != OTBM_ITEM)
ground = item; stdext::throw_exception("invalid container item node");
} else {
tile = createTile(pos, ground); ItemPtr newItem = Item::createFromOtb(insideItem->getU16());
tile->addThing(item); newItem->unserializeItem(insideItem);
} mapContainer->add(newItem);
} else }
stdext::throw_exception("Unknown item node"); m_containers.push_back(mapContainer);
} }
if (!tile) if (house) {
tile = createTile(pos, ground); if (item->isMoveable()) {
g_logger.warning(stdext::format("Movable item found in house: %d at pos %d %d %d - escaping...", item->getId(),
px, py, pz));
item = nullptr;
} else if (item->isDoor())
house->addDoor(item->getDoorId(), pos);
} else if (tile)
addThing(item, pos, 255);
else if (item->isGround())
ground = item;
else
tile = createTileEx(pos, ground, item);
}
tile->setFlags((tileflags_t)flags); if (!tile)
} else tile = createTileEx(pos, ground);
stdext::throw_exception(stdext::format("Unknown tile node type %d", type));
tile->setFlags((tileflags_t)flags);
} }
} else if (mapDataType == OTBM_TOWNS) { } else if (mapDataType == OTBM_TOWNS) {
TownPtr town = nullptr; TownPtr town = nullptr;
for (const BinaryTreePtr &nodeTown : nodeMapData->getChildren()) { for (const BinaryTreePtr &nodeTown : nodeMapData->getChildren()) {
if (nodeTown->getU8() == OTBM_TOWN) { if (nodeTown->getU8() != OTBM_TOWN)
uint32 townId = nodeTown->getU32(); stdext::throw_exception("invalid town node.");
std::string townName = nodeTown->getString();
Position townCoords(nodeTown->getU16(), nodeTown->getU16(), nodeTown->getU8()); uint32 townId = nodeTown->getU32();
if (!(town = g_towns.getTown(townId))) std::string townName = nodeTown->getString();
town = TownPtr(new Town(townId, townName, townCoords)); Position townCoords(nodeTown->getU16(), nodeTown->getU16(), nodeTown->getU8());
} else if (!(town = m_towns.getTown(townId))) {
stdext::throw_exception("invalid town node"); town = TownPtr(new Town(townId, townName, townCoords));
m_towns.addTown(town);
} else {
// override data
town->setName(townName);
town->setPos(townCoords);
town->setId(townId);
}
} }
} else if (mapDataType == OTBM_WAYPOINTS && headerVersion > 1) { } else if (mapDataType == OTBM_WAYPOINTS && headerVersion > 1) {
for (const BinaryTreePtr &nodeWaypoint : nodeMapData->getChildren()) { for (const BinaryTreePtr &nodeWaypoint : nodeMapData->getChildren()) {
if (nodeWaypoint->getU8() == OTBM_WAYPOINT) { if (nodeWaypoint->getU8() != OTBM_WAYPOINT)
std::string name = nodeWaypoint->getString(); stdext::throw_exception("invalid waypoint node.");
Position waypointPos(nodeWaypoint->getU16(), nodeWaypoint->getU16(), nodeWaypoint->getU8());
if (waypointPos.isValid() && !name.empty()) std::string name = nodeWaypoint->getString();
m_waypoints.insert(std::make_pair(waypointPos, name)); Position waypointPos(nodeWaypoint->getU16(), nodeWaypoint->getU16(), nodeWaypoint->getU8());
if (waypointPos.isValid() && !name.empty() && m_waypoints.find(waypointPos) == m_waypoints.end())
} else m_waypoints.insert(std::make_pair(waypointPos, name));
stdext::throw_exception("invalid waypoint node");
} }
} else } else
stdext::throw_exception("Unknown map data node"); stdext::throw_exception("Unknown map data node");
@ -250,6 +268,115 @@ void Map::loadOtbm(const std::string& fileName, bool /*display*/)
/// TODO read XML Stuff (houses & spawns). /// TODO read XML Stuff (houses & spawns).
} }
void Map::saveOtbm(const std::string &fileName)
{
// TODO: Continue sleepy work.
#if 0
/// TODO: Use binary trees for this
FileStreamPtr fin = g_resources.openFile(fileName);
if(!fin)
stdext::throw_exception(stdext::format("failed to open file '%s'", fileName));
std::string dir;
if (fileName.find_last_of('/') <= 0)
dir = g_resources.getWorkDir();
else
dir = fileName.substr(0, fileName.find_last_of('/'));
if (m_houseFile.empty())
m_houseFile = "houses.xml";
if (m_spawnFile.empty())
m_spawnFile = "spawns.xml";
#if 0
if (!m_houses->save(dir + "/" + m_houseFile))
;
if (!m_spawns->save(dir + "/" + m_spawnFile))
;
#endif
uint32 ver;
if (g_things.getOtbMajorVersion() < 2)
ver =0;
else if (g_things.getOtbMajorVersion() < 10)
ver = 1;
else
ver = 2;
fin->addU32(0x00); // file version
{
fin->startNode(0x00); // root
fin->addU32(ver);
fin->addU16(m_width); // some random width.
fin->addU16(m_height); // some random height.
fin->addU32(g_things.getOtbMajorVersion());
fin->addU32(g_things.getOtbMinorVersion());
fin->startNode(OTBM_MAP_DATA); // map data node
{
// own description.
fin->addU8(OTBM_ATTR_DESCRIPTION);
fin->addString(m_description);
// special one
fin->addU8(OTBM_ATTR_DESCRIPTION);
fin->addString(stdext::format("Saved with %s v%d", g_app.getName(), stdext::unsafe_cast<int>(g_app.getVersion())));
// spawn file.
fin->addU8(OTBM_ATTR_SPAWN_FILE);
fin->addString(m_spawnFile);
// house file.
if (ver > 1) {
fin->addU8(OTBM_ATTR_HOUSE_FILE);
fin->addString(m_houseFile);
}
Position pos(-1, -1, -1);
Boolean<true> first;
for (auto& pair : m_tiles) {
TilePtr tile = pair.second;
if(!tile || tile->isEmpty())
continue;
Position tilePos = pair.first;
if (tilePos.x < pos.x || tilePos.x >= pos.x + 256 ||
tilePos.y < pos.y || tilePos.y >= pos.y + 256 ||
tilePos.z != pos.z) {
if (!first)
fin->endNode();
pos.x = tilePos.x & 0xFF00;
pos.y = tilePos.y & 0xFF00;
pos.z = tilePos.z;
fin->addU16(pos.x);
fin->addU16(pos.y);
fin->addU8(pos.z);
}
// TODO: hOUSES.
fin->startNode(OTBM_TILE);
fin->addU8(tilePos.x);
fin->addU8(tilePos.y);
#if 0
// TODO: hOUSES again.
if (is house tile)
add u32 house id...;
#endif
if (tile->flags()) {
fin->addU8(OTBM_ATTR_TILE_FLAGS);
fin->addU32(tile->flags());
}
}
}
}
#endif
}
bool Map::loadOtcm(const std::string& fileName) bool Map::loadOtcm(const std::string& fileName)
{ {
try { try {
@ -393,6 +520,10 @@ void Map::clean()
cleanDynamicThings(); cleanDynamicThings();
m_tiles.clear(); m_tiles.clear();
m_waypoints.clear(); m_waypoints.clear();
// This is a fix to a segfault on exit.
m_towns.clear();
m_houses.clear();
} }
void Map::cleanDynamicThings() void Map::cleanDynamicThings()
@ -514,12 +645,20 @@ bool Map::removeThingByPos(const Position& pos, int stackPos)
return false; return false;
} }
TilePtr Map::createTile(const Position& pos, const ItemPtr &g) template <typename... Items>
TilePtr Map::createTileEx(const Position& pos, const Items&... items)
{ {
TilePtr tile = TilePtr(new Tile(pos)); TilePtr tile = getOrCreateTile(pos);
if (g) auto vec = {items...};
tile->addThing(g); for (auto it : vec)
addThing(it, pos, 255);
return tile;
}
TilePtr Map::createTile(const Position& pos)
{
TilePtr tile = TilePtr(new Tile(pos));
m_tiles[pos] = tile; m_tiles[pos] = tile;
return tile; return tile;
} }

@ -24,6 +24,8 @@
#define MAP_H #define MAP_H
#include "creature.h" #include "creature.h"
#include "houses.h"
#include "towns.h"
#include "animatedtext.h" #include "animatedtext.h"
#include <framework/core/clock.h> #include <framework/core/clock.h>
@ -80,6 +82,23 @@ enum {
OTCM_VERSION = 1 OTCM_VERSION = 1
}; };
/// Temporary way for reading container items
struct MapContainer {
private:
std::vector<ItemPtr> m_items;
public:
void add(const ItemPtr& item) { m_items.push_back(item); }
ItemPtr operator[](uint idx) { return getItem(idx); }
ItemPtr getItem(int index) {
if (index < 0 || index > (int)m_items.size())
return nullptr;
return m_items[index];
}
};
typedef std::shared_ptr<MapContainer> MapContainerPtr;
//@bindsingleton g_map //@bindsingleton g_map
class Map class Map
{ {
@ -93,8 +112,8 @@ public:
bool loadOtcm(const std::string& fileName); bool loadOtcm(const std::string& fileName);
void saveOtcm(const std::string& fileName); void saveOtcm(const std::string& fileName);
void loadOtbm(const std::string& fileName, bool display = false/* temporary*/); void loadOtbm(const std::string& fileName);
//void saveOtbm(const std::string& fileName); void saveOtbm(const std::string& fileName);
void clean(); void clean();
void cleanDynamicThings(); void cleanDynamicThings();
@ -106,7 +125,9 @@ public:
bool removeThingByPos(const Position& pos, int stackPos); bool removeThingByPos(const Position& pos, int stackPos);
// tile related // tile related
TilePtr createTile(const Position& pos, const ItemPtr &g = nullptr); template <typename... Items>
TilePtr createTileEx(const Position& pos, const Items&... items);
TilePtr createTile(const Position& pos);
const TilePtr& getTile(const Position& pos); const TilePtr& getTile(const Position& pos);
TilePtr getOrCreateTile(const Position& pos); TilePtr getOrCreateTile(const Position& pos);
void cleanTile(const Position& pos); void cleanTile(const Position& pos);
@ -120,6 +141,10 @@ public:
std::vector<CreaturePtr> getSpectatorsInRange(const Position& centerPos, bool multiFloor, int xRange, int yRange); std::vector<CreaturePtr> getSpectatorsInRange(const Position& centerPos, bool multiFloor, int xRange, int yRange);
std::vector<CreaturePtr> getSpectatorsInRangeEx(const Position& centerPos, bool multiFloor, int minXRange, int maxXRange, int minYRange, int maxYRange); std::vector<CreaturePtr> getSpectatorsInRangeEx(const Position& centerPos, bool multiFloor, int minXRange, int maxXRange, int minYRange, int maxYRange);
// town/house related
TownPtr getTown(uint32 tid) { return m_towns.getTown(tid); }
HousePtr getHouse(uint32 hid) { return m_houses.getHouse(hid); }
void setLight(const Light& light) { m_light = light; } void setLight(const Light& light) { m_light = light; }
void setCentralPosition(const Position& centralPosition); void setCentralPosition(const Position& centralPosition);
@ -147,11 +172,17 @@ private:
std::vector<StaticTextPtr> m_staticTexts; std::vector<StaticTextPtr> m_staticTexts;
std::vector<MapViewPtr> m_mapViews; std::vector<MapViewPtr> m_mapViews;
std::unordered_map<Position, std::string, PositionHasher> m_waypoints; std::unordered_map<Position, std::string, PositionHasher> m_waypoints;
std::vector<MapContainerPtr> m_containers;
Light m_light; Light m_light;
Position m_centralPosition; Position m_centralPosition;
std::string m_description, m_spawnFile, m_houseFile; std::string m_description, m_spawnFile, m_houseFile;
Houses m_houses;
Towns m_towns;
uint16 m_width, m_height;
}; };
extern Map g_map; extern Map g_map;

@ -87,151 +87,89 @@ bool ThingTypeManager::loadDat(const std::string& file)
} }
} }
bool ThingTypeManager::loadOtb(const std::string& file) void ThingTypeManager::loadOtb(const std::string& file)
{ {
try { FileStreamPtr fin = g_resources.openFile(file);
FileStreamPtr fin = g_resources.openFile(file);
uint signature = fin->getU32(); uint signature = fin->getU32();
if(signature != 0) if(signature != 0)
stdext::throw_exception("invalid otb file"); stdext::throw_exception("invalid otb file");
BinaryTreePtr root = fin->getBinaryTree(); BinaryTreePtr root = fin->getBinaryTree();
signature = root->getU32(); signature = root->getU32();
if(signature != 0) if(signature != 0)
stdext::throw_exception("invalid otb file"); stdext::throw_exception("invalid otb file");
root->getU32(); // flags root->getU32(); // flags
m_otbMajorVersion = root->getU32(); m_otbMajorVersion = root->getU32();
m_otbMinorVersion = root->getU32(); m_otbMinorVersion = root->getU32();
root->getU32(); // build number root->getU32(); // build number
root->skip(128); // description root->skip(128); // description
m_otbTypes.resize(root->getChildren().size(), m_nullOtbType);
for(const BinaryTreePtr& node : root->getChildren()) {
ThingTypeOtbPtr otbType(new ThingTypeOtb);
otbType->unserialize(node);
addOtbType(otbType);
}
m_otbLoaded = true; m_otbTypes.resize(root->getChildren().size(), m_nullOtbType);
return true; for(const BinaryTreePtr& node : root->getChildren()) {
} catch(stdext::exception& e) { ThingTypeOtbPtr otbType(new ThingTypeOtb);
g_logger.error(stdext::format("failed to load otb '%s': %s", file, e.what())); otbType->unserialize(node);
return false; addOtbType(otbType);
} }
m_otbLoaded = true;
} }
bool ThingTypeManager::loadXml(const std::string& file) void ThingTypeManager::loadXml(const std::string& file)
{ {
/* TiXmlDocument doc(file.c_str());
try { if (!doc.LoadFile())
TiXmlDocument doc(file.c_str()); stdext::throw_exception(stdext::format("failed to load xml '%s'", file));
if (!doc.LoadFile()) {
g_logger.error(stdext::format("failed to load xml '%s'", file)); TiXmlElement* root = doc.FirstChildElement();
return false; if (!root || root->ValueTStr() != "items")
} stdext::throw_exception("invalid root tag name");
TiXmlElement* root = doc.FirstChildElement(); ThingTypeOtbPtr otbType = nullptr;
if (!root) { for (TiXmlElement *element = root->FirstChildElement(); element; element = element->NextSiblingElement()) {
g_logger.error("invalid xml root"); if (element->ValueTStr() != "item")
return false; continue;
}
std::string name = element->Attribute("id");
if (root->ValueTStr() != "items") { if (name.empty())
g_logger.error("invalid xml tag name, should be 'items'"); continue;
return false;
} uint16 id = stdext::unsafe_cast<uint16>(element->Attribute("id"));
if (!(otbType = getOtbType(id))) {
for (TiXmlElement *element = root->FirstChildElement(); element; element = element->NextSiblingElement()) { // try reading fromId toId
if (element->ValueTStr() != "item") uint16 from = stdext::unsafe_cast<uint16>(element->Attribute("fromId"));
continue; uint16 to = stdext::unsafe_cast<uint16>(element->Attribute("toid"));
std::string name = element->Attribute("id"); for (uint16 __id = from; __id < to; ++__id) {
if (name.empty()) if (!(otbType = getOtbType(__id)))
continue;
uint16 id = stdext::unsafe_cast<uint16>(element->Attribute("id"));
uint16 idEx = 0;
if (!id) {
bool found = false;
// fallback into reading fromid and toid
uint16 fromid = stdext::unsafe_cast<uint16>(element->Attribute("fromid"));
uint16 toid = stdext::unsafe_cast<uint16>(element->Attribute("toid"));
ThingTypeOtbPtr iType;
for (int __id = fromid; __id < toid; ++__id) {
if (!(iType = getType(__id)))
continue;
iType->name = name;
idEx = iType->id == fromid ? fromid : toid;
found = true;
}
if (!found)
continue; continue;
}
ThingTypeOtbPtr otbType = getType(id); otbType->setHasRange();
if (!otbType) { otbType->setFromServerId(from);
otbType = ThingTypeOtbPtr(new ItemData); otbType->setToServerId(to);
otbType->id = idEx ? idEx : id; break;
otbType->name = name;
addType(otbType->id, otbType);
} }
otbType->name = name; // perform last check
if (!otbType) {
for (TiXmlElement *attr = element->FirstChildElement(); attr; attr = attr->NextSiblingElement()) { stdext::throw_exception(stdext::format("failed to find item with server id %d - tried reading fromid to id",
if (attr->ValueTStr() != "attribute") id));
continue;
std::string key = attr->Attribute("key");
std::string value = attr->Attribute("value");
if (key == "type") {
if (value == "magicfield")
otbType->category = IsMagicField;
else if (value == "key")
otbType->category = IsKey;
else if (value == "depot")
otbType->isDepot = true;
else if (value == "teleport")
otbType->category = IsTeleport;
else if (value == "bed")
otbType->isBed = true;
else if (value == "door")
otbType->category = IsDoor;
} else if (key == "name") {
otbType->name = value;
} else if (key == "description") {
otbType->description = value;
} else if (key == "weight") {
otbType->weight = stdext::unsafe_cast<double>(stdext::unsafe_cast<double>(value) / 100.f);
} else if (key == "containerSize") {
int containerSize = stdext::unsafe_cast<int>(value);
if (containerSize)
otbType->containerSize = containerSize;
otbType->category = IsContainer;
} else if (key == "writeable") {
if (!value.empty())
otbType->category = IsWritable;
} else if (key == "maxTextLen") {
otbType->maxTextLength = stdext::unsafe_cast<int>(value);
} else if (key == "charges") {
otbType->charges = stdext::unsafe_cast<int>(value);
}
} }
} }
doc.Clear(); for (TiXmlElement *attr = element->FirstChildElement(); attr; attr = attr->NextSiblingElement()) {
} catch(stdext::exception& e) { if (attr->ValueTStr() != "attribute")
continue;
otbType->unserializeXML(attr);
}
} }
return true;
*/ doc.Clear();
return false; m_xmlLoaded = true;
} }
void ThingTypeManager::addOtbType(const ThingTypeOtbPtr& otbType) void ThingTypeManager::addOtbType(const ThingTypeOtbPtr& otbType)

@ -36,8 +36,8 @@ public:
void terminate(); void terminate();
bool loadDat(const std::string& file); bool loadDat(const std::string& file);
bool loadOtb(const std::string& file); void loadOtb(const std::string& file);
bool loadXml(const std::string& file); void loadXml(const std::string& file);
void addOtbType(const ThingTypeOtbPtr& otbType); void addOtbType(const ThingTypeOtbPtr& otbType);
const ThingTypeOtbPtr& findOtbForClientId(uint16 id); const ThingTypeOtbPtr& findOtbForClientId(uint16 id);

@ -62,3 +62,14 @@ void ThingTypeOtb::unserialize(const BinaryTreePtr& node)
} }
} }
} }
void ThingTypeOtb::unserializeXML(const TiXmlElement* elem)
{
std::string key = elem->Attribute("key");
std::string value = elem->Attribute("value");
if (key == "name")
setName(value);
else if (key == "description")
setDesc(value);
}

@ -85,19 +85,30 @@ public:
ThingTypeOtb(); ThingTypeOtb();
void unserialize(const BinaryTreePtr& node); void unserialize(const BinaryTreePtr& node);
void unserializeXML(); void unserializeXML(const TiXmlElement* elem);
uint16 getServerId() { return m_serverId; } uint16 getServerId() { return m_serverId; }
uint16 getClientId() { return m_clientId; } uint16 getClientId() { return m_clientId; }
OtbCategory getCategory() { return m_category; } OtbCategory getCategory() { return m_category; }
bool isNull() { return m_null; } bool isNull() { return m_null; }
bool hasRange() { return m_hasRange; }
void setHasRange() { m_hasRange = true; }
void setFromServerId(uint16 from) { m_fromId = from; }
void setToServerId(uint16 to) { m_toId = to; }
void setName(const std::string& name) { m_name = name; }
void setDesc(const std::string& desc) { m_desc = desc; }
private: private:
uint16 m_serverId; uint16 m_serverId;
uint16 m_clientId; uint16 m_clientId;
uint16 m_fromId, m_toId;
std::string m_name, m_desc;
OtbCategory m_category; OtbCategory m_category;
Boolean<true> m_null; Boolean<true> m_null;
Boolean<false> m_hasRange;
}; };
#endif #endif

@ -100,6 +100,7 @@ public:
TilePtr asTile() { return std::static_pointer_cast<Tile>(shared_from_this()); } TilePtr asTile() { return std::static_pointer_cast<Tile>(shared_from_this()); }
void setFlags(tileflags_t flags) { m_flags |= (uint32)flags; } void setFlags(tileflags_t flags) { m_flags |= (uint32)flags; }
uint32 flags() { return m_flags; }
private: private:
void update(); void update();

@ -38,6 +38,8 @@
#include <otclient/core/thingtypemanager.h> #include <otclient/core/thingtypemanager.h>
#include <otclient/core/spritemanager.h> #include <otclient/core/spritemanager.h>
#include <otclient/core/shadermanager.h> #include <otclient/core/shadermanager.h>
#include <otclient/core/houses.h>
#include <otclient/core/towns.h>
#include <otclient/net/protocolgame.h> #include <otclient/net/protocolgame.h>
#include <otclient/ui/uiitem.h> #include <otclient/ui/uiitem.h>
#include <otclient/ui/uicreature.h> #include <otclient/ui/uicreature.h>
@ -53,6 +55,19 @@ void OTClient::registerLuaFunctions()
g_lua.bindSingletonFunction("g_things", "loadXml", &ThingTypeManager::loadXml, &g_things); g_lua.bindSingletonFunction("g_things", "loadXml", &ThingTypeManager::loadXml, &g_things);
g_lua.bindSingletonFunction("g_things", "getDatSignature", &ThingTypeManager::getDatSignature, &g_things); g_lua.bindSingletonFunction("g_things", "getDatSignature", &ThingTypeManager::getDatSignature, &g_things);
#if 0
g_lua.registerSingletonClass("g_houses");
g_lua.bindSingletonFunction("g_houses", "load", &Houses::load, &g_houses);
g_lua.bindSingletonFunction("g_houses", "getHouse", &Houses::getHouse, &g_houses);
g_lua.bindSingletonFunction("g_houses", "addHouse", &Houses::addHouse, &g_houses);
g_lua.bindSingletonFunction("g_houses", "removeHouse", &Houses::removeHouse, &g_houses);
g_lua.registerSingletonClass("g_towns");
g_lua.bindSingletonFunction("g_towns", "getTown", &Towns::getTown, &g_towns);
g_lua.bindSingletonFunction("g_towns", "addTown", &Towns::addTown, &g_towns);
g_lua.bindSingletonFunction("g_towns", "removeTown", &Towns::removeTown, &g_towns);
#endif
g_lua.registerSingletonClass("g_sprites"); g_lua.registerSingletonClass("g_sprites");
g_lua.bindSingletonFunction("g_sprites", "loadSpr", &SpriteManager::loadSpr, &g_sprites); g_lua.bindSingletonFunction("g_sprites", "loadSpr", &SpriteManager::loadSpr, &g_sprites);
g_lua.bindSingletonFunction("g_sprites", "unload", &SpriteManager::unload, &g_sprites); g_lua.bindSingletonFunction("g_sprites", "unload", &SpriteManager::unload, &g_sprites);
@ -81,6 +96,8 @@ void OTClient::registerLuaFunctions()
//g_lua.bindSingletonFunction("g_map", "saveOtbm", &Map::saveOtbm, &g_map); //g_lua.bindSingletonFunction("g_map", "saveOtbm", &Map::saveOtbm, &g_map);
g_lua.bindSingletonFunction("g_map", "loadOtcm", &Map::loadOtcm, &g_map); g_lua.bindSingletonFunction("g_map", "loadOtcm", &Map::loadOtcm, &g_map);
g_lua.bindSingletonFunction("g_map", "saveOtcm", &Map::saveOtcm, &g_map); g_lua.bindSingletonFunction("g_map", "saveOtcm", &Map::saveOtcm, &g_map);
g_lua.bindSingletonFunction("g_map", "getTown", &Map::getTown, &g_map);
g_lua.bindSingletonFunction("g_map", "getHouse", &Map::getHouse, &g_map);
g_lua.registerSingletonClass("g_game"); g_lua.registerSingletonClass("g_game");
g_lua.bindSingletonFunction("g_game", "loginWorld", &Game::loginWorld, &g_game); g_lua.bindSingletonFunction("g_game", "loginWorld", &Game::loginWorld, &g_game);
@ -255,6 +272,26 @@ void OTClient::registerLuaFunctions()
g_lua.bindClassMemberFunction<Thing>("isFullGround", &Thing::isFullGround); g_lua.bindClassMemberFunction<Thing>("isFullGround", &Thing::isFullGround);
g_lua.bindClassMemberFunction<Thing>("getParentContainer", &Thing::getParentContainer); g_lua.bindClassMemberFunction<Thing>("getParentContainer", &Thing::getParentContainer);
g_lua.registerClass<House>();
g_lua.bindClassStaticFunction<House>("create", []{ return HousePtr(new House); });
g_lua.bindClassMemberFunction<House>("setId", &House::setId);
g_lua.bindClassMemberFunction<House>("setName", &House::setName);
g_lua.bindClassMemberFunction<House>("addDoor", &House::addDoor);
g_lua.bindClassMemberFunction<House>("addDoorPos", &House::addDoor); // alternative method
g_lua.bindClassMemberFunction<House>("setTile", &House::setTile);
g_lua.bindClassMemberFunction<House>("addTile", &House::addDoor); // alternative method
g_lua.registerClass<Town>();
g_lua.bindClassStaticFunction<Town>("create", []{ return TownPtr(new Town); });
g_lua.bindClassMemberFunction<Town>("setId", &Town::setId);
g_lua.bindClassMemberFunction<Town>("setName", &Town::setName);
g_lua.bindClassMemberFunction<Town>("setPos", &Town::setPos);
g_lua.bindClassMemberFunction<Town>("setTemplePos", &Town::setPos); // alternative method
g_lua.bindClassMemberFunction<Town>("getId", &Town::getId);
g_lua.bindClassMemberFunction<Town>("getName", &Town::getName);
g_lua.bindClassMemberFunction<Town>("getPos", &Town::getPos);
g_lua.bindClassMemberFunction<Town>("getTemplePos", &Town::getPos); // alternative method
g_lua.registerClass<Creature, Thing>(); g_lua.registerClass<Creature, Thing>();
g_lua.bindClassStaticFunction<Creature>("create", []{ return CreaturePtr(new Creature); }); g_lua.bindClassStaticFunction<Creature>("create", []{ return CreaturePtr(new Creature); });
g_lua.bindClassMemberFunction<Creature>("getId", &Creature::getId); g_lua.bindClassMemberFunction<Creature>("getId", &Creature::getId);

Loading…
Cancel
Save