diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/game-server/actor.h | 3 | ||||
-rw-r--r-- | src/game-server/itemmanager.h | 3 | ||||
-rw-r--r-- | src/game-server/main-game.cpp | 8 | ||||
-rw-r--r-- | src/game-server/monstermanager.h | 7 | ||||
-rw-r--r-- | src/game-server/skillmanager.cpp | 241 | ||||
-rw-r--r-- | src/game-server/skillmanager.h | 55 | ||||
-rw-r--r-- | src/game-server/trigger.cpp | 11 | ||||
-rw-r--r-- | src/scripting/lua.cpp | 48 | ||||
-rw-r--r-- | src/scripting/luautil.cpp | 11 | ||||
-rw-r--r-- | src/scripting/luautil.h | 2 | ||||
-rw-r--r-- | src/utils/point.h | 4 |
11 files changed, 240 insertions, 153 deletions
diff --git a/src/game-server/actor.h b/src/game-server/actor.h index 529d48c4..abc1e1d0 100644 --- a/src/game-server/actor.h +++ b/src/game-server/actor.h @@ -111,6 +111,9 @@ class Actor : public Thing void setPublicID(int id) { mPublicID = id; } + bool isPublicIdValid() const + { return (mPublicID > 0 && mPublicID != 65535); } + /** * Gets the way the actor blocks pathfinding for other actors. */ diff --git a/src/game-server/itemmanager.h b/src/game-server/itemmanager.h index 9eee326e..cc4fb0ae 100644 --- a/src/game-server/itemmanager.h +++ b/src/game-server/itemmanager.h @@ -58,6 +58,9 @@ class ItemManager mItemDatabaseVersion(0) {} + ~ItemManager() + { deinitialize(); } + /** * Loads item reference file. */ diff --git a/src/game-server/main-game.cpp b/src/game-server/main-game.cpp index 0b786555..529e0690 100644 --- a/src/game-server/main-game.cpp +++ b/src/game-server/main-game.cpp @@ -88,6 +88,7 @@ utils::StringFilter *stringFilter; /**< Slang's Filter */ AttributeManager *attributeManager = new AttributeManager(DEFAULT_ATTRIBUTEDB_FILE); ItemManager *itemManager = new ItemManager(DEFAULT_ITEMSDB_FILE, DEFAULT_EQUIPDB_FILE); MonsterManager *monsterManager = new MonsterManager(DEFAULT_MONSTERSDB_FILE); +SkillManager *skillManager = new SkillManager(DEFAULT_SKILLSDB_FILE); /** Core game message handler */ GameHandler *gameHandler; @@ -193,7 +194,7 @@ static void initializeServer() exit(EXIT_MAP_FILE_NOT_FOUND); } attributeManager->initialize(); - SkillManager::initialize(DEFAULT_SKILLSDB_FILE); + skillManager->initialize(); itemManager->initialize(); monsterManager->initialize(); StatusManager::initialize(DEFAULT_STATUSDB_FILE); @@ -248,8 +249,9 @@ static void deinitializeServer() // Destroy Managers delete stringFilter; - monsterManager->deinitialize(); - itemManager->deinitialize(); + delete monsterManager; monsterManager = 0; + delete itemManager; itemManager = 0; + delete skillManager; skillManager = 0; MapManager::deinitialize(); StatusManager::deinitialize(); diff --git a/src/game-server/monstermanager.h b/src/game-server/monstermanager.h index f04a5733..07ebb58f 100644 --- a/src/game-server/monstermanager.h +++ b/src/game-server/monstermanager.h @@ -30,8 +30,13 @@ class MonsterClass; class MonsterManager { public: + MonsterManager(const std::string &file): + mMonsterReferenceFile(file) + {} + + ~MonsterManager() + { deinitialize(); } - MonsterManager(const std::string &file) : mMonsterReferenceFile(file) {} /** * Loads monster reference file. */ diff --git a/src/game-server/skillmanager.cpp b/src/game-server/skillmanager.cpp index 75f5f53c..66d9b939 100644 --- a/src/game-server/skillmanager.cpp +++ b/src/game-server/skillmanager.cpp @@ -20,174 +20,169 @@ #include "game-server/skillmanager.h" -#include "utils/string.h" // for the toUpper function #include "utils/logger.h" -#include "utils/xml.h" #include <map> -typedef std::map< std::string, int > SkillMap; -static SkillMap skillMap; -static std::string skillReferenceFile; -static std::string defaultSkillKey = std::string(); - -void SkillManager::initialize(const std::string &file) +void SkillManager::clear() { - skillReferenceFile = file; - reload(); + for (SkillsInfo::iterator it = mSkillsInfo.begin(), + it_end = mSkillsInfo.end(); it != it_end; ++it) + { + delete it->second; + } + + mSkillsInfo.clear(); + mNamedSkillsInfo.clear(); } -void SkillManager::reload() +void SkillManager::initialize() { - /* - skillMap["UNARMED"] = 100; - skillMap["KNIFE"] = 101; - */ + clear(); - XML::Document doc(skillReferenceFile); + XML::Document doc(mSkillFile); xmlNodePtr rootNode = doc.rootNode(); if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "skills")) { - LOG_ERROR("Skill Manager: " << skillReferenceFile + LOG_ERROR("Skill Manager: " << mSkillFile << " is not a valid database file!"); return; } - LOG_INFO("Loading skill reference: " << skillReferenceFile); + LOG_INFO("Loading skill reference: " << mSkillFile); - for_each_xml_child_node(setnode, rootNode) + for_each_xml_child_node(setNode, rootNode) { - if (!xmlStrEqual(setnode->name, BAD_CAST "set")) + // The server will prefix the core name with the set, so we need one. + if (!xmlStrEqual(setNode->name, BAD_CAST "set")) continue; - // we don't care about sets server-sided (yet?) - for_each_xml_child_node(skillnode, setnode) + std::string setName = XML::getProperty(setNode, "name", std::string()); + if (setName.empty()) { - if (xmlStrEqual(skillnode->name, BAD_CAST "skill")) - { - std::string name = XML::getProperty(skillnode, "name", - std::string()); - name = utils::toUpper(name); - int id = XML::getProperty(skillnode, "id", 0); - if (id > 0 && !name.empty()) - { - bool duplicateKey = false; - for (SkillMap::iterator i = skillMap.begin(); - i != skillMap.end(); i++) - { - if (id == i->second) - { - LOG_ERROR("SkillManager: The same id: " << id - << " is given for skill names: " << i->first - << " and " << name); - LOG_ERROR("The skill reference: " << "'" << name - << "': " << id << " will be ignored."); - - duplicateKey = true; - break; - } - } - - if (!duplicateKey) - { - if (XML::getBoolProperty(skillnode, "default", false)) - { - if (!defaultSkillKey.empty()) - { - LOG_WARN("SkillManager: " - "Default Skill Key already defined as " - << defaultSkillKey - << ". Redefinit it as: " << name); - } - else - { - LOG_INFO("SkillManager: Defining " << name - << " as default weapon-type key."); - } - defaultSkillKey = name; - } - skillMap[name] = id; - } - } - } + LOG_WARN("The " << mSkillFile << " file is containing unamed <set> " + "tags and will be ignored."); + continue; } + + setName = utils::toLower(setName); + + for_each_xml_child_node(skillNode, setNode) + readSkillNode(skillNode, setName); } - if (::utils::Logger::mVerbosity >= ::utils::Logger::Debug) + printDebugSkillTable(); + + if (!mDefaultSkillId) + LOG_WARN("SkillManager: No default weapon-type id was given during " + "Skill map loading. " + "Players won't be able to earn XP when unarmed."); + + LOG_INFO("Loaded " << mSkillsInfo.size() << " skills from " + << mSkillFile); +} + +void SkillManager::readSkillNode(xmlNodePtr skillNode, + const std::string& setName) +{ + if (!xmlStrEqual(skillNode->name, BAD_CAST "skill")) + return; + + SkillInfo *skillInfo = new SkillInfo; + skillInfo->setName = setName; + skillInfo->skillName = XML::getProperty(skillNode, "name", std::string()); + skillInfo->skillName = utils::toLower(skillInfo->skillName); + int id = XML::getProperty(skillNode, "id", 0); + + if (id <= 0 || skillInfo->skillName.empty()) { - LOG_DEBUG("Skill map in " << skillReferenceFile << ":" - << std::endl << "-----"); - for (SkillMap::iterator i = skillMap.begin(); i != skillMap.end(); i++) + LOG_WARN("Invalid skill (empty name or id <= 0) in set: " << setName); + return; + } + skillInfo->id = (unsigned)id; + + SkillsInfo::iterator it = mSkillsInfo.find(skillInfo->id); + if (it != mSkillsInfo.end()) + { + LOG_WARN("SkillManager: The same id: " << skillInfo->id + << " is given for skill names: " << it->first + << " and " << skillInfo->skillName); + LOG_WARN("The skill reference: " << skillInfo->id + << ": '" << skillInfo->skillName << "' will be ignored."); + return; + } + + if (XML::getBoolProperty(skillNode, "default", false)) + { + if (mDefaultSkillId) { - if (!defaultSkillKey.compare(i->first)) - { - LOG_DEBUG("'" << i->first << "': " << i->second - << " (Default)"); - } - else - { - LOG_DEBUG("'" << i->first << "': " << i->second); - } + LOG_WARN("SkillManager: " + "Default Skill id already defined as " + << mDefaultSkillId + << ". Redefinit it as: " << skillInfo->id); } - LOG_DEBUG("-----"); + else + { + LOG_INFO("SkillManager: Defining skill id: " << skillInfo->id + << " as default weapon-type id."); + } + mDefaultSkillId = skillInfo->id; } - if (defaultSkillKey.empty()) - LOG_WARN("SkillManager: No default weapon-type id was given during " - "Skill map loading. Defaults will fall back to id 0."); + mSkillsInfo.insert( + std::make_pair<unsigned int, SkillInfo*>(skillInfo->id, skillInfo)); - LOG_INFO("Loaded " << skillMap.size() << " skill references from " - << skillReferenceFile); + std::string keyName = setName + "_" + skillInfo->skillName; + mNamedSkillsInfo.insert(keyName, skillInfo); } -int SkillManager::getIdFromString(const std::string &name) +void SkillManager::printDebugSkillTable() { - // Check if the name is an integer value. - if (utils::isNumeric(name)) + if (::utils::Logger::mVerbosity >= ::utils::Logger::Debug) { - int val = 0; - val = utils::stringToInt(name); - if (val) + std::string lastSet; + LOG_DEBUG("Skill map in " << mSkillFile << ":" + << std::endl << "-----"); + for (SkillsInfo::iterator it = mSkillsInfo.begin(); + it != mSkillsInfo.end(); ++it) { - for (SkillMap::iterator i = skillMap.begin(); i != skillMap.end(); i++) + if (!lastSet.compare(it->second->setName)) { - if (i->second == val) - return val; + lastSet = it->second->setName; + LOG_DEBUG("Skill set: " << lastSet); } - LOG_WARN("SkillManager::getIdFromString(): Numeric weapon-type id " - << val << " not found into " << skillReferenceFile); - SkillMap::iterator i = skillMap.find(defaultSkillKey); - if (i != skillMap.end()) + if (it->first == mDefaultSkillId) { - LOG_WARN("Id defaulted to " << defaultSkillKey << ": " - << i->second); - return i->second; + LOG_DEBUG("'" << it->first << "': " << it->second->skillName + << " (Default)"); } else { - LOG_WARN("Id defaulted to 0."); - return 0; + LOG_DEBUG("'" << it->first << "': " << it->second->skillName); } } - else - { - LOG_WARN("SkillManager: Invalid skill id " << name); - return 0; - } + LOG_DEBUG("-----"); } +} - // Convert to upper case for easier finding - SkillMap::iterator i = skillMap.find(utils::toUpper(name)); - if (i == skillMap.end()) - { - LOG_WARN("SkillManager: No weapon-type name corresponding to " - << utils::toUpper(name) << " into " << skillReferenceFile); - return 0; - } - else - { - return i->second; - } +unsigned int SkillManager::getId(const std::string& set, + const std::string &name) const +{ + std::string key = utils::toLower(set) + "_" + utils::toLower(name); + SkillInfo *skillInfo = mNamedSkillsInfo.find(key); + return skillInfo ? skillInfo->id : 0; +} + +const std::string SkillManager::getSkillName(unsigned int id) const +{ + SkillsInfo::const_iterator it = mSkillsInfo.find(id); + return it != mSkillsInfo.end() ? it->second->skillName : ""; +} + +const std::string SkillManager::getSetName(unsigned int id) const +{ + SkillsInfo::const_iterator it = mSkillsInfo.find(id); + return it != mSkillsInfo.end() ? it->second->setName : ""; } diff --git a/src/game-server/skillmanager.h b/src/game-server/skillmanager.h index c6a73a5c..1912e2fc 100644 --- a/src/game-server/skillmanager.h +++ b/src/game-server/skillmanager.h @@ -22,14 +22,24 @@ #ifndef SKILLMANAGER_H #define SKILLMANAGER_H -#include <string> +#include "utils/string.h" +#include "utils/xml.h" -namespace SkillManager +class SkillManager { + public: + SkillManager(const std::string & skillFile): + mSkillFile(skillFile), + mDefaultSkillId(0) + {} + + ~SkillManager() + { clear(); } + /** * Loads skill reference file. */ - void initialize(const std::string &); + void initialize(); /** * Reloads skill reference file. @@ -37,12 +47,43 @@ namespace SkillManager void reload(); /** - * Gets the skill ID of a skill string - * (not case-sensitive to reduce wall-bashing) + * Gets the skill Id from a set and a skill string. */ - int getIdFromString(const std::string &name); -} + unsigned int getId(const std::string& set, const std::string &name) const; + const std::string getSkillName(unsigned int id) const; + const std::string getSetName(unsigned int id) const; + + private: + struct SkillInfo { + SkillInfo(): + id(0) + {} + + unsigned int id; + std::string setName; + std::string skillName; + }; + + /* + * Clears up the skill maps. + */ + void clear(); + + void readSkillNode(xmlNodePtr skillNode, const std::string& setName); + + void printDebugSkillTable(); + + // The skill file (skills.xml) + std::string mSkillFile; + // The skill map + typedef std::map<unsigned int, SkillInfo*> SkillsInfo; + SkillsInfo mSkillsInfo; + // A map used to get skills per name. + utils::NameMap<SkillInfo*> mNamedSkillsInfo; + // The default skill id + unsigned int mDefaultSkillId; +}; #endif // SKILLMANAGER_H diff --git a/src/game-server/trigger.cpp b/src/game-server/trigger.cpp index f25b00b8..c4cec2f4 100644 --- a/src/game-server/trigger.cpp +++ b/src/game-server/trigger.cpp @@ -52,10 +52,15 @@ void TriggerArea::update() std::set<Actor*> insideNow; for (BeingIterator i(getMap()->getInsideRectangleIterator(mZone)); i; ++i) { - //skip garbage - if (!(*i) || (*i)->getPublicID() == 0) continue; + // Don't deal with unitialized actors. + if (!(*i) || !(*i)->isPublicIdValid()) + continue; - if (mZone.contains((*i)->getPosition())) //<-- Why is this additional condition necessary? Shouldn't getInsideRectangleIterator already exclude those outside of the zone? --Crush + // The BeingIterator returns the mapZones in touch with the rectangle + // area. On the other hand, the beings contained in the map zones + // may not be within the rectangle area. Hence, this additional + // contains() condition. + if (mZone.contains((*i)->getPosition())) { insideNow.insert(*i); diff --git a/src/scripting/lua.cpp b/src/scripting/lua.cpp index 2ea2187c..75a8ca2c 100644 --- a/src/scripting/lua.cpp +++ b/src/scripting/lua.cpp @@ -206,10 +206,7 @@ static int npc_create(lua_State *s) } q->setMap(m); q->setPosition(Point(x, y)); - bool b = GameState::insert(q); - /* Do not try to deal with a failure there. There are some serious issues - if an insertion failed on an almost empty map. */ - assert(b); (void)b; + GameState::enqueueInsert(q); lua_pushlightuserdata(s, q); return 1; } @@ -299,7 +296,7 @@ static int chr_warp(lua_State *s) Character *q = getCharacter(s, 1); bool b = lua_isnil(s, 2); - if (!q || !(b || lua_isnumber(s, 2))) + if (!q || !(b || lua_isnumber(s, 2) || lua_isstring(s, 2))) { raiseScriptError(s, "chr_warp called with incorrect parameters."); return 0; @@ -312,10 +309,14 @@ static int chr_warp(lua_State *s) Script *t = static_cast<Script *>(lua_touserdata(s, -1)); m = t->getMap(); } - else + else if (lua_isnumber(s, 2)) { m = MapManager::getMap(lua_tointeger(s, 2)); } + else + { + m = MapManager::getMap(lua_tostring(s, 2)); + } if (!m) { raiseScriptError(s, "chr_warp called with a non-existing map."); @@ -1125,20 +1126,38 @@ static int monster_get_name(lua_State *s) } /** + * mana.monster_change_anger(Monster*, Being*, int anger) + * Makes a monster angry at a being + */ +static int monster_change_anger(lua_State *s) +{ + const int anger = luaL_checkint(s, 3); + Monster *m = getMonster(s, 1); + if (!m) + { + raiseScriptError(s, "monster_change_anger called " + "for a nonexisting monster"); + return 0; + } + Being *being = getBeing(s, 2); + if (!being) + { + raiseScriptError(s, "monster_change_anger called " + "for a nonexisting being"); + } + m->changeAnger(being, anger); + return 0; +} + +/** * mana.monster_remove(Monster*): bool success * Remove a monster object without kill event. * return whether the monster was enqueued for removal. */ static int monster_remove(lua_State *s) { - if (!lua_islightuserdata(s, 1)) - { - lua_pushboolean(s, false); - return 1; - } - bool monsterEnqueued = false; - Monster *m = dynamic_cast<Monster *>((Thing *)lua_touserdata(s, 1)); + Monster *m = getMonster(s, 1); if (m) { GameState::enqueueRemove(m); @@ -1154,7 +1173,7 @@ static int monster_remove(lua_State *s) */ static int monster_load_script(lua_State *s) { - Monster *m = static_cast< Monster* >(getBeing(s, 1)); + Monster *m = getMonster(s, 1); if (!m) { raiseScriptError(s, "monster_load_script called " @@ -2148,6 +2167,7 @@ LuaScript::LuaScript(): { "exp_for_level", &exp_for_level }, { "monster_create", &monster_create }, { "monster_get_name", &monster_get_name }, + { "monster_change_anger", &monster_change_anger }, { "monster_remove", &monster_remove }, { "monster_load_script", &monster_load_script }, { "being_apply_status", &being_apply_status }, diff --git a/src/scripting/luautil.cpp b/src/scripting/luautil.cpp index 4a5bee9a..b7680c6b 100644 --- a/src/scripting/luautil.cpp +++ b/src/scripting/luautil.cpp @@ -23,6 +23,7 @@ #include "game-server/character.h" #include "game-server/npc.h" +#include "game-server/monster.h" #include "utils/logger.h" @@ -78,6 +79,16 @@ Character *getCharacter(lua_State *s, int p) return static_cast<Character *>(t); } +Monster *getMonster(lua_State *s, int p) +{ + if (!lua_islightuserdata(s, p)) + return 0; + Thing *t = static_cast<Thing *>(lua_touserdata(s, p)); + if (t->getType() != OBJECT_MONSTER) + return 0; + return static_cast<Monster *>(t); +} + Being *getBeing(lua_State *s, int p) { if (!lua_islightuserdata(s, p)) diff --git a/src/scripting/luautil.h b/src/scripting/luautil.h index 87185155..c55b04b7 100644 --- a/src/scripting/luautil.h +++ b/src/scripting/luautil.h @@ -34,6 +34,7 @@ extern "C" { class Being; class NPC; class Character; +class Monster; class Thing; // Report script errors and interrupt the script. @@ -43,6 +44,7 @@ void raiseWarning(lua_State *s, const char *format, ...); NPC *getNPC(lua_State *s, int p); Character *getCharacter(lua_State *s, int p); +Monster *getMonster(lua_State *s, int p); Being *getBeing(lua_State *s, int p); diff --git a/src/utils/point.h b/src/utils/point.h index 4402aa09..ccd3d2c6 100644 --- a/src/utils/point.h +++ b/src/utils/point.h @@ -75,8 +75,8 @@ class Rectangle bool contains(const Point &p) const { - return (p.x - x) < w && - (p.y - y) < h; + return (p.x >= x && p.x <= x + w && + p.y >= y && p.y <= y + h); } bool intersects(const Rectangle &r) const |