More work on OTBM/OTB/XML

This commit is contained in:
niczkx 2012-08-19 15:41:03 +00:00
parent 8cd8829048
commit 1ed95b6120
18 changed files with 254 additions and 167 deletions

View File

@ -181,32 +181,3 @@ Point BinaryTree::getPoint()
ret.y = getU8(); ret.y = getU8();
return ret; return ret;
} }
/// BinaryWriteTree
BinaryWriteTree::BinaryWriteTree(const FileStreamPtr& fin) :
m_fin(fin)
{
}
BinaryWriteTree::~BinaryWriteTree()
{
m_fin->close();
m_fin = nullptr;
}
void BinaryWriteTree::startNode(uint8 type)
{
writeU8(BINARYTREE_NODE_START);
writeU8(type);
}
void BinaryWriteTree::endNode()
{
writeU8(BINARYTREE_NODE_END);
}
void BinaryWriteTree::writeU8(uint8 u8) { m_fin->addU8(u8); }
void BinaryWriteTree::writeU16(uint16 u16) { m_fin->addU16(u16); }
void BinaryWriteTree::writeU32(uint32 u32) { m_fin->addU32(u32); }
void BinaryWriteTree::writeString(const std::string& str) { m_fin->addString(str); }

View File

@ -66,25 +66,4 @@ private:
uint m_startPos; uint m_startPos;
}; };
class BinaryWriteTree : public stdext::shared_object
{
public:
BinaryWriteTree(const FileStreamPtr& fin);
~BinaryWriteTree();
void startNode(uint8 type);
void endNode();
void writeU8(uint8 u8);
void writeU16(uint16 u16);
void writeU32(uint32 u32);
void writeString(const std::string& str);
void writePoint(const Point& p) { writeU8(p.x); writeU8(p.y); }
void writePos(const Position& p) { writeU16(p.x); writeU16(p.y); writeU8(p.z); }
private:
FileStreamPtr m_fin;
};
#endif #endif

View File

@ -267,6 +267,17 @@ BinaryTreePtr FileStream::getBinaryTree()
return BinaryTreePtr(new BinaryTree(asFileStream())); return BinaryTreePtr(new BinaryTree(asFileStream()));
} }
void FileStream::startNode(uint8 n)
{
addU8(BINARYTREE_NODE_START);
addU8(n);
}
void FileStream::endNode()
{
addU8(BINARYTREE_NODE_END);
}
void FileStream::addU8(uint8 v) void FileStream::addU8(uint8 v)
{ {
if(!m_caching) { if(!m_caching) {

View File

@ -26,6 +26,8 @@
#include "declarations.h" #include "declarations.h"
#include <framework/luaengine/luaobject.h> #include <framework/luaengine/luaobject.h>
#include <framework/util/databuffer.h> #include <framework/util/databuffer.h>
#include <otclient/position.h>
#include <framework/util/point.h>
struct PHYSFS_File; struct PHYSFS_File;
@ -55,11 +57,15 @@ public:
std::string getString(); std::string getString();
BinaryTreePtr getBinaryTree(); BinaryTreePtr getBinaryTree();
void startNode(uint8 n);
void endNode();
void addU8(uint8 v); void addU8(uint8 v);
void addU16(uint16 v); void addU16(uint16 v);
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 addPos(const Position& pos) { addU16(pos.x); addU16(pos.y); addU8(pos.z); }
void addPoint(const Point& p) { addU8(p.x); addU8(p.y); }
FileStreamPtr asFileStream() { return static_self_cast<FileStream>(); } FileStreamPtr asFileStream() { return static_self_cast<FileStream>(); }

View File

@ -26,6 +26,8 @@
#include <framework/core/resourcemanager.h> #include <framework/core/resourcemanager.h>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
Creatures g_creatures;
void Creatures::loadMonsters(const std::string& file) void Creatures::loadMonsters(const std::string& file)
{ {
TiXmlDocument doc; TiXmlDocument doc;
@ -127,7 +129,7 @@ bool Creatures::m_loadCreatureBuffer(TiXmlElement* attrib, const CreatureTypePtr
return type >= 0; return type >= 0;
} }
CreatureTypePtr Creatures::getCreature(std::string name) CreatureTypePtr Creatures::getCreatureByName(std::string name)
{ {
stdext::tolower(name); stdext::tolower(name);
stdext::trim(name); stdext::trim(name);
@ -135,3 +137,14 @@ CreatureTypePtr Creatures::getCreature(std::string name)
[=] (const CreatureTypePtr& m) -> bool { return m->getName() == name; }); [=] (const CreatureTypePtr& m) -> bool { return m->getName() == name; });
return it != m_creatures.end() ? *it : nullptr; return it != m_creatures.end() ? *it : nullptr;
} }
CreatureTypePtr Creatures::getCreatureByLook(int look)
{
auto findFun = [=] (const CreatureTypePtr& c) -> bool
{
const Outfit& o = c->getOutfit();
return o.getId() == look;
};
auto it = std::find_if(m_creatures.begin(), m_creatures.end(), findFun);
return it != m_creatures.end() ? *it : nullptr;
}

View File

@ -41,14 +41,15 @@ public:
CreatureType() { } CreatureType() { }
CreatureType(const std::string& name) { setName(name); } CreatureType(const std::string& name) { setName(name); }
void setName(const std::string& name) { m_attribs.set(CreatureAttrName, name); }
void setOutfit(const Outfit& o) { m_attribs.set(CreatureAttrOutfit, o); }
void setSpawnTime(int spawnTime) { m_attribs.set(CreatureAttrSpawnTime, spawnTime); } void setSpawnTime(int spawnTime) { m_attribs.set(CreatureAttrSpawnTime, spawnTime); }
std::string getName() { return m_attribs.get<std::string>(CreatureAttrName); }
Outfit getOutfit() { return m_attribs.get<Outfit>(CreatureAttrOutfit); }
int getSpawnTime() { return m_attribs.get<int>(CreatureAttrSpawnTime); } int getSpawnTime() { return m_attribs.get<int>(CreatureAttrSpawnTime); }
void setName(const std::string& name) { m_attribs.set(CreatureAttrName, name); }
std::string getName() { return m_attribs.get<std::string>(CreatureAttrName); }
void setOutfit(const Outfit& o) { m_attribs.set(CreatureAttrOutfit, o); }
Outfit getOutfit() { return m_attribs.get<Outfit>(CreatureAttrOutfit); }
private: private:
stdext::dynamic_storage<uint8> m_attribs; stdext::dynamic_storage<uint8> m_attribs;
}; };
@ -63,7 +64,9 @@ public:
void loadNpcs(const std::string& folder); void loadNpcs(const std::string& folder);
void loadCreatureBuffer(const std::string& buffer); void loadCreatureBuffer(const std::string& buffer);
CreatureTypePtr getCreature(std::string name); CreatureTypePtr getCreatureByName(std::string name);
CreatureTypePtr getCreatureByLook(int look);
bool isLoaded() const { return m_loaded; } bool isLoaded() const { return m_loaded; }
protected: protected:
@ -74,4 +77,6 @@ private:
stdext::boolean<false> m_loaded; stdext::boolean<false> m_loaded;
}; };
extern Creatures g_creatures;
#endif #endif

