diff options
-rw-r--r-- | src/game-server/map.cpp | 10 | ||||
-rw-r--r-- | src/game-server/map.h | 60 | ||||
-rw-r--r-- | src/game-server/mapreader.cpp | 208 | ||||
-rw-r--r-- | src/scripting/lua.cpp | 131 | ||||
-rw-r--r-- | src/scripting/luautil.cpp | 5 | ||||
-rw-r--r-- | src/scripting/luautil.h | 5 |
6 files changed, 264 insertions, 155 deletions
diff --git a/src/game-server/map.cpp b/src/game-server/map.cpp index b824aaac..e372f03d 100644 --- a/src/game-server/map.cpp +++ b/src/game-server/map.cpp @@ -96,7 +96,6 @@ class Location int Fcost; /**< Estimation of total path cost */ }; - Map::Map(int width, int height, int tileWidth, int tileHeight): mWidth(width), mHeight(height), mTileWidth(tileWidth), mTileHeight(tileHeight), @@ -104,6 +103,15 @@ Map::Map(int width, int height, int tileWidth, int tileHeight): { } +Map::~Map() +{ + for (std::vector<MapObject*>::iterator it = mMapObjects.begin(); + it != mMapObjects.end(); ++it) + { + delete *it; + } +} + void Map::setSize(int width, int height) { mWidth = width; diff --git a/src/game-server/map.h b/src/game-server/map.h index 7c58d005..f1180a77 100644 --- a/src/game-server/map.h +++ b/src/game-server/map.h @@ -26,11 +26,12 @@ #include <string> #include <vector> +#include "utils/logger.h" #include "utils/point.h" +#include "utils/string.h" typedef std::list<Point> Path; typedef Path::iterator PathIterator; - enum BlockType { BLOCKTYPE_NONE = -1, @@ -59,6 +60,46 @@ class MetaTile char blockmask; /**< walkability bitfield */ }; +class MapObject +{ + public: + MapObject(const Rectangle &bounds, + const std::string &name, + const std::string &type) + : mBounds(bounds), + mName(name), + mType(type) + { } + + void addProperty(const std::string &key, const std::string &value) + { + if (mProperties.contains(key)) + LOG_WARN("Duplicate property " << key << + " of object " << mName); + else + mProperties.insert(key, value); + } + + std::string getProperty(const std::string &key) const + { return mProperties.find(key); } + + const std::string &getName() const + { return mName; } + + const std::string &getType() const + { return mType; } + + const Rectangle &getBounds() const + { return mBounds; } + + private: + Rectangle mBounds; + std::string mName; + std::string mType; + utils::NameMap<std::string> mProperties; +}; + + /** * A tile map. */ @@ -71,6 +112,8 @@ class Map Map(int width, int height, int tileWidth, int tileHeight); + ~Map(); + /** * Sets the size of the map. This will destroy any existing map data. */ @@ -129,9 +172,21 @@ class Map /** * Sets a map property */ - void setProperty(const std::string& key, const std::string& val) + void setProperty(const std::string &key, const std::string &val) { mProperties[key] = val; } + /** + * Adds an object. + */ + void addObject(MapObject *object) + { mMapObjects.push_back(object); } + + /** + * Returns the objects of the map. + */ + const std::vector<MapObject*> &getObjects() const + { return mMapObjects; } + /** * Find a path from one location to the next. */ @@ -154,6 +209,7 @@ class Map std::map<std::string, std::string> mProperties; std::vector<MetaTile> mMetaTiles; + std::vector<MapObject*> mMapObjects; }; #endif diff --git a/src/game-server/mapreader.cpp b/src/game-server/mapreader.cpp index 8438c82c..e82fa10a 100644 --- a/src/game-server/mapreader.cpp +++ b/src/game-server/mapreader.cpp @@ -141,54 +141,44 @@ Map* MapReader::readMap(xmlNodePtr node, const std::string &path, int objH = XML::getProperty(objectNode, "height", 0); Rectangle rect = { objX, objY, objW, objH }; + MapObject *newObject = new MapObject(rect, objName, objType); - if (utils::compareStrI(objType, "WARP") == 0) + for_each_xml_child_node(propertiesNode, objectNode) { - std::string destMapName = std::string(); - int destX = -1; - int destY = -1; - - for_each_xml_child_node(propertiesNode, objectNode) + if (!xmlStrEqual(propertiesNode->name, BAD_CAST "properties")) { - if (!xmlStrEqual(propertiesNode->name, BAD_CAST "properties")) - { - continue; - } - - for_each_xml_child_node(propertyNode, propertiesNode) + continue; + } + + for_each_xml_child_node(propertyNode, propertiesNode) + { + if (xmlStrEqual(propertyNode->name, BAD_CAST "property")) { - if (xmlStrEqual(propertyNode->name, - BAD_CAST "property")) - { - std::string value = XML::getProperty( - propertyNode, "name", std::string()); - value = utils::toUpper(value); - if (utils::compareStrI(value, "DEST_MAP") == 0) - { - destMapName = getObjectProperty(propertyNode, + std::string key = XML::getProperty( + propertyNode, "name", std::string()); + std::string value = getObjectProperty(propertyNode, std::string()); - } - else if (utils::compareStrI(value, "DEST_X") == 0) - { - destX = getObjectProperty(propertyNode, -1); - } - else if (utils::compareStrI(value, "DEST_Y") == 0) - { - destY = getObjectProperty(propertyNode, -1); - } - } + newObject->addProperty(key, value); } } + } - if (!destMapName.empty() && destX != -1 && destY != -1) + if (utils::compareStrI(objType, "WARP") == 0) + { + std::string destMapName = newObject->getProperty("DEST_MAP"); + int destX = utils::stringToInt( + newObject->getProperty("DEST_X")); + int destY = utils::stringToInt( + newObject->getProperty("DEST_Y")); + + if (!destMapName.empty() && destX && destY) { MapComposite *destMap = MapManager::getMap(destMapName); if (destMap) { things.push_back(new TriggerArea( composite, rect, - new WarpAction(destMap, destX, destY), - false)); + new WarpAction(destMap, destX, destY), false)); } } else @@ -199,71 +189,36 @@ Map* MapReader::readMap(xmlNodePtr node, const std::string &path, else if (utils::compareStrI(objType, "SPAWN") == 0) { MonsterClass *monster = 0; - int maxBeings = 10; // Default value - int spawnRate = 10; // Default value - - for_each_xml_child_node(propertiesNode, objectNode) + int maxBeings = utils::stringToInt( + newObject->getProperty("MAX_BEINGS")); + int spawnRate = utils::stringToInt( + newObject->getProperty("SPAWN_RATE")); + std::string monsterName = + newObject->getProperty("MONSTER_ID"); + int monsterId = utils::stringToInt(monsterName); + if (monsterId) { - if (!xmlStrEqual(propertiesNode->name, BAD_CAST "properties")) + monster = monsterManager->getMonster( + monsterId); + if (!monster) { - continue; + LOG_WARN("Couldn't find monster ID " + << monsterId << + " for spawn area"); } - - for_each_xml_child_node(propertyNode, propertiesNode) + } + else + { + monster = monsterManager-> + getMonsterByName(monsterName); + if (!monster) { - if (xmlStrEqual(propertyNode->name, BAD_CAST "property")) - { - std::string value = XML::getProperty( - propertyNode, - "name", - std::string()); - value = utils::toUpper(value); - if (utils::compareStrI(value, "MONSTER_ID") == 0) - { - std::string monsterName = - getObjectProperty(propertyNode, - std::string()); - int monsterId = utils::stringToInt(monsterName); - if (monsterId) - { - monster = monsterManager->getMonster( - monsterId); - if (!monster) - { - LOG_WARN("Couldn't find monster ID " - << monsterId << - " for spawn area"); - } - } - else - { - monster = monsterManager-> - getMonsterByName(monsterName); - if (!monster) - { - LOG_WARN("Couldn't find monster " - << monsterName << - " for spawn area"); - } - } - } - else if (utils::compareStrI(value, - "MAX_BEINGS") == 0) - { - maxBeings = getObjectProperty(propertyNode, - maxBeings); - } - else if (utils::compareStrI(value, - "SPAWN_RATE") == 0) - { - spawnRate = getObjectProperty(propertyNode, - spawnRate); - } - } + LOG_WARN("Couldn't find monster " + << monsterName << + " for spawn area"); } } - - if (monster) + if (monster && maxBeings && spawnRate) { things.push_back(new SpawnArea(composite, monster, rect, maxBeings, spawnRate)); @@ -279,35 +234,11 @@ Map* MapReader::readMap(xmlNodePtr node, const std::string &path, composite->setScript(s); } - int npcId = -1; - std::string scriptText; + int npcId = utils::stringToInt( + newObject->getProperty("NPC_ID")); + std::string scriptText = newObject->getProperty("SCRIPT"); - for_each_xml_child_node(propertiesNode, objectNode) - { - if (!xmlStrEqual(propertiesNode->name, BAD_CAST "properties")) - { - continue; - } - - for_each_xml_child_node(propertyNode, propertiesNode) - { - if (xmlStrEqual(propertyNode->name, BAD_CAST "property")) - { - std::string value = XML::getProperty(propertyNode, "name", std::string()); - value = utils::toUpper(value); - if (utils::compareStrI(value, "NPC_ID") == 0) - { - npcId = getObjectProperty(propertyNode, npcId); - } - else if (utils::compareStrI(value, "SCRIPT") == 0) - { - scriptText = getObjectProperty(propertyNode, std::string()); - } - } - } - } - - if (npcId != -1 && !scriptText.empty()) + if (npcId && !scriptText.empty()) { s->loadNPC(objName, npcId, objX, objY, scriptText.c_str()); } @@ -326,36 +257,9 @@ Map* MapReader::readMap(xmlNodePtr node, const std::string &path, composite->setScript(s); } - std::string scriptFilename; - std::string scriptText; - - for_each_xml_child_node(propertiesNode, objectNode) - { - if (!xmlStrEqual(propertiesNode->name, BAD_CAST "properties")) - { - continue; - } - - for_each_xml_child_node(propertyNode, propertiesNode) - { - if (xmlStrEqual(propertyNode->name, BAD_CAST "property")) - { - std::string value = XML::getProperty(propertyNode, "name", - std::string()); - value = utils::toUpper(value); - if (utils::compareStrI(value, "FILENAME") == 0) - { - scriptFilename = getObjectProperty(propertyNode, - std::string()); - utils::trim(scriptFilename); - } - else if (utils::compareStrI(value, "TEXT") == 0) - { - scriptText = getObjectProperty(propertyNode, ""); - } - } - } - } + std::string scriptFilename = + newObject->getProperty("FILENAME"); + std::string scriptText = newObject->getProperty("TEXT"); if (!scriptFilename.empty()) { @@ -371,6 +275,8 @@ Map* MapReader::readMap(xmlNodePtr node, const std::string &path, LOG_WARN("Unrecognized format for script"); } } + + map->addObject(newObject); } } } diff --git a/src/scripting/lua.cpp b/src/scripting/lua.cpp index 7213bd09..16781937 100644 --- a/src/scripting/lua.cpp +++ b/src/scripting/lua.cpp @@ -2102,6 +2102,132 @@ static int get_distance(lua_State *s) return 1; } +/** + * mana.map_get_objects(): table of all objects + * mana.map_get_objects(string type): table of all objects of type + * Gets the objects of a map. + */ +static int map_get_objects(lua_State *s) +{ + const bool filtered = (lua_gettop(s) == 1); + std::string filter; + if (filtered) + filter = luaL_checkstring(s, 1); + + lua_pushlightuserdata(s, (void *)®istryKey); + lua_gettable(s, LUA_REGISTRYINDEX); + Script *t = static_cast<Script *>(lua_touserdata(s, -1)); + const std::vector<MapObject*> &objects = t->getMap()->getMap()->getObjects(); + + if (!filtered) + pushSTLContainer<MapObject*>(s, objects); + else + { + std::vector<MapObject*> filteredObjects; + for (std::vector<MapObject*>::const_iterator it = objects.begin(); + it != objects.end(); ++it) + { + if (utils::compareStrI((*it)->getType(), filter) == 0) + { + filteredObjects.push_back(*it); + } + } + pushSTLContainer<MapObject*>(s, filteredObjects); + } + return 1; +} + +/** + * mana.map_object_get_property(handle object, string key) + * Returns the value of the object property 'key'. + */ +static int map_object_get_property(lua_State *s) +{ + std::string key = luaL_checkstring(s, 2); + if (!lua_islightuserdata(s, 1)) + { + raiseScriptError(s, "map_object_get_property called with invalid" + "object handle"); + return 0; + } + MapObject *obj = static_cast<MapObject *>(lua_touserdata(s, 1)); + if (obj) + { + std::string property = obj->getProperty(key); + if (!property.empty()) + { + lua_pushstring(s, property.c_str()); + return 1; + } + else + { + // scripts can check for nil + return 0; + } + } + else + { + raiseScriptError(s, "map_object_get_property called with invalid" + "object handle"); + return 0; + } +} + +/** + * mana.map_object_get_bounds(object) + * Returns 4 int: x/y/width/height of object. + */ +static int map_object_get_bounds(lua_State *s) +{ + if (!lua_islightuserdata(s, 1)) + { + raiseScriptError(s, "map_object_get_bounds called with invalid" + "object handle"); + return 0; + } + MapObject *obj = static_cast<MapObject *>(lua_touserdata(s, 1)); + const Rectangle &bounds = obj->getBounds(); + lua_pushinteger(s, bounds.x); + lua_pushinteger(s, bounds.y); + lua_pushinteger(s, bounds.w); + lua_pushinteger(s, bounds.h); + return 4; +} + +/** + * mana.map_object_get_name(object) + * Returns the name of the object. + */ +static int map_object_get_name(lua_State *s) +{ + if (!lua_islightuserdata(s, 1)) + { + raiseScriptError(s, "map_object_get_name called with invalid" + "object handle"); + return 0; + } + MapObject *obj = static_cast<MapObject *>(lua_touserdata(s, 1)); + lua_pushstring(s, obj->getName().c_str()); + return 1; +} + +/** + * mana.map_object_get_type(object) + * Returns the type of the object. + */ +static int map_object_get_type(lua_State *s) +{ + if (!lua_islightuserdata(s, 1)) + { + raiseScriptError(s, "map_object_get_type called with invalid" + "object handle"); + return 0; + } + MapObject *obj = static_cast<MapObject *>(lua_touserdata(s, 1)); + lua_pushstring(s, obj->getType().c_str()); + return 1; +} + static int require_loader(lua_State *s) { // Add .lua extension (maybe only do this when it doesn't have it already) @@ -2209,6 +2335,11 @@ LuaScript::LuaScript(): { "npc_ask_string", &npc_ask_string }, { "log", &log }, { "get_distance", &get_distance }, + { "map_get_objects", &map_get_objects }, + { "map_object_get_property", &map_object_get_property }, + { "map_object_get_bounds", &map_object_get_bounds }, + { "map_object_get_name", &map_object_get_name }, + { "map_object_get_type", &map_object_get_type }, { NULL, NULL } }; luaL_register(mState, "mana", callbacks); diff --git a/src/scripting/luautil.cpp b/src/scripting/luautil.cpp index b7680c6b..a7521426 100644 --- a/src/scripting/luautil.cpp +++ b/src/scripting/luautil.cpp @@ -116,3 +116,8 @@ void push(lua_State *s, double val) { lua_pushnumber(s, val); } + +void push(lua_State *s, MapObject *val) +{ + lua_pushlightuserdata(s, val); +} diff --git a/src/scripting/luautil.h b/src/scripting/luautil.h index c55b04b7..82bb78cf 100644 --- a/src/scripting/luautil.h +++ b/src/scripting/luautil.h @@ -31,6 +31,8 @@ extern "C" { #include <set> #include <vector> +#include "game-server/map.h" + class Being; class NPC; class Character; @@ -52,8 +54,9 @@ Being *getBeing(lua_State *s, int p); Useful for templates.*/ void push(lua_State *s, int val); void push(lua_State *s, const std::string &val); -void push(lua_State *s, Thing* val); +void push(lua_State *s, Thing *val); void push(lua_State *s, double val); +void push(lua_State *s, MapObject *val); /* Pushes an STL LIST */ |