More work on OTBM/OTB/XML
This commit is contained in:
parent
8cd8829048
commit
1ed95b6120
|
@ -181,32 +181,3 @@ Point BinaryTree::getPoint()
|
|||
ret.y = getU8();
|
||||
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); }
|
||||
|
||||
|
|
|
@ -66,25 +66,4 @@ private:
|
|||
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
|
||||
|
|
|
@ -267,6 +267,17 @@ BinaryTreePtr FileStream::getBinaryTree()
|
|||
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)
|
||||
{
|
||||
if(!m_caching) {
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include "declarations.h"
|
||||
#include <framework/luaengine/luaobject.h>
|
||||
#include <framework/util/databuffer.h>
|
||||
#include <otclient/position.h>
|
||||
#include <framework/util/point.h>
|
||||
|
||||
struct PHYSFS_File;
|
||||
|
||||
|
@ -55,11 +57,15 @@ public:
|
|||
std::string getString();
|
||||
BinaryTreePtr getBinaryTree();
|
||||
|
||||
void startNode(uint8 n);
|
||||
void endNode();
|
||||
void addU8(uint8 v);
|
||||
void addU16(uint16 v);
|
||||
void addU32(uint32 v);
|
||||
void addU64(uint64 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>(); }
|
||||
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include <framework/core/resourcemanager.h>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
Creatures g_creatures;
|
||||
|
||||
void Creatures::loadMonsters(const std::string& file)
|
||||
{
|
||||
TiXmlDocument doc;
|
||||
|
@ -127,7 +129,7 @@ bool Creatures::m_loadCreatureBuffer(TiXmlElement* attrib, const CreatureTypePtr
|
|||
return type >= 0;
|
||||
}
|
||||
|
||||
CreatureTypePtr Creatures::getCreature(std::string name)
|
||||
CreatureTypePtr Creatures::getCreatureByName(std::string name)
|
||||
{
|
||||
stdext::tolower(name);
|
||||
stdext::trim(name);
|
||||
|
@ -135,3 +137,14 @@ CreatureTypePtr Creatures::getCreature(std::string name)
|
|||
[=] (const CreatureTypePtr& m) -> bool { return m->getName() == name; });
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -41,14 +41,15 @@ public:
|
|||
CreatureType() { }
|
||||
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); }
|
||||
|
||||
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); }
|
||||
|
||||
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:
|
||||
stdext::dynamic_storage<uint8> m_attribs;
|
||||
};
|
||||
|
@ -63,7 +64,9 @@ public:
|
|||
void loadNpcs(const std::string& folder);
|
||||
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; }
|
||||
|
||||
protected:
|
||||
|
@ -74,4 +77,6 @@ private:
|
|||
stdext::boolean<false> m_loaded;
|
||||
};
|
||||
|
||||
extern Creatures g_creatures;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -42,7 +42,7 @@ void Effect::onAppear()
|
|||
|
||||
// hack to fix some animation phases duration, currently there is no better solution
|
||||
if(m_id == 33)
|
||||
m_phaseDuration *= 4;
|
||||
m_phaseDuration <<= 2;
|
||||
|
||||
// schedule removal
|
||||
auto self = asEffect();
|
||||
|
|
|
@ -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->writeU16(getId());
|
||||
out->addU16(getId());
|
||||
|
||||
out->writeU8(ATTR_COUNT);
|
||||
out->writeU8(getCount());
|
||||
out->addU8(ATTR_COUNT);
|
||||
out->addU8(getCount());
|
||||
|
||||
out->writeU8(ATTR_CHARGES);
|
||||
out->writeU16(getCountOrSubType());
|
||||
out->addU8(ATTR_CHARGES);
|
||||
out->addU16(getCountOrSubType());
|
||||
|
||||
Position dest = m_attribs.get<Position>(ATTR_TELE_DEST);
|
||||
if(dest.isValid()) {
|
||||
out->writeU8(ATTR_TELE_DEST);
|
||||
out->writePos(dest);
|
||||
out->addU8(ATTR_TELE_DEST);
|
||||
out->addPos(dest);
|
||||
}
|
||||
|
||||
if(isDepot()) {
|
||||
out->writeU8(ATTR_DEPOT_ID);
|
||||
out->writeU16(getDepotId());
|
||||
out->addU8(ATTR_DEPOT_ID);
|
||||
out->addU16(getDepotId());
|
||||
}
|
||||
|
||||
uint16 aid = m_attribs.get<uint16>(ATTR_ACTION_ID);
|
||||
uint16 uid = m_attribs.get<uint16>(ATTR_UNIQUE_ID);
|
||||
if(aid) {
|
||||
out->writeU8(ATTR_ACTION_ID);
|
||||
out->writeU16(aid);
|
||||
out->addU8(ATTR_ACTION_ID);
|
||||
out->addU16(aid);
|
||||
}
|
||||
|
||||
if(uid) {
|
||||
out->writeU8(ATTR_UNIQUE_ID);
|
||||
out->writeU16(uid);
|
||||
out->addU8(ATTR_UNIQUE_ID);
|
||||
out->addU16(uid);
|
||||
}
|
||||
|
||||
out->endNode();
|
||||
if(!m_containerItems.empty()) {
|
||||
for(auto c : m_containerItems)
|
||||
c->serializeItem(out);
|
||||
}
|
||||
}
|
||||
|
||||
int Item::getSubType()
|
||||
|
|
|
@ -98,7 +98,7 @@ public:
|
|||
ItemPtr clone();
|
||||
|
||||
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); }
|
||||
uint16 getDepotId() { return m_attribs.get<uint16>(ATTR_DEPOT_ID); }
|
||||
|
@ -119,6 +119,8 @@ public:
|
|||
ItemPtr asItem() { return static_self_cast<Item>(); }
|
||||
bool isItem() { return true; }
|
||||
|
||||
void addContainerItem(const ItemPtr& i) { m_containerItems.push_back(i); }
|
||||
|
||||
const ThingTypePtr& getThingType();
|
||||
ThingType *rawGetThingType();
|
||||
|
||||
|
@ -127,6 +129,7 @@ private:
|
|||
uint16 m_otbId;
|
||||
uint8 m_countOrSubType;
|
||||
stdext::packed_storage<uint8> m_attribs;
|
||||
std::vector<ItemPtr> m_containerItems;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
|
|
@ -41,6 +41,7 @@ void ItemType::unserialize(const BinaryTreePtr& node)
|
|||
node->getU32(); // flags
|
||||
|
||||
static uint16 lastId = 99;
|
||||
static ItemTypePtr nullType = g_things.getNullItemType();
|
||||
while(node->canRead()) {
|
||||
uint8 attr = node->getU8();
|
||||
if(attr == 0 || attr == 0xFF)
|
||||
|
@ -53,10 +54,13 @@ void ItemType::unserialize(const BinaryTreePtr& node)
|
|||
if(serverId > 20000 && serverId < 20100) {
|
||||
serverId -= 20000;
|
||||
} else if(lastId > 99 && lastId != serverId - 1) {
|
||||
while(lastId != serverId - 1)
|
||||
++lastId;
|
||||
while(lastId != serverId - 1) {
|
||||
nullType->setServerId(lastId++);
|
||||
g_things.addItemType(nullType);
|
||||
}
|
||||
}
|
||||
setServerId(serverId);
|
||||
lastId = serverId;
|
||||
break;
|
||||
}
|
||||
case ItemTypeAttrClientId: {
|
||||
|
@ -67,10 +71,6 @@ void ItemType::unserialize(const BinaryTreePtr& node)
|
|||
setName(node->getString(len));
|
||||
break;
|
||||
}
|
||||
case ItemTypeAttrDesc: {
|
||||
setDesc(node->getString());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
node->skip(len); // skip attribute
|
||||
break;
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#include <framework/luaengine/luaobject.h>
|
||||
#include <framework/xml/tinyxml.h>
|
||||
|
||||
enum ItemCategory {
|
||||
enum ItemCategory : uint8 {
|
||||
ItemCategoryInvalid = 0,
|
||||
ItemCategoryGround = 1,
|
||||
ItemCategoryContainer = 2,
|
||||
|
@ -86,19 +86,23 @@ public:
|
|||
|
||||
void unserialize(const BinaryTreePtr& node);
|
||||
|
||||
void setServerId(uint16 serverId) { m_attribs.set(ItemTypeAttrServerId, serverId); }
|
||||
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); }
|
||||
|
||||
void setCategory(ItemCategory category) { m_category = 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); }
|
||||
|
||||
void setDesc(const std::string& desc) { m_attribs.set(ItemTypeAttrDesc, desc); }
|
||||
std::string getDesc() { return m_attribs.get<std::string>(ItemTypeAttrDesc); }
|
||||
|
||||
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:
|
||||
ItemCategory m_category;
|
||||
stdext::boolean<true> m_null;
|
||||
|
|
|
@ -59,9 +59,11 @@ void OTClient::registerLuaFunctions()
|
|||
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", "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", "findThingTypeByAttr", &ThingTypeManager::findThingTypeByAttr, &g_things);
|
||||
g_lua.bindSingletonFunction("g_things", "findItemTypeByCategory", &ThingTypeManager::findItemTypeByCategory, &g_things);
|
||||
g_lua.bindSingletonFunction("g_things", "castThingToCreature", &ThingTypeManager::castThingToCreature, &g_things);
|
||||
|
||||
#if 0
|
||||
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", "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.bindSingletonFunction("g_game", "loginWorld", &Game::loginWorld, &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>("getMarketData", &ThingType::getMarketData);
|
||||
g_lua.bindClassMemberFunction<ThingType>("getClothSlot", &ThingType::getClothSlot);
|
||||
g_lua.bindClassMemberFunction<ThingType>("getCategory", &ThingType::getCategory);
|
||||
|
||||
g_lua.registerClass<Item, Thing>();
|
||||
g_lua.bindClassStaticFunction<Item>("create", &Item::create);
|
||||
|
|
|
@ -69,7 +69,7 @@ void Map::clean()
|
|||
|
||||
m_towns.clear();
|
||||
m_houses.clear();
|
||||
m_creatures.clear();
|
||||
g_creatures.clear();
|
||||
m_tilesRect = Rect(65534, 65534, 0, 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -187,7 +187,7 @@ public:
|
|||
void saveOtbm(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.)
|
||||
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)); }
|
||||
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 loadSingleCreature(const std::string& file) { m_creatures.loadSingleCreature(file); }
|
||||
void loadNpcs(const std::string& folder) { m_creatures.loadNpcs(folder); }
|
||||
void loadMonsters(const std::string& fileName) { g_creatures.loadMonsters(fileName); }
|
||||
void loadSingleCreature(const std::string& file) { g_creatures.loadSingleCreature(file); }
|
||||
void loadNpcs(const std::string& folder) { g_creatures.loadNpcs(folder); }
|
||||
|
||||
void clean();
|
||||
void cleanDynamicThings();
|
||||
|
@ -234,7 +234,7 @@ public:
|
|||
// town/house/monster related
|
||||
TownPtr getTown(uint32 tid) { return m_towns.getTown(tid); }
|
||||
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 setCentralPosition(const Position& centralPosition);
|
||||
|
@ -273,7 +273,6 @@ private:
|
|||
stdext::packed_storage<uint8> m_attribs;
|
||||
Houses m_houses;
|
||||
Towns m_towns;
|
||||
Creatures m_creatures;
|
||||
static TilePtr m_nulltile;
|
||||
};
|
||||
|
||||
|
|
|
@ -163,7 +163,7 @@ void Map::loadOtbm(const std::string& fileName)
|
|||
|
||||
ItemPtr cItem = Item::createFromOtb(containerItem->getU16());
|
||||
cItem->unserializeItem(containerItem);
|
||||
//item->addContainerItem(cItem);
|
||||
item->addContainerItem(cItem);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,9 +175,12 @@ void Map::loadOtbm(const std::string& fileName)
|
|||
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);
|
||||
}
|
||||
}
|
||||
} else if(mapDataType == OTBM_TOWNS) {
|
||||
TownPtr town = nullptr;
|
||||
for(const BinaryTreePtr &nodeTown : nodeMapData->getChildren()) {
|
||||
|
@ -263,41 +266,40 @@ void Map::saveOtbm(const std::string &fileName)
|
|||
#endif
|
||||
|
||||
fin->addU32(0); // file version
|
||||
BinaryWriteTreePtr root(new BinaryWriteTree(fin));
|
||||
root->startNode(0);
|
||||
fin->startNode(0);
|
||||
{
|
||||
root->writeU32(version);
|
||||
fin->addU32(version);
|
||||
|
||||
Size mapSize = getSize();
|
||||
root->writeU16(mapSize.width());
|
||||
root->writeU16(mapSize.height());
|
||||
fin->addU16(mapSize.width());
|
||||
fin->addU16(mapSize.height());
|
||||
|
||||
root->writeU32(g_things.getOtbMajorVersion());
|
||||
root->writeU32(g_things.getOtbMinorVersion());
|
||||
fin->addU32(g_things.getOtbMajorVersion());
|
||||
fin->addU32(g_things.getOtbMinorVersion());
|
||||
|
||||
root->startNode(OTBM_MAP_DATA);
|
||||
fin->startNode(OTBM_MAP_DATA);
|
||||
{
|
||||
// own description.
|
||||
for(const auto& desc : getDescriptions()) {
|
||||
root->writeU8(OTBM_ATTR_DESCRIPTION);
|
||||
root->writeString(desc);
|
||||
fin->addU8(OTBM_ATTR_DESCRIPTION);
|
||||
fin->addString(desc);
|
||||
}
|
||||
|
||||
// special one
|
||||
root->writeU8(OTBM_ATTR_DESCRIPTION);
|
||||
root->writeString(stdext::format("Saved with %s v%s", g_app.getName(), g_app.getVersion()));
|
||||
fin->addU8(OTBM_ATTR_DESCRIPTION);
|
||||
fin->addString(stdext::format("Saved with %s v%s", g_app.getName(), g_app.getVersion()));
|
||||
|
||||
// spawn file.
|
||||
root->writeU8(OTBM_ATTR_SPAWN_FILE);
|
||||
root->writeString(spawnFile);
|
||||
fin->addU8(OTBM_ATTR_SPAWN_FILE);
|
||||
fin->addString(spawnFile);
|
||||
|
||||
// house file.
|
||||
if(version > 1) {
|
||||
root->writeU8(OTBM_ATTR_HOUSE_FILE);
|
||||
root->writeString(houseFile);
|
||||
fin->addU8(OTBM_ATTR_HOUSE_FILE);
|
||||
fin->addString(houseFile);
|
||||
}
|
||||
|
||||
Position base(-1, -1, -1);
|
||||
Position base(0, 0, 0);
|
||||
bool firstNode = true;
|
||||
|
||||
for(uint8_t z = 0; z <= Otc::MAX_Z; ++z) {
|
||||
|
@ -311,71 +313,72 @@ void Map::saveOtbm(const std::string &fileName)
|
|||
if(!pos.isValid())
|
||||
continue;
|
||||
|
||||
if(pos.x < base.x || pos.x >= base.x + 256 || pos.y < base.y|| pos.y >= base.y + 256 ||
|
||||
pos.z != base.z) {
|
||||
if(pos.x < base.x || pos.x >= base.x + 255
|
||||
|| pos.y < base.y || pos.y >= base.y + 255
|
||||
|| pos.z != base.z) {
|
||||
if(!firstNode)
|
||||
root->endNode(); /// OTBM_TILE_AREA
|
||||
fin->endNode(); /// OTBM_TILE_AREA
|
||||
|
||||
root->startNode(OTBM_TILE_AREA);
|
||||
fin->startNode(OTBM_TILE_AREA);
|
||||
firstNode = false;
|
||||
root->writePos(base = pos & 0xFF00);
|
||||
fin->addPos(base = pos & 0xFF00);
|
||||
}
|
||||
|
||||
uint32 flags = tile->getFlags();
|
||||
|
||||
root->startNode((flags & TILESTATE_HOUSE) == TILESTATE_HOUSE ? OTBM_HOUSETILE : OTBM_TILE);
|
||||
root->writePoint(Point(pos.x, pos.y) & 0xFF);
|
||||
// if(tileNode->getType() == OTBM_HOUSETILE)
|
||||
// tileNode->writeU32(tile->getHouseId());
|
||||
fin->startNode((flags & TILESTATE_HOUSE) == TILESTATE_HOUSE ? OTBM_HOUSETILE : OTBM_TILE);
|
||||
fin->addPoint(Point(pos.x, pos.y) & 0xFF);
|
||||
if((flags & TILESTATE_HOUSE) == TILESTATE_HOUSE)
|
||||
fin->addU32(tile->getHouseId());
|
||||
|
||||
if(flags) {
|
||||
root->writeU8(OTBM_ATTR_TILE_FLAGS);
|
||||
root->writeU32(flags);
|
||||
fin->addU8(OTBM_ATTR_TILE_FLAGS);
|
||||
fin->addU32(flags);
|
||||
}
|
||||
|
||||
for(const ItemPtr& item : tile->getItems()) {
|
||||
if(item->isGround()) {
|
||||
root->writeU8(OTBM_ATTR_ITEM);
|
||||
root->writeU16(item->getId());
|
||||
fin->addU8(OTBM_ATTR_ITEM);
|
||||
fin->addU16(item->getId());
|
||||
continue;
|
||||
}
|
||||
|
||||
item->serializeItem(root);
|
||||
item->serializeItem(fin);
|
||||
}
|
||||
|
||||
root->endNode(); // OTBM_TILE
|
||||
fin->endNode(); // OTBM_TILE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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()) {
|
||||
root->writeU32(town->getId());
|
||||
root->writeString(town->getName());
|
||||
root->writePos(town->getPos());
|
||||
fin->addU32(town->getId());
|
||||
fin->addString(town->getName());
|
||||
fin->addPos(town->getPos());
|
||||
}
|
||||
root->endNode();
|
||||
fin->endNode();
|
||||
|
||||
if(version > 1) {
|
||||
root->startNode(OTBM_WAYPOINTS);
|
||||
fin->startNode(OTBM_WAYPOINTS);
|
||||
for(const auto& it : m_waypoints) {
|
||||
root->writeString(it.second);
|
||||
root->writePos(it.first);
|
||||
fin->addString(it.second);
|
||||
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)
|
||||
{
|
||||
if(!m_creatures.isLoaded())
|
||||
if(!g_creatures.isLoaded())
|
||||
stdext::throw_exception("cannot load spawns; monsters/nps aren't loaded.");
|
||||
|
||||
TiXmlDocument doc;
|
||||
|
@ -401,7 +404,7 @@ void Map::loadSpawns(const std::string &fileName)
|
|||
stdext::tolower(cName);
|
||||
stdext::trim(cName);
|
||||
|
||||
if (!(cType = m_creatures.getCreature(cName)))
|
||||
if (!(cType = g_creatures.getCreatureByName(cName)))
|
||||
continue;
|
||||
|
||||
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)
|
||||
{
|
||||
try {
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
#include "thing.h"
|
||||
#include "thingtype.h"
|
||||
#include "itemtype.h"
|
||||
#include "creature.h"
|
||||
#include "creatures.h"
|
||||
|
||||
#include <framework/core/resourcemanager.h>
|
||||
#include <framework/core/filestream.h>
|
||||
|
@ -125,7 +127,9 @@ void ThingTypeManager::loadOtb(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;
|
||||
doc.Parse(g_resources.loadFile(file).c_str());
|
||||
if(doc.Error())
|
||||
|
@ -140,19 +144,27 @@ void ThingTypeManager::loadXml(const std::string& file)
|
|||
continue;
|
||||
|
||||
uint16 id = element->readType<uint16>("id");
|
||||
if(id > 20000 && id < 20100) {
|
||||
id -= 20000;
|
||||
ItemTypePtr newType(new ItemType);
|
||||
newType->setServerId(id);
|
||||
addItemType(newType);
|
||||
if(id != 0) {
|
||||
std::vector<std::string> s_ids = stdext::split(element->Attribute("id"), ";");
|
||||
for(const std::string& s : s_ids) {
|
||||
std::vector<int32> ids = stdext::split<int32>(s, "-");
|
||||
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)
|
||||
{
|
||||
uint16 serverId = id;
|
||||
ItemTypePtr itemType = nullptr;
|
||||
if(serverId > 20000 && id < 20100) {
|
||||
serverId -= 20000;
|
||||
|
||||
ItemTypePtr newType(new ItemType);
|
||||
newType->setServerId(serverId);
|
||||
addItemType(newType);
|
||||
itemType = ItemTypePtr(new ItemType);
|
||||
itemType->setServerId(serverId);
|
||||
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"));
|
||||
for(TiXmlElement* attrib = elem->FirstChildElement(); attrib; attrib = attrib->NextSiblingElement()) {
|
||||
if(attrib->ValueStr() != "attribute")
|
||||
break;
|
||||
std::string key = attrib->Attribute("key");
|
||||
if(key.empty())
|
||||
continue;
|
||||
|
||||
if(attrib->Attribute("key") == "description") {
|
||||
stdext::tolower(key);
|
||||
if(key == "description")
|
||||
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();
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -217,13 +259,36 @@ const ThingTypePtr& ThingTypeManager::getThingType(uint16 id, ThingCategory cate
|
|||
|
||||
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));
|
||||
return m_nullItemType;
|
||||
}
|
||||
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 ret;
|
||||
|
|
|
@ -50,6 +50,7 @@ public:
|
|||
const ItemTypePtr& getItemType(uint16 id);
|
||||
ThingType* rawGetThingType(uint16 id, ThingCategory category) { return m_thingTypes[category][id].get(); }
|
||||
ItemType* rawGetItemType(uint16 id) { return m_itemTypes[id].get(); }
|
||||
CreaturePtr castThingToCreature(const ThingTypePtr& thing);
|
||||
|
||||
ThingTypeList findThingTypeByAttr(ThingAttr attr, ThingCategory category);
|
||||
ItemTypeList findItemTypeByCategory(ItemCategory category);
|
||||
|
|
|
@ -109,7 +109,7 @@ public:
|
|||
void setFlags(tileflags_t flags) { m_flags |= (uint32)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; }
|
||||
|
||||
TilePtr asTile() { return static_self_cast<Tile>(); }
|
||||
|
|
Loading…
Reference in New Issue