View File

@ -42,7 +42,7 @@ void Effect::onAppear()
// hack to fix some animation phases duration, currently there is no better solution // hack to fix some animation phases duration, currently there is no better solution
if(m_id == 33) if(m_id == 33)
m_phaseDuration *= 4; m_phaseDuration <<= 2;
// schedule removal // schedule removal
auto self = asEffect(); auto self = asEffect();

View File

@ -268,41 +268,45 @@ void Item::unserializeItem(const BinaryTreePtr &in)
} }
} }
void Item::serializeItem(const BinaryWriteTreePtr& out) void Item::serializeItem(const FileStreamPtr& out)
{ {
out->startNode(OTBM_ITEM); out->startNode(OTBM_ITEM);
out->writeU16(getId()); out->addU16(getId());
out->writeU8(ATTR_COUNT); out->addU8(ATTR_COUNT);
out->writeU8(getCount()); out->addU8(getCount());
out->writeU8(ATTR_CHARGES); out->addU8(ATTR_CHARGES);
out->writeU16(getCountOrSubType()); out->addU16(getCountOrSubType());
Position dest = m_attribs.get<Position>(ATTR_TELE_DEST); Position dest = m_attribs.get<Position>(ATTR_TELE_DEST);
if(dest.isValid()) { if(dest.isValid()) {
out->writeU8(ATTR_TELE_DEST); out->addU8(ATTR_TELE_DEST);
out->writePos(dest); out->addPos(dest);
} }
if(isDepot()) { if(isDepot()) {
out->writeU8(ATTR_DEPOT_ID); out->addU8(ATTR_DEPOT_ID);
out->writeU16(getDepotId()); out->addU16(getDepotId());
} }
uint16 aid = m_attribs.get<uint16>(ATTR_ACTION_ID); uint16 aid = m_attribs.get<uint16>(ATTR_ACTION_ID);
uint16 uid = m_attribs.get<uint16>(ATTR_UNIQUE_ID); uint16 uid = m_attribs.get<uint16>(ATTR_UNIQUE_ID);
if(aid) { if(aid) {
out->writeU8(ATTR_ACTION_ID); out->addU8(ATTR_ACTION_ID);
out->writeU16(aid); out->addU16(aid);
} }
if(uid) { if(uid) {
out->writeU8(ATTR_UNIQUE_ID); out->addU8(ATTR_UNIQUE_ID);
out->writeU16(uid); out->addU16(uid);
} }
out->endNode(); out->endNode();
if(!m_containerItems.empty()) {
for(auto c : m_containerItems)
c->serializeItem(out);
}
} }
int Item::getSubType() int Item::getSubType()

View File

@ -98,7 +98,7 @@ public:
ItemPtr clone(); ItemPtr clone();
void unserializeItem(const BinaryTreePtr& in); void unserializeItem(const BinaryTreePtr& in);
void serializeItem(const BinaryWriteTreePtr& out); void serializeItem(const FileStreamPtr& out);
void setDepotId(uint16 depotId) { m_attribs.set(ATTR_DEPOT_ID, depotId); } void setDepotId(uint16 depotId) { m_attribs.set(ATTR_DEPOT_ID, depotId); }
uint16 getDepotId() { return m_attribs.get<uint16>(ATTR_DEPOT_ID); } uint16 getDepotId() { return m_attribs.get<uint16>(ATTR_DEPOT_ID); }
@ -119,6 +119,8 @@ public:
ItemPtr asItem() { return static_self_cast<Item>(); } ItemPtr asItem() { return static_self_cast<Item>(); }
bool isItem() { return true; } bool isItem() { return true; }
void addContainerItem(const ItemPtr& i) { m_containerItems.push_back(i); }
const ThingTypePtr& getThingType(); const ThingTypePtr& getThingType();
ThingType *rawGetThingType(); ThingType *rawGetThingType();
@ -127,6 +129,7 @@ private:
uint16 m_otbId; uint16 m_otbId;
uint8 m_countOrSubType; uint8 m_countOrSubType;
stdext::packed_storage<uint8> m_attribs; stdext::packed_storage<uint8> m_attribs;
std::vector<ItemPtr> m_containerItems;
}; };
#pragma pack(pop) #pragma pack(pop)

View File

@ -41,6 +41,7 @@ void ItemType::unserialize(const BinaryTreePtr& node)
node->getU32(); // flags node->getU32(); // flags
static uint16 lastId = 99; static uint16 lastId = 99;
static ItemTypePtr nullType = g_things.getNullItemType();
while(node->canRead()) { while(node->canRead()) {
uint8 attr = node->getU8(); uint8 attr = node->getU8();
if(attr == 0 || attr == 0xFF) if(attr == 0 || attr == 0xFF)
@ -53,10 +54,13 @@ void ItemType::unserialize(const BinaryTreePtr& node)
if(serverId > 20000 && serverId < 20100) { if(serverId > 20000 && serverId < 20100) {
serverId -= 20000; serverId -= 20000;
} else if(lastId > 99 && lastId != serverId - 1) { } else if(lastId > 99 && lastId != serverId - 1) {
while(lastId != serverId - 1) while(lastId != serverId - 1) {
++lastId; nullType->setServerId(lastId++);
g_things.addItemType(nullType);
}
} }
setServerId(serverId); setServerId(serverId);
lastId = serverId;
break; break;
} }
case ItemTypeAttrClientId: { case ItemTypeAttrClientId: {
@ -67,10 +71,6 @@ void ItemType::unserialize(const BinaryTreePtr& node)
setName(node->getString(len)); setName(node->getString(len));
break; break;
} }
case ItemTypeAttrDesc: {
setDesc(node->getString());
break;
}
default: default:
node->skip(len); // skip attribute node->skip(len); // skip attribute
break; break;

View File

@ -28,7 +28,7 @@
#include <framework/luaengine/luaobject.h> #include <framework/luaengine/luaobject.h>
#include <framework/xml/tinyxml.h> #include <framework/xml/tinyxml.h>
enum ItemCategory { enum ItemCategory : uint8 {
ItemCategoryInvalid = 0, ItemCategoryInvalid = 0,
ItemCategoryGround = 1, ItemCategoryGround = 1,
ItemCategoryContainer = 2, ItemCategoryContainer = 2,
@ -86,19 +86,23 @@ public:
void unserialize(const BinaryTreePtr& node); void unserialize(const BinaryTreePtr& node);
void setServerId(uint16 serverId) { m_attribs.set(ItemTypeAttrServerId, serverId); }
uint16 getServerId() { return m_attribs.get<uint16>(ItemTypeAttrServerId); } uint16 getServerId() { return m_attribs.get<uint16>(ItemTypeAttrServerId); }
void setClientId(uint16 clientId) { m_attribs.set(ItemTypeAttrClientId, clientId); }
uint16 getClientId() { return m_attribs.get<uint16>(ItemTypeAttrClientId); } uint16 getClientId() { return m_attribs.get<uint16>(ItemTypeAttrClientId); }
void setCategory(ItemCategory category) { m_category = category; }
ItemCategory getCategory() { return m_category; } ItemCategory getCategory() { return m_category; }
void setName(const std::string& name) { m_attribs.set(ItemTypeAttrName, name); }
std::string getName() { return m_attribs.get<std::string>(ItemTypeAttrName); } std::string getName() { return m_attribs.get<std::string>(ItemTypeAttrName); }
void setDesc(const std::string& desc) { m_attribs.set(ItemTypeAttrDesc, desc); }
std::string getDesc() { return m_attribs.get<std::string>(ItemTypeAttrDesc); } std::string getDesc() { return m_attribs.get<std::string>(ItemTypeAttrDesc); }
bool isNull() { return m_null; } bool isNull() { return m_null; }
void setClientId(uint16 clientId) { m_attribs.set(ItemTypeAttrClientId, clientId); }
void setServerId(uint16 serverId) { m_attribs.set(ItemTypeAttrServerId, serverId); }
void setName(const std::string& name) { m_attribs.set(ItemTypeAttrName, name); }
void setDesc(const std::string& desc) { m_attribs.set(ItemTypeAttrDesc, desc); }
private: private:
ItemCategory m_category; ItemCategory m_category;
stdext::boolean<true> m_null; stdext::boolean<true> m_null;

View File

@ -59,9 +59,11 @@ void OTClient::registerLuaFunctions()
g_lua.bindSingletonFunction("g_things", "getDatSignature", &ThingTypeManager::getDatSignature, &g_things); g_lua.bindSingletonFunction("g_things", "getDatSignature", &ThingTypeManager::getDatSignature, &g_things);
g_lua.bindSingletonFunction("g_things", "getThingType", &ThingTypeManager::getThingType, &g_things); g_lua.bindSingletonFunction("g_things", "getThingType", &ThingTypeManager::getThingType, &g_things);
g_lua.bindSingletonFunction("g_things", "getItemType", &ThingTypeManager::getItemType, &g_things); g_lua.bindSingletonFunction("g_things", "getItemType", &ThingTypeManager::getItemType, &g_things);
g_lua.bindSingletonFunction("g_things", "getThingTypes", &ThingTypeManager::getThingTypes, &g_things);
g_lua.bindSingletonFunction("g_things", "findItemTypeByClientId", &ThingTypeManager::findItemTypeByClientId, &g_things); g_lua.bindSingletonFunction("g_things", "findItemTypeByClientId", &ThingTypeManager::findItemTypeByClientId, &g_things);
g_lua.bindSingletonFunction("g_things", "findThingTypeByAttr", &ThingTypeManager::findThingTypeByAttr, &g_things); g_lua.bindSingletonFunction("g_things", "findThingTypeByAttr", &ThingTypeManager::findThingTypeByAttr, &g_things);
g_lua.bindSingletonFunction("g_things", "findItemTypeByCategory", &ThingTypeManager::findItemTypeByCategory, &g_things); g_lua.bindSingletonFunction("g_things", "findItemTypeByCategory", &ThingTypeManager::findItemTypeByCategory, &g_things);
g_lua.bindSingletonFunction("g_things", "castThingToCreature", &ThingTypeManager::castThingToCreature, &g_things);
#if 0 #if 0
g_lua.registerSingletonClass("g_houses"); g_lua.registerSingletonClass("g_houses");
@ -112,6 +114,11 @@ void OTClient::registerLuaFunctions()
g_lua.bindSingletonFunction("g_map", "getHouse", &Map::getHouse, &g_map); g_lua.bindSingletonFunction("g_map", "getHouse", &Map::getHouse, &g_map);
g_lua.bindSingletonFunction("g_map", "getCreature", &Map::getCreature, &g_map); g_lua.bindSingletonFunction("g_map", "getCreature", &Map::getCreature, &g_map);
/// \todo move creatures from Map to here
g_lua.registerSingletonClass("g_creatures");
g_lua.bindSingletonFunction("g_creatures", "getCreature", &Creatures::getCreatureByName, &g_creatures);
g_lua.bindSingletonFunction("g_creatures", "getCreatureByLook", &Creatures::getCreatureByLook, &g_creatures);
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);
g_lua.bindSingletonFunction("g_game", "cancelLogin", &Game::cancelLogin, &g_game); g_lua.bindSingletonFunction("g_game", "cancelLogin", &Game::cancelLogin, &g_game);
@ -340,6 +347,7 @@ void OTClient::registerLuaFunctions()
g_lua.bindClassMemberFunction<ThingType>("getId", &ThingType::getId); g_lua.bindClassMemberFunction<ThingType>("getId", &ThingType::getId);
g_lua.bindClassMemberFunction<ThingType>("getMarketData", &ThingType::getMarketData); g_lua.bindClassMemberFunction<ThingType>("getMarketData", &ThingType::getMarketData);
g_lua.bindClassMemberFunction<ThingType>("getClothSlot", &ThingType::getClothSlot); g_lua.bindClassMemberFunction<ThingType>("getClothSlot", &ThingType::getClothSlot);
g_lua.bindClassMemberFunction<ThingType>("getCategory", &ThingType::getCategory);
g_lua.registerClass<Item, Thing>(); g_lua.registerClass<Item, Thing>();
g_lua.bindClassStaticFunction<Item>("create", &Item::create); g_lua.bindClassStaticFunction<Item>("create", &Item::create);

View File

@ -69,7 +69,7 @@ void Map::clean()
m_towns.clear(); m_towns.clear();
m_houses.clear(); m_houses.clear();
m_creatures.clear(); g_creatures.clear();
m_tilesRect = Rect(65534, 65534, 0, 0); m_tilesRect = Rect(65534, 65534, 0, 0);
} }

View File

@ -187,7 +187,7 @@ public:
void saveOtbm(const std::string& fileName); void saveOtbm(const std::string& fileName);
void loadSpawns(const std::string& fileName); void loadSpawns(const std::string& fileName);
void saveSpawns(const std::string&) { } void saveSpawns(const std::string&);
// otbm attributes (description, size, etc.) // otbm attributes (description, size, etc.)
void setHouseFile(const std::string& file) { m_attribs.set(OTBM_ATTR_HOUSE_FILE, file); } void setHouseFile(const std::string& file) { m_attribs.set(OTBM_ATTR_HOUSE_FILE, file); }
@ -201,9 +201,9 @@ public:
Size getSize() { return Size(m_attribs.get<uint16>(OTBM_ATTR_WIDTH), m_attribs.get<uint16>(OTBM_ATTR_HEIGHT)); } Size getSize() { return Size(m_attribs.get<uint16>(OTBM_ATTR_WIDTH), m_attribs.get<uint16>(OTBM_ATTR_HEIGHT)); }
std::vector<std::string> getDescriptions() { return stdext::split(m_attribs.get<std::string>(OTBM_ATTR_DESCRIPTION), "\n"); } std::vector<std::string> getDescriptions() { return stdext::split(m_attribs.get<std::string>(OTBM_ATTR_DESCRIPTION), "\n"); }
void loadMonsters(const std::string& fileName) { m_creatures.loadMonsters(fileName); } void loadMonsters(const std::string& fileName) { g_creatures.loadMonsters(fileName); }
void loadSingleCreature(const std::string& file) { m_creatures.loadSingleCreature(file); } void loadSingleCreature(const std::string& file) { g_creatures.loadSingleCreature(file); }
void loadNpcs(const std::string& folder) { m_creatures.loadNpcs(folder); } void loadNpcs(const std::string& folder) { g_creatures.loadNpcs(folder); }
void clean(); void clean();
void cleanDynamicThings(); void cleanDynamicThings();
@ -234,7 +234,7 @@ public:
// town/house/monster related // town/house/monster related
TownPtr getTown(uint32 tid) { return m_towns.getTown(tid); } TownPtr getTown(uint32 tid) { return m_towns.getTown(tid); }
HousePtr getHouse(uint32 hid) { return m_houses.getHouse(hid); } HousePtr getHouse(uint32 hid) { return m_houses.getHouse(hid); }
CreatureTypePtr getCreature(const std::string &name) { return m_creatures.getCreature(name); } CreatureTypePtr getCreature(const std::string &name) { return g_creatures.getCreatureByName(name); }
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);
@ -273,7 +273,6 @@ private:
stdext::packed_storage<uint8> m_attribs; stdext::packed_storage<uint8> m_attribs;
Houses m_houses; Houses m_houses;
Towns m_towns; Towns m_towns;
Creatures m_creatures;
static TilePtr m_nulltile; static TilePtr m_nulltile;
}; };

View File

@ -95,7 +95,7 @@ void Map::loadOtbm(const std::string& fileName)
} }
} }
for(const BinaryTreePtr &nodeMapData : node->getChildren()) { for(const BinaryTreePtr& nodeMapData : node->getChildren()) {
uint8 mapDataType = nodeMapData->getU8(); uint8 mapDataType = nodeMapData->getU8();
if(mapDataType == OTBM_TILE_AREA) { if(mapDataType == OTBM_TILE_AREA) {
Position basePos = nodeMapData->getPosition(); Position basePos = nodeMapData->getPosition();
@ -149,7 +149,7 @@ void Map::loadOtbm(const std::string& fileName)
} }
} }
for(const BinaryTreePtr &nodeItem : nodeTile->getChildren()) { for(const BinaryTreePtr& nodeItem : nodeTile->getChildren()) {
if(nodeItem->getU8() != OTBM_ITEM) if(nodeItem->getU8() != OTBM_ITEM)
stdext::throw_exception("invalid item node"); stdext::throw_exception("invalid item node");
@ -163,7 +163,7 @@ void Map::loadOtbm(const std::string& fileName)
ItemPtr cItem = Item::createFromOtb(containerItem->getU16()); ItemPtr cItem = Item::createFromOtb(containerItem->getU16());
cItem->unserializeItem(containerItem); cItem->unserializeItem(containerItem);
//item->addContainerItem(cItem); item->addContainerItem(cItem);
} }
} }
@ -175,9 +175,12 @@ void Map::loadOtbm(const std::string& fileName)
addThing(item, pos); addThing(item, pos);
} }
if(const TilePtr& tile = getTile(pos)) if(const TilePtr& tile = getTile(pos)) {
if(house)
tile->setHouseId(house->getId());
tile->setFlags((tileflags_t)flags); 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()) {
@ -263,41 +266,40 @@ void Map::saveOtbm(const std::string &fileName)
#endif #endif
fin->addU32(0); // file version fin->addU32(0); // file version
BinaryWriteTreePtr root(new BinaryWriteTree(fin)); fin->startNode(0);
root->startNode(0);
{ {
root->writeU32(version); fin->addU32(version);
Size mapSize = getSize(); Size mapSize = getSize();
root->writeU16(mapSize.width()); fin->addU16(mapSize.width());
root->writeU16(mapSize.height()); fin->addU16(mapSize.height());
root->writeU32(g_things.getOtbMajorVersion()); fin->addU32(g_things.getOtbMajorVersion());
root->writeU32(g_things.getOtbMinorVersion()); fin->addU32(g_things.getOtbMinorVersion());
root->startNode(OTBM_MAP_DATA); fin->startNode(OTBM_MAP_DATA);
{ {
// own description. // own description.
for(const auto& desc : getDescriptions()) { for(const auto& desc : getDescriptions()) {
root->writeU8(OTBM_ATTR_DESCRIPTION); fin->addU8(OTBM_ATTR_DESCRIPTION);
root->writeString(desc); fin->addString(desc);
} }
// special one // special one
root->writeU8(OTBM_ATTR_DESCRIPTION); fin->addU8(OTBM_ATTR_DESCRIPTION);
root->writeString(stdext::format("Saved with %s v%s", g_app.getName(), g_app.getVersion())); fin->addString(stdext::format("Saved with %s v%s", g_app.getName(), g_app.getVersion()));
// spawn file. // spawn file.
root->writeU8(OTBM_ATTR_SPAWN_FILE); fin->addU8(OTBM_ATTR_SPAWN_FILE);
root->writeString(spawnFile); fin->addString(spawnFile);
// house file. // house file.
if(version > 1) { if(version > 1) {
root->writeU8(OTBM_ATTR_HOUSE_FILE); fin->addU8(OTBM_ATTR_HOUSE_FILE);
root->writeString(houseFile); fin->addString(houseFile);
} }
Position base(-1, -1, -1); Position base(0, 0, 0);
bool firstNode = true; bool firstNode = true;
for(uint8_t z = 0; z <= Otc::MAX_Z; ++z) { for(uint8_t z = 0; z <= Otc::MAX_Z; ++z) {
@ -311,71 +313,72 @@ void Map::saveOtbm(const std::string &fileName)
if(!pos.isValid()) if(!pos.isValid())
continue; continue;
if(pos.x < base.x || pos.x >= base.x + 256 || pos.y < base.y|| pos.y >= base.y + 256 || if(pos.x < base.x || pos.x >= base.x + 255
pos.z != base.z) { || pos.y < base.y || pos.y >= base.y + 255
|| pos.z != base.z) {
if(!firstNode) if(!firstNode)
root->endNode(); /// OTBM_TILE_AREA fin->endNode(); /// OTBM_TILE_AREA
root->startNode(OTBM_TILE_AREA); fin->startNode(OTBM_TILE_AREA);
firstNode = false; firstNode = false;
root->writePos(base = pos & 0xFF00); fin->addPos(base = pos & 0xFF00);
} }
uint32 flags = tile->getFlags(); uint32 flags = tile->getFlags();
root->startNode((flags & TILESTATE_HOUSE) == TILESTATE_HOUSE ? OTBM_HOUSETILE : OTBM_TILE); fin->startNode((flags & TILESTATE_HOUSE) == TILESTATE_HOUSE ? OTBM_HOUSETILE : OTBM_TILE);
root->writePoint(Point(pos.x, pos.y) & 0xFF); fin->addPoint(Point(pos.x, pos.y) & 0xFF);
// if(tileNode->getType() == OTBM_HOUSETILE) if((flags & TILESTATE_HOUSE) == TILESTATE_HOUSE)
// tileNode->writeU32(tile->getHouseId()); fin->addU32(tile->getHouseId());
if(flags) { if(flags) {
root->writeU8(OTBM_ATTR_TILE_FLAGS); fin->addU8(OTBM_ATTR_TILE_FLAGS);
root->writeU32(flags); fin->addU32(flags);
} }
for(const ItemPtr& item : tile->getItems()) { for(const ItemPtr& item : tile->getItems()) {
if(item->isGround()) { if(item->isGround()) {
root->writeU8(OTBM_ATTR_ITEM); fin->addU8(OTBM_ATTR_ITEM);
root->writeU16(item->getId()); fin->addU16(item->getId());
continue; continue;
} }
item->serializeItem(root); item->serializeItem(fin);
} }
root->endNode(); // OTBM_TILE fin->endNode(); // OTBM_TILE
} }
} }
} }
if(!firstNode) if(!firstNode)
root->endNode(); // OTBM_TILE_AREA fin->endNode(); // OTBM_TILE_AREA
root->startNode(OTBM_TOWNS); fin->startNode(OTBM_TOWNS);
for(const TownPtr& town : m_towns.getTowns()) { for(const TownPtr& town : m_towns.getTowns()) {
root->writeU32(town->getId()); fin->addU32(town->getId());
root->writeString(town->getName()); fin->addString(town->getName());
root->writePos(town->getPos()); fin->addPos(town->getPos());
} }
root->endNode(); fin->endNode();
if(version > 1) { if(version > 1) {
root->startNode(OTBM_WAYPOINTS); fin->startNode(OTBM_WAYPOINTS);
for(const auto& it : m_waypoints) { for(const auto& it : m_waypoints) {
root->writeString(it.second); fin->addString(it.second);
root->writePos(it.first); fin->addPos(it.first);
} }
root->endNode(); fin->endNode();
} }
} }
root->endNode(); // OTBM_MAP_DATA fin->endNode(); // OTBM_MAP_DATA
} }
root->endNode(); // 0 (root) fin->endNode(); // 0 (root)
} }
void Map::loadSpawns(const std::string &fileName) void Map::loadSpawns(const std::string &fileName)
{ {
if(!m_creatures.isLoaded()) if(!g_creatures.isLoaded())
stdext::throw_exception("cannot load spawns; monsters/nps aren't loaded."); stdext::throw_exception("cannot load spawns; monsters/nps aren't loaded.");
TiXmlDocument doc; TiXmlDocument doc;
@ -401,7 +404,7 @@ void Map::loadSpawns(const std::string &fileName)
stdext::tolower(cName); stdext::tolower(cName);
stdext::trim(cName); stdext::trim(cName);
if (!(cType = m_creatures.getCreature(cName))) if (!(cType = g_creatures.getCreatureByName(cName)))
continue; continue;
cType->setSpawnTime(cNode->readType<int>("spawntime")); cType->setSpawnTime(cNode->readType<int>("spawntime"));
@ -420,6 +423,21 @@ void Map::loadSpawns(const std::string &fileName)
} }
} }
void Map::saveSpawns(const std::string& fileName)
{
#if 0
TiXmlDocument doc;
TiXmlDeclaration* decl = new TiXmlDeclaration("1.0", "UTF-8", "");
doc.LinkEndChild(decl);
TiXmlElement* root = new TiXmlElement("spawns");
doc.LinkEndChild(root);
TiXmlElement* spawn = NULL;
#endif
}
bool Map::loadOtcm(const std::string& fileName) bool Map::loadOtcm(const std::string& fileName)
{ {
try { try {

View File

@ -25,6 +25,8 @@
#include "thing.h" #include "thing.h"
#include "thingtype.h" #include "thingtype.h"
#include "itemtype.h" #include "itemtype.h"
#include "creature.h"
#include "creatures.h"
#include <framework/core/resourcemanager.h> #include <framework/core/resourcemanager.h>
#include <framework/core/filestream.h> #include <framework/core/filestream.h>
@ -125,7 +127,9 @@ void ThingTypeManager::loadOtb(const std::string& file)
void ThingTypeManager::loadXml(const std::string& file) void ThingTypeManager::loadXml(const std::string& file)
{ {
/// Read XML if(!isOtbLoaded())
stdext::throw_exception("OTB must be loaded before XML");
TiXmlDocument doc; TiXmlDocument doc;
doc.Parse(g_resources.loadFile(file).c_str()); doc.Parse(g_resources.loadFile(file).c_str());
if(doc.Error()) if(doc.Error())
@ -140,19 +144,27 @@ void ThingTypeManager::loadXml(const std::string& file)
continue; continue;
uint16 id = element->readType<uint16>("id"); uint16 id = element->readType<uint16>("id");
if(id > 20000 && id < 20100) { if(id != 0) {
id -= 20000; std::vector<std::string> s_ids = stdext::split(element->Attribute("id"), ";");
ItemTypePtr newType(new ItemType); for(const std::string& s : s_ids) {
newType->setServerId(id); std::vector<int32> ids = stdext::split<int32>(s, "-");
addItemType(newType); if(ids.size() > 1) {
int32 i = ids[0];
while(i <= ids[1])
parseItemType(i++, element);
} else
parseItemType(atoi(s.c_str()), element);
}
} else {
std::vector<int32> begin = stdext::split<int32>(element->Attribute("fromid"), ";");
std::vector<int32> end = stdext::split<int32>(element->Attribute("toid"), ";");
if(begin[0] && begin.size() == end.size()) {
size_t size = begin.size();
for(size_t i = 0; i < size; ++i) {
while(begin[i] <= end[i])
parseItemType(begin[i]++, element);
}
} }
if(id != 0)
parseItemType(id, element);
else {
uint16 fromId = element->readType<uint16>("fromid"), toId = element->readType<uint16>("toid");
for(uint16 i = fromId; i < toId; ++i)
parseItemType(i, element);
} }
} }
@ -164,23 +176,53 @@ void ThingTypeManager::loadXml(const std::string& file)
void ThingTypeManager::parseItemType(uint16 id, TiXmlElement* elem) void ThingTypeManager::parseItemType(uint16 id, TiXmlElement* elem)
{ {
uint16 serverId = id; uint16 serverId = id;
ItemTypePtr itemType = nullptr;
if(serverId > 20000 && id < 20100) { if(serverId > 20000 && id < 20100) {
serverId -= 20000; serverId -= 20000;
ItemTypePtr newType(new ItemType); itemType = ItemTypePtr(new ItemType);
newType->setServerId(serverId); itemType->setServerId(serverId);
addItemType(newType); addItemType(itemType);
}
if(!itemType) {
itemType = getItemType(serverId);
if(itemType == m_nullItemType) {
itemType = ItemTypePtr(new ItemType);
itemType->setServerId(id);
addItemType(itemType);
}
} }
ItemTypePtr itemType = getItemType(serverId);
itemType->setName(elem->Attribute("name")); itemType->setName(elem->Attribute("name"));
for(TiXmlElement* attrib = elem->FirstChildElement(); attrib; attrib = attrib->NextSiblingElement()) { for(TiXmlElement* attrib = elem->FirstChildElement(); attrib; attrib = attrib->NextSiblingElement()) {
if(attrib->ValueStr() != "attribute") std::string key = attrib->Attribute("key");
break; if(key.empty())
continue;
if(attrib->Attribute("key") == "description") { stdext::tolower(key);
if(key == "description")
itemType->setDesc(attrib->Attribute("value")); itemType->setDesc(attrib->Attribute("value"));
break; else if(key == "weapontype")
itemType->setCategory(ItemCategoryWeapon);
else if(key == "ammotype")
itemType->setCategory(ItemCategoryAmmunition);
else if(key == "armor")
itemType->setCategory(ItemCategoryArmor);
else if(key == "charges")
itemType->setCategory(ItemCategoryCharges);
else if(key == "type") {
std::string value = attrib->Attribute("value");
stdext::tolower(value);
if(value == "key")
itemType->setCategory(ItemCategoryKey);
else if(value == "magicfield")
itemType->setCategory(ItemCategoryMagicField);
else if(value == "teleport")
itemType->setCategory(ItemCategoryTeleport);
else if(value == "door")
itemType->setCategory(ItemCategoryDoor);
} }
} }
} }
@ -189,7 +231,7 @@ void ThingTypeManager::addItemType(const ItemTypePtr& itemType)
{ {
uint16 id = itemType->getServerId(); uint16 id = itemType->getServerId();
if(m_itemTypes.size() <= id) if(m_itemTypes.size() <= id)
m_itemTypes.resize(id+1, m_nullItemType); m_itemTypes.resize((id * 3) / 2 + 1, m_nullItemType);
m_itemTypes[id] = itemType; m_itemTypes[id] = itemType;
} }
@ -217,13 +259,36 @@ const ThingTypePtr& ThingTypeManager::getThingType(uint16 id, ThingCategory cate
const ItemTypePtr& ThingTypeManager::getItemType(uint16 id) const ItemTypePtr& ThingTypeManager::getItemType(uint16 id)
{ {
if(id >= m_itemTypes.size()) { if(id >= m_itemTypes.size() || m_itemTypes[id] == m_nullItemType) {
g_logger.error(stdext::format("invalid thing type server id %d", id)); g_logger.error(stdext::format("invalid thing type server id %d", id));
return m_nullItemType; return m_nullItemType;
} }
return m_itemTypes[id]; return m_itemTypes[id];
} }
CreaturePtr ThingTypeManager::castThingToCreature(const ThingTypePtr& thing)
{
if(!thing)
return nullptr;
if(thing->getCategory() != ThingCategoryCreature)
stdext::throw_exception("Thing type is not a creature");
uint16 clientId = thing->getId();
CreaturePtr ret(new Creature);
CreatureTypePtr cType = g_creatures.getCreatureByLook(clientId);
if(!cType) {
// a creature can have a look item with whether client id or even server id
const ItemTypePtr& item = findItemTypeByClientId(clientId);
if(item && !(cType = g_creatures.getCreatureByLook(item->getServerId())))
stdext::throw_exception(stdext::format("failed to find creature with look type/item %hd", clientId));
}
ret->setName(cType->getName());
ret->setOutfit(cType->getOutfit());
return ret;
}
ThingTypeList ThingTypeManager::findThingTypeByAttr(ThingAttr attr, ThingCategory category) ThingTypeList ThingTypeManager::findThingTypeByAttr(ThingAttr attr, ThingCategory category)
{ {
ThingTypeList ret; ThingTypeList ret;

View File

@ -50,6 +50,7 @@ public:
const ItemTypePtr& getItemType(uint16 id); const ItemTypePtr& getItemType(uint16 id);
ThingType* rawGetThingType(uint16 id, ThingCategory category) { return m_thingTypes[category][id].get(); } ThingType* rawGetThingType(uint16 id, ThingCategory category) { return m_thingTypes[category][id].get(); }
ItemType* rawGetItemType(uint16 id) { return m_itemTypes[id].get(); } ItemType* rawGetItemType(uint16 id) { return m_itemTypes[id].get(); }
CreaturePtr castThingToCreature(const ThingTypePtr& thing);
ThingTypeList findThingTypeByAttr(ThingAttr attr, ThingCategory category); ThingTypeList findThingTypeByAttr(ThingAttr attr, ThingCategory category);
ItemTypeList findItemTypeByCategory(ItemCategory category); ItemTypeList findItemTypeByCategory(ItemCategory category);

View File

@ -109,7 +109,7 @@ public:
void setFlags(tileflags_t flags) { m_flags |= (uint32)flags; } void setFlags(tileflags_t flags) { m_flags |= (uint32)flags; }
uint32 getFlags() { return m_flags; } uint32 getFlags() { return m_flags; }
void setHouseId(uint32 hid) { if(m_flags & TILESTATE_HOUSE) m_houseId = hid; } void setHouseId(uint32 hid) { m_houseId = hid; }
uint32 getHouseId() { return m_houseId; } uint32 getHouseId() { return m_houseId; }
TilePtr asTile() { return static_self_cast<Tile>(); } TilePtr asTile() { return static_self_cast<Tile>(); }