summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChuck Miller <shadowmil@gmail.com>2009-07-17 14:11:30 -0400
committerChuck Miller <shadowmil@gmail.com>2009-07-17 14:11:30 -0400
commit1923fcab4fc9aefd3eaa97fd9ca9b1c507bb4bcb (patch)
tree9400828ce46de3dd8246f012d78af6bf8f4d744b /src
parent053d2fa151ae209fe15c0a38fddb10abf1f6ad8a (diff)
downloadmanaserv-1923fcab4fc9aefd3eaa97fd9ca9b1c507bb4bcb.tar.gz
manaserv-1923fcab4fc9aefd3eaa97fd9ca9b1c507bb4bcb.tar.bz2
manaserv-1923fcab4fc9aefd3eaa97fd9ca9b1c507bb4bcb.tar.xz
manaserv-1923fcab4fc9aefd3eaa97fd9ca9b1c507bb4bcb.zip
Adds scripted status effects
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am4
-rw-r--r--src/game-server/being.cpp38
-rw-r--r--src/game-server/being.hpp20
-rw-r--r--src/game-server/main-game.cpp4
-rw-r--r--src/game-server/statuseffect.cpp48
-rw-r--r--src/game-server/statuseffect.hpp47
-rw-r--r--src/game-server/statusmanager.cpp141
-rw-r--r--src/game-server/statusmanager.hpp52
-rw-r--r--src/scripting/lua.cpp39
9 files changed, 393 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index d4fdd662..47ce13c8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -137,6 +137,10 @@ tmwserv_game_SOURCES = \
game-server/spawnarea.cpp \
game-server/state.hpp \
game-server/state.cpp \
+ game-server/statuseffect.hpp \
+ game-server/statuseffect.cpp \
+ game-server/statusmanager.hpp \
+ game-server/statusmanager.cpp \
game-server/thing.hpp \
game-server/thing.cpp \
game-server/trade.hpp \
diff --git a/src/game-server/being.cpp b/src/game-server/being.cpp
index bbe3ac91..a68ed1f5 100644
--- a/src/game-server/being.cpp
+++ b/src/game-server/being.cpp
@@ -28,6 +28,8 @@
#include "game-server/eventlistener.hpp"
#include "game-server/mapcomposite.hpp"
#include "game-server/effect.hpp"
+#include "game-server/statuseffect.hpp"
+#include "game-server/statusmanager.hpp"
#include "utils/logger.h"
Being::Being(ThingType type):
@@ -294,6 +296,25 @@ int Being::getModifiedAttribute(int attr) const
return res <= 0 ? 0 : res;
}
+void Being::applyStatusEffect(int id, int timer)
+{
+ Status newStatus;
+ newStatus.status = StatusManager::getStatus(id);
+ newStatus.time = timer;
+ mStatus.push_back(newStatus);
+}
+
+bool Being::hasStatusEffect(int id)
+{
+ StatusEffects::iterator it = mStatus.begin();
+ while (it != mStatus.end())
+ {
+ if (it->status->getId() == id)
+ return true;
+ }
+ return false;
+}
+
void Being::update()
{
int oldHP = getModifiedAttribute(BASE_ATTR_HP);
@@ -333,6 +354,23 @@ void Being::update()
++i;
}
+ // Update and run status effects
+ StatusEffects::iterator it = mStatus.begin();
+ while (it != mStatus.end())
+ {
+ it->time--;
+ if (it->time > 0 && mAction != DEAD)
+ {
+ it->status->tick(this, it->time);
+ }
+ else
+ {
+ it = mStatus.erase(it);
+ continue;
+ }
+ it++;
+ }
+
// Check if being died
if (getModifiedAttribute(BASE_ATTR_HP) <= 0 && mAction != DEAD)
{
diff --git a/src/game-server/being.hpp b/src/game-server/being.hpp
index 89134c7c..5c431503 100644
--- a/src/game-server/being.hpp
+++ b/src/game-server/being.hpp
@@ -32,6 +32,7 @@
class Being;
class MapComposite;
class AttackZone;
+class StatusEffect;
/**
* Beings and actors directions
@@ -69,6 +70,7 @@ struct Damage
std::list<size_t> usedSkills; /**< Skills used by source (needed for exp calculation) */
};
+
/**
* Holds the base value of an attribute and the sum of all its modifiers.
* While base + mod may be negative, the modified attribute is not.
@@ -94,6 +96,13 @@ struct AttributeModifier
unsigned char level;
};
+struct Status
+{
+ StatusEffect *status;
+ unsigned time; // Number of ticks
+};
+
+typedef std::vector< Status > StatusEffects;
typedef std::vector< AttributeModifier > AttributeModifiers;
/**
@@ -270,6 +279,16 @@ class Being : public Actor
*/
virtual void modifiedAttribute(int) {}
+ /**
+ * Sets a statuseffect on this being
+ */
+ void applyStatusEffect(int id, int time);
+
+ /**
+ * Returns true if the being has a status effect
+ */
+ bool hasStatusEffect(int id);
+
/** Gets the name of the being. */
const std::string &getName() const
{ return mName; }
@@ -314,6 +333,7 @@ class Being : public Actor
std::string mName;
Hits mHitsTaken; /**< List of punches taken since last update. */
AttributeModifiers mModifiers; /**< Currently modified attributes. */
+ StatusEffects mStatus;
int mHpRegenTimer; /**< Timer for hp regeneration. */
};
diff --git a/src/game-server/main-game.cpp b/src/game-server/main-game.cpp
index 03c6aa71..12b8c78c 100644
--- a/src/game-server/main-game.cpp
+++ b/src/game-server/main-game.cpp
@@ -35,6 +35,7 @@
#include "game-server/itemmanager.hpp"
#include "game-server/mapmanager.hpp"
#include "game-server/monstermanager.hpp"
+#include "game-server/statusmanager.hpp"
#include "game-server/postman.hpp"
#include "game-server/resourcemanager.hpp"
#include "game-server/state.hpp"
@@ -55,6 +56,7 @@ using utils::Logger;
#define DEFAULT_ITEMSDB_FILE "items.xml"
#define DEFAULT_MAPSDB_FILE "maps.xml"
#define DEFAULT_MONSTERSDB_FILE "monsters.xml"
+#define DEFAULT_STATUSDB_FILE "tmw-status-effect.xml"
utils::Timer worldTimer(100, false); /**< Timer for world tics set to 100 ms */
int worldTime = 0; /**< Current world time in 100ms ticks */
@@ -150,6 +152,7 @@ void initialize()
MapManager::initialize(DEFAULT_MAPSDB_FILE);
ItemManager::initialize(DEFAULT_ITEMSDB_FILE);
MonsterManager::initialize(DEFAULT_MONSTERSDB_FILE);
+ StatusManager::initialize(DEFAULT_STATUSDB_FILE);
// --- Initialize the global handlers
// FIXME: Make the global handlers global vars or part of a bigger
@@ -201,6 +204,7 @@ void deinitialize()
MonsterManager::deinitialize();
ItemManager::deinitialize();
MapManager::deinitialize();
+ StatusManager::deinitialize();
PHYSFS_deinit();
}
diff --git a/src/game-server/statuseffect.cpp b/src/game-server/statuseffect.cpp
new file mode 100644
index 00000000..a8179a17
--- /dev/null
+++ b/src/game-server/statuseffect.cpp
@@ -0,0 +1,48 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "game-server/statuseffect.hpp"
+
+#include "scripting/script.hpp"
+#include "game-server/being.hpp"
+
+StatusEffect::StatusEffect(int id)
+{
+ mId = id;
+ mScript = NULL;
+}
+
+StatusEffect::~StatusEffect()
+{
+ if (mScript) delete mScript;
+}
+
+void StatusEffect::tick(Being *target, int count)
+{
+ if (mScript)
+ {
+ mScript->setMap(target->getMap());
+ mScript->prepare("tick");
+ mScript->push(target);
+ mScript->push(count);
+ mScript->execute();
+ }
+}
diff --git a/src/game-server/statuseffect.hpp b/src/game-server/statuseffect.hpp
new file mode 100644
index 00000000..46af13ce
--- /dev/null
+++ b/src/game-server/statuseffect.hpp
@@ -0,0 +1,47 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _TMW_STATUSEFFECT_H
+#define _TMW_STATUSEFFECT_H
+
+class Script;
+class Being;
+
+class StatusEffect
+{
+ public:
+ StatusEffect(int);
+ ~StatusEffect();
+
+ void tick(Being *target, int count);
+
+ int getId() const
+ { return mId; }
+
+ void setScript(Script *script)
+ { mScript = script; };
+
+ private:
+ int mId;
+ Script *mScript;
+};
+
+#endif
diff --git a/src/game-server/statusmanager.cpp b/src/game-server/statusmanager.cpp
new file mode 100644
index 00000000..ea96a226
--- /dev/null
+++ b/src/game-server/statusmanager.cpp
@@ -0,0 +1,141 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <map>
+#include <set>
+
+#include "game-server/statusmanager.hpp"
+
+#include "defines.h"
+#include "game-server/statuseffect.hpp"
+#include "game-server/resourcemanager.hpp"
+#include "scripting/script.hpp"
+#include "utils/logger.h"
+#include "utils/xml.hpp"
+
+#include <sstream>
+
+typedef std::map< int, StatusEffect * > StatusEffects;
+static StatusEffects statusEffects;
+static std::string statusReferenceFile;
+
+void StatusManager::initialize(const std::string &file)
+{
+ statusReferenceFile = file;
+ reload();
+}
+
+void StatusManager::reload()
+{
+ int size;
+ char *data = ResourceManager::loadFile(statusReferenceFile, size);
+
+ if (!data) {
+ LOG_ERROR("Status Manager: Could not find " << statusReferenceFile << "!");
+ free(data);
+ return;
+ }
+
+ xmlDocPtr doc = xmlParseMemory(data, size);
+ free(data);
+
+ if (!doc)
+ {
+ LOG_ERROR("Status Manager: Error while parsing status database ("
+ << statusReferenceFile << ")!");
+ return;
+ }
+
+ xmlNodePtr node = xmlDocGetRootElement(doc);
+ if (!node || !xmlStrEqual(node->name, BAD_CAST "status-effects"))
+ {
+ LOG_ERROR("Status Manager: " << statusReferenceFile
+ << " is not a valid database file!");
+ xmlFreeDoc(doc);
+ return;
+ }
+
+ LOG_INFO("Loading status reference...");
+ for (node = node->xmlChildrenNode; node != NULL; node = node->next)
+ {
+ if (!xmlStrEqual(node->name, BAD_CAST "status-effect"))
+ {
+ continue;
+ }
+
+ int id = XML::getProperty(node, "id", 0);
+ if (id == 0)
+ {
+ LOG_WARN("Status Manager: An (ignored) Status has no ID in "
+ << statusReferenceFile << "!");
+ continue;
+ }
+
+ std::string scriptFile = XML::getProperty(node, "script", "");
+ //TODO: Get these modifiers
+/*
+ modifiers.setAttributeValue(BASE_ATTR_PHY_ATK_MIN, XML::getProperty(node, "attack-min", 0));
+ modifiers.setAttributeValue(BASE_ATTR_PHY_ATK_DELTA, XML::getProperty(node, "attack-delta", 0));
+ modifiers.setAttributeValue(BASE_ATTR_HP, XML::getProperty(node, "hp", 0));
+ modifiers.setAttributeValue(BASE_ATTR_PHY_RES, XML::getProperty(node, "defense", 0));
+ modifiers.setAttributeValue(CHAR_ATTR_STRENGTH, XML::getProperty(node, "strength", 0));
+ modifiers.setAttributeValue(CHAR_ATTR_AGILITY, XML::getProperty(node, "agility", 0));
+ modifiers.setAttributeValue(CHAR_ATTR_DEXTERITY, XML::getProperty(node, "dexterity", 0));
+ modifiers.setAttributeValue(CHAR_ATTR_VITALITY, XML::getProperty(node, "vitality", 0));
+ modifiers.setAttributeValue(CHAR_ATTR_INTELLIGENCE, XML::getProperty(node, "intelligence", 0));
+ modifiers.setAttributeValue(CHAR_ATTR_WILLPOWER, XML::getProperty(node, "willpower", 0));
+*/
+ StatusEffect *statusEffect = new StatusEffect(id);
+ if (scriptFile != "")
+ {
+ std::stringstream filename;
+ filename << "scripts/status/" << scriptFile;
+ if (ResourceManager::exists(filename.str())) // file exists!
+ {
+ LOG_INFO("Loading status script: " << filename.str());
+ Script *s = Script::create("lua");
+ s->loadFile(filename.str());
+ statusEffect->setScript(s);
+ } else {
+ LOG_WARN("Could not find script file \"" << filename.str() << "\" for status #"<<id);
+ }
+ }
+ statusEffects[id] = statusEffect;
+ }
+
+ xmlFreeDoc(doc);
+}
+
+void StatusManager::deinitialize()
+{
+ for (StatusEffects::iterator i = statusEffects.begin(), i_end = statusEffects.end(); i != i_end; ++i)
+ {
+ delete i->second;
+ }
+ statusEffects.clear();
+}
+
+StatusEffect *StatusManager::getStatus(int statusId)
+{
+ StatusEffects::const_iterator i = statusEffects.find(statusId);
+ return i != statusEffects.end() ? i->second : NULL;
+}
+
diff --git a/src/game-server/statusmanager.hpp b/src/game-server/statusmanager.hpp
new file mode 100644
index 00000000..6f8f7358
--- /dev/null
+++ b/src/game-server/statusmanager.hpp
@@ -0,0 +1,52 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _TMW_STATUSMANAGER_H
+#define _TMW_STATUSMANAGER_H
+
+#include <string>
+
+class StatusEffect;
+
+namespace StatusManager
+{
+ /**
+ * Loads status reference file.
+ */
+ void initialize(const std::string &);
+
+ /**
+ * Reloads status reference file.
+ */
+ void reload();
+
+ /**
+ * Destroy status classes.
+ */
+ void deinitialize();
+
+ /**
+ * Gets the status having the given ID.
+ */
+ StatusEffect *getStatus(int statusId);
+}
+
+#endif
diff --git a/src/scripting/lua.cpp b/src/scripting/lua.cpp
index d5c12c76..230c8a3c 100644
--- a/src/scripting/lua.cpp
+++ b/src/scripting/lua.cpp
@@ -482,6 +482,42 @@ static int npc_trade(lua_State *s)
}
/**
+ * Applies a status effect with id to the being given for a amount of time
+ * tmw.being_apply_status(Being *being, int id, int time)
+ */
+
+static int being_apply_status(lua_State *s)
+{
+ if (!lua_isuserdata(s, 1) || !lua_isnumber(s, 2) || !lua_isnumber(s, 3))
+ {
+ raiseScriptError(s, "being_apply_status called with incorrect parameters.");
+ return 0;
+ }
+ Being *being = getBeing(s, 1);
+ int id = lua_tointeger(s, 2);
+ int time = lua_tointeger(s, 3);
+ being->applyStatusEffect(id, time);
+ return 1;
+}
+
+/**
+ * Returns true if a being has a status effect
+ * tmw.being_has_status(Being *being, int id)
+ */
+static int being_has_status(lua_State *s)
+{
+ if (!lua_isuserdata(s, 1) || !lua_isnumber(s, 2))
+ {
+ raiseScriptError(s, "being_has_status called with incorrect parameters.");
+ return 0;
+ }
+ Being *being = getBeing(s, 1);
+ lua_pushboolean(s, being->hasStatusEffect(lua_tointeger(s,2)));
+ return 1;
+}
+
+
+/**
* Returns the Thing type of the given Being
* tmw.being_type(Being *being)
*/
@@ -499,6 +535,7 @@ static int being_type(lua_State *s)
return 1;
}
+
/**
* Function for making a being walk to a position
* being_walk(Being *being, int x, int y, int speed)
@@ -1245,6 +1282,8 @@ LuaScript::LuaScript():
{ "chr_get_hair_color", &chr_get_hair_color },
{ "exp_for_level", &exp_for_level },
{ "monster_create", &monster_create },
+ { "being_apply_status", &being_apply_status },
+ { "being_has_status", &being_has_status },
{ "being_type", &being_type },
{ "being_walk", &being_walk },
{ "being_say", &being_say },