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();
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;
};
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

View File

@ -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) {

View File

@ -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>(); }

View File

@ -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;
}

View File

@ -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

View File

@ -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();

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->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()

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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 {

View File

@ -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;

View File

@ -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);

View File

@ -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>(); }