summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/game-server/actor.h3
-rw-r--r--src/game-server/itemmanager.h3
-rw-r--r--src/game-server/main-game.cpp8
-rw-r--r--src/game-server/monstermanager.h7
-rw-r--r--src/game-server/skillmanager.cpp241
-rw-r--r--src/game-server/skillmanager.h55
-rw-r--r--src/game-server/trigger.cpp11
-rw-r--r--src/scripting/lua.cpp48
-rw-r--r--src/scripting/luautil.cpp11
-rw-r--r--src/scripting/luautil.h2
-rw-r--r--src/utils/point.h4
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