summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-rw-r--r--CMake/Modules/FindSigC++.cmake34
-rw-r--r--CMake/Modules/LibFindMacros.cmake99
-rw-r--r--README13
-rw-r--r--src/CMakeLists.txt5
-rw-r--r--src/game-server/being.cpp27
-rw-r--r--src/game-server/being.h10
-rw-r--r--src/game-server/character.cpp10
-rw-r--r--src/game-server/character.h2
-rw-r--r--src/game-server/entity.cpp47
-rw-r--r--src/game-server/entity.h37
-rw-r--r--src/game-server/eventlistener.h102
-rw-r--r--src/game-server/monster.cpp83
-rw-r--r--src/game-server/monster.h23
-rw-r--r--src/game-server/quest.cpp78
-rw-r--r--src/game-server/spawnarea.cpp20
-rw-r--r--src/game-server/spawnarea.h2
-rw-r--r--src/game-server/state.cpp6
-rw-r--r--src/scripting/lua.cpp6
-rw-r--r--src/scripting/luascript.cpp2
-rw-r--r--src/scripting/luascript.h2
-rw-r--r--src/scripting/script.cpp3
-rw-r--r--src/scripting/script.h22
23 files changed, 291 insertions, 344 deletions
diff --git a/.travis.yml b/.travis.yml
index bbebefd2..b56d187b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,5 +4,5 @@ compiler:
- clang
before_install:
- sudo apt-get update -qq
- - sudo apt-get install -qq sqlite3 cmake make gcc libxml2-dev liblua5.1-0-dev libphysfs-dev libsqlite3-dev libsdl-gfx1.2-dev libsdl-image1.2-dev libsdl-mixer1.2-dev libsdl-net1.2-dev libsdl-pango-dev libsdl-ttf2.0-dev libsdl1.2-dev libguichan-dev libphysfs-dev libenet1a libcurl4-openssl-dev libcurl3 zlib1g-dev libmysqlclient-dev
+ - sudo apt-get install -qq sqlite3 cmake make gcc libxml2-dev liblua5.1-0-dev libphysfs-dev libsqlite3-dev libsdl-gfx1.2-dev libsdl-image1.2-dev libsdl-mixer1.2-dev libsdl-net1.2-dev libsdl-pango-dev libsdl-ttf2.0-dev libsdl1.2-dev libguichan-dev libphysfs-dev libenet1a libcurl4-openssl-dev libcurl3 zlib1g-dev libmysqlclient-dev libsigc++-2.0-dev
script: cmake . -DWITH_MYSQL=ON && make
diff --git a/CMake/Modules/FindSigC++.cmake b/CMake/Modules/FindSigC++.cmake
new file mode 100644
index 00000000..35687d5b
--- /dev/null
+++ b/CMake/Modules/FindSigC++.cmake
@@ -0,0 +1,34 @@
+# - Try to find SigC++-2.0
+# Once done, this will define
+#
+# SigC++_FOUND - system has SigC++
+# SigC++_INCLUDE_DIRS - the SigC++ include directories
+# SigC++_LIBRARIES - link these to use SigC++
+
+include(LibFindMacros)
+
+# Use pkg-config to get hints about paths
+libfind_pkg_check_modules(SigC++_PKGCONF sigc++-2.0)
+
+# Main include dir
+find_path(SigC++_INCLUDE_DIR
+ NAMES sigc++/sigc++.h
+ PATHS ${SigC++_PKGCONF_INCLUDE_DIRS}
+ PATH_SUFFIXES sigc++-2.0
+)
+
+# Glib-related libraries also use a separate config header, which is in lib dir
+find_path(SigC++Config_INCLUDE_DIR
+ NAMES sigc++config.h
+ PATHS ${SigC++_PKGCONF_INCLUDE_DIRS} /usr
+ PATH_SUFFIXES lib/sigc++-2.0/include
+)
+
+libfind_library(SigC++ sigc 2.0)
+
+# Set the include dir variables and the libraries and let libfind_process do
+# the rest. NOTE: Singular variables for this library, plural for libraries
+# this this lib depends on.
+set(SigC++_PROCESS_INCLUDES SigC++_INCLUDE_DIR SigC++Config_INCLUDE_DIR)
+set(SigC++_PROCESS_LIBS SigC++_LIBRARY)
+libfind_process(SigC++)
diff --git a/CMake/Modules/LibFindMacros.cmake b/CMake/Modules/LibFindMacros.cmake
new file mode 100644
index 00000000..69975c51
--- /dev/null
+++ b/CMake/Modules/LibFindMacros.cmake
@@ -0,0 +1,99 @@
+# Works the same as find_package, but forwards the "REQUIRED" and "QUIET" arguments
+# used for the current package. For this to work, the first parameter must be the
+# prefix of the current package, then the prefix of the new package etc, which are
+# passed to find_package.
+macro (libfind_package PREFIX)
+ set (LIBFIND_PACKAGE_ARGS ${ARGN})
+ if (${PREFIX}_FIND_QUIETLY)
+ set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} QUIET)
+ endif (${PREFIX}_FIND_QUIETLY)
+ if (${PREFIX}_FIND_REQUIRED)
+ set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} REQUIRED)
+ endif (${PREFIX}_FIND_REQUIRED)
+ find_package(${LIBFIND_PACKAGE_ARGS})
+endmacro (libfind_package)
+
+# CMake developers made the UsePkgConfig system deprecated in the same release (2.6)
+# where they added pkg_check_modules. Consequently I need to support both in my scripts
+# to avoid those deprecated warnings. Here's a helper that does just that.
+# Works identically to pkg_check_modules, except that no checks are needed prior to use.
+macro (libfind_pkg_check_modules PREFIX PKGNAME)
+ if (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
+ include(UsePkgConfig)
+ pkgconfig(${PKGNAME} ${PREFIX}_INCLUDE_DIRS ${PREFIX}_LIBRARY_DIRS ${PREFIX}_LDFLAGS ${PREFIX}_CFLAGS)
+ else (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
+ find_package(PkgConfig)
+ if (PKG_CONFIG_FOUND)
+ pkg_check_modules(${PREFIX} ${PKGNAME})
+ endif (PKG_CONFIG_FOUND)
+ endif (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
+endmacro (libfind_pkg_check_modules)
+
+# Do the final processing once the paths have been detected.
+# If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain
+# all the variables, each of which contain one include directory.
+# Ditto for ${PREFIX}_PROCESS_LIBS and library files.
+# Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES.
+# Also handles errors in case library detection was required, etc.
+macro (libfind_process PREFIX)
+ # Skip processing if already processed during this run
+ if (NOT ${PREFIX}_FOUND)
+ # Start with the assumption that the library was found
+ set (${PREFIX}_FOUND TRUE)
+
+ # Process all includes and set _FOUND to false if any are missing
+ foreach (i ${${PREFIX}_PROCESS_INCLUDES})
+ if (${i})
+ set (${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIRS} ${${i}})
+ mark_as_advanced(${i})
+ else (${i})
+ set (${PREFIX}_FOUND FALSE)
+ endif (${i})
+ endforeach (i)
+
+ # Process all libraries and set _FOUND to false if any are missing
+ foreach (i ${${PREFIX}_PROCESS_LIBS})
+ if (${i})
+ set (${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARIES} ${${i}})
+ mark_as_advanced(${i})
+ else (${i})
+ set (${PREFIX}_FOUND FALSE)
+ endif (${i})
+ endforeach (i)
+
+ # Print message and/or exit on fatal error
+ if (${PREFIX}_FOUND)
+ if (NOT ${PREFIX}_FIND_QUIETLY)
+ message (STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}")
+ endif (NOT ${PREFIX}_FIND_QUIETLY)
+ else (${PREFIX}_FOUND)
+ if (${PREFIX}_FIND_REQUIRED)
+ foreach (i ${${PREFIX}_PROCESS_INCLUDES} ${${PREFIX}_PROCESS_LIBS})
+ message("${i}=${${i}}")
+ endforeach (i)
+ message (FATAL_ERROR "Required library ${PREFIX} NOT FOUND.\nInstall the library (dev version) and try again. If the library is already installed, use ccmake to set the missing variables manually.")
+ endif (${PREFIX}_FIND_REQUIRED)
+ endif (${PREFIX}_FOUND)
+ endif (NOT ${PREFIX}_FOUND)
+endmacro (libfind_process)
+
+macro(libfind_library PREFIX basename)
+ set(TMP "")
+ if(MSVC80)
+ set(TMP -vc80)
+ endif(MSVC80)
+ if(MSVC90)
+ set(TMP -vc90)
+ endif(MSVC90)
+ set(${PREFIX}_LIBNAMES ${basename}${TMP})
+ if(${ARGC} GREATER 2)
+ set(${PREFIX}_LIBNAMES ${basename}${TMP}-${ARGV2})
+ string(REGEX REPLACE "\\." "_" TMP ${${PREFIX}_LIBNAMES})
+ set(${PREFIX}_LIBNAMES ${${PREFIX}_LIBNAMES} ${TMP})
+ endif(${ARGC} GREATER 2)
+ find_library(${PREFIX}_LIBRARY
+ NAMES ${${PREFIX}_LIBNAMES}
+ PATHS ${${PREFIX}_PKGCONF_LIBRARY_DIRS}
+ )
+endmacro(libfind_library)
+
diff --git a/README b/README
index 06e56ce6..34faafcf 100644
--- a/README
+++ b/README
@@ -6,15 +6,16 @@ COMPILATION
Before trying to compile, make sure all the dependencies are installed. For
each dependency the Ubuntu package name is listed as well as the website.
- * libxml2 (libxml2-dev) - http://xmlsoft.org/
- * Lua (liblua5.1-0-dev) - http://lua.org/
- * PhysFS (libphysfs-dev) - http://icculus.org/physfs/
- * SQLite 3 (libsqlite3-dev) - http://sqlite.org/
- * zlib (zlib1g-dev) - http://zlib.net/
+ * libsigc++ 2.0 (libsigc++-2.0-dev) - http://libsigc.sourceforge.net/
+ * libxml2 (libxml2-dev) - http://xmlsoft.org/
+ * Lua (liblua5.1-0-dev) - http://lua.org/
+ * PhysFS (libphysfs-dev) - http://icculus.org/physfs/
+ * SQLite 3 (libsqlite3-dev) - http://sqlite.org/
+ * zlib (zlib1g-dev) - http://zlib.net/
Optional dependencies:
- * MySQL (libmysqlclient-dev) - http://dev.mysql.com/
+ * MySQL (libmysqlclient-dev) - http://dev.mysql.com/
(replaces the SQLite 3 depency)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 5a4b38fc..73f969f7 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,6 +1,7 @@
FIND_PACKAGE(LibXml2 REQUIRED)
FIND_PACKAGE(PhysFS REQUIRED)
FIND_PACKAGE(ZLIB REQUIRED)
+FIND_PACKAGE(SigC++ REQUIRED)
IF (CMAKE_COMPILER_IS_GNUCXX)
# Help getting compilation warnings
@@ -93,6 +94,8 @@ INCLUDE_DIRECTORIES(
${CMAKE_CURRENT_SOURCE_DIR}
${PHYSFS_INCLUDE_DIR}
${LIBXML2_INCLUDE_DIR}
+ ${SigC++_INCLUDE_DIR}
+ ${SigC++Config_INCLUDE_DIR}
)
# Fix some stuff that gets not hidden by mainline modules
@@ -214,7 +217,6 @@ SET(SRCS_MANASERVGAME
game-server/effect.cpp
game-server/entity.h
game-server/entity.cpp
- game-server/eventlistener.h
game-server/gamehandler.h
game-server/gamehandler.cpp
game-server/inventory.h
@@ -315,6 +317,7 @@ FOREACH(program ${PROGRAMS})
${PHYSFS_LIBRARY}
${LIBXML2_LIBRARIES}
${ZLIB_LIBRARIES}
+ ${SigC++_LIBRARIES}
${OPTIONAL_LIBRARIES}
${EXTRA_LIBRARIES})
INSTALL(TARGETS ${program} RUNTIME DESTINATION ${PKG_BINDIR})
diff --git a/src/game-server/being.cpp b/src/game-server/being.cpp
index ea7540ca..9ce19d76 100644
--- a/src/game-server/being.cpp
+++ b/src/game-server/being.cpp
@@ -27,7 +27,6 @@
#include "game-server/attributemanager.h"
#include "game-server/character.h"
#include "game-server/collisiondetection.h"
-#include "game-server/eventlistener.h"
#include "game-server/mapcomposite.h"
#include "game-server/effect.h"
#include "game-server/skillmanager.h"
@@ -58,6 +57,9 @@ Being::Being(EntityType type):
Attribute(*it1->second)));
}
+
+ signal_inserted.connect(sigc::mem_fun(this, &Being::inserted));
+
// TODO: Way to define default base values?
// Should this be handled by the virtual modifiedAttribute?
// URGENT either way
@@ -177,14 +179,7 @@ void Being::died()
// reset target
mTarget = NULL;
- for (Listeners::iterator i = mListeners.begin(),
- i_end = mListeners.end(); i != i_end;)
- {
- const EventListener &l = **i;
- ++i; // In case the listener removes itself from the list on the fly.
- if (l.dispatch->died)
- l.dispatch->died(&l, this);
- }
+ signal_died.emit(this);
}
void Being::processAttacks()
@@ -512,6 +507,11 @@ bool Being::removeModifier(unsigned attr, double value, unsigned layer,
return ret;
}
+void Being::setGender(BeingGender gender)
+{
+ mGender = gender;
+}
+
void Being::setAttribute(unsigned id, double value)
{
AttributeMap::iterator ret = mAttributes.find(id);
@@ -743,20 +743,13 @@ void Being::update()
processAttacks();
}
-void Being::inserted()
+void Being::inserted(Entity *)
{
- Actor::inserted();
-
// Reset the old position, since after insertion it is important that it is
// in sync with the zone that we're currently present in.
mOld = getPosition();
}
-void Being::setGender(BeingGender gender)
-{
- mGender = gender;
-}
-
void Being::processAttack(Attack &attack)
{
performAttack(mTarget, attack.getAttackInfo()->getDamage());
diff --git a/src/game-server/being.h b/src/game-server/being.h
index 0083be1f..a08df018 100644
--- a/src/game-server/being.h
+++ b/src/game-server/being.h
@@ -297,10 +297,7 @@ class Being : public Actor
void setTarget(Being *target)
{ mTarget = target; }
- /**
- * Overridden in order to reset the old position upon insertion.
- */
- virtual void inserted();
+ sigc::signal<void, Being *> signal_died;
protected:
/**
@@ -332,6 +329,11 @@ class Being : public Actor
Being(const Being &rhs);
Being &operator=(const Being &rhs);
+ /**
+ * Connected to signal_inserted to reset the old position.
+ */
+ void inserted(Entity *);
+
Path mPath;
BeingDirection mDirection; /**< Facing direction. */
diff --git a/src/game-server/character.cpp b/src/game-server/character.cpp
index 15ba940a..a9777991 100644
--- a/src/game-server/character.cpp
+++ b/src/game-server/character.cpp
@@ -24,7 +24,6 @@
#include "game-server/accountconnection.h"
#include "game-server/attributemanager.h"
#include "game-server/buysell.h"
-#include "game-server/eventlistener.h"
#include "game-server/inventory.h"
#include "game-server/item.h"
#include "game-server/itemmanager.h"
@@ -792,14 +791,7 @@ void Character::disconnected()
else
GameState::remove(this);
- for (Listeners::iterator i = mListeners.begin(),
- i_end = mListeners.end(); i != i_end;)
- {
- const EventListener &l = **i;
- ++i; // In case the listener removes itself from the list on the fly.
- if (l.dispatch->disconnected)
- l.dispatch->disconnected(&l, this);
- }
+ signal_disconnected.emit(this);
}
bool Character::takeSpecial(int id)
diff --git a/src/game-server/character.h b/src/game-server/character.h
index 5f3d3a64..d225081b 100644
--- a/src/game-server/character.h
+++ b/src/game-server/character.h
@@ -428,6 +428,8 @@ class Character : public Being
virtual void removeAttack(AttackInfo *attackInfo);
+ sigc::signal<void, Character *> signal_disconnected;
+
protected:
/**
* Gets the way the actor blocks pathfinding for other objects
diff --git a/src/game-server/entity.cpp b/src/game-server/entity.cpp
index 671ef5e6..6cb61e58 100644
--- a/src/game-server/entity.cpp
+++ b/src/game-server/entity.cpp
@@ -18,51 +18,4 @@
* along with The Mana Server. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <cassert>
-
#include "game-server/entity.h"
-
-#include "game-server/eventlistener.h"
-
-Entity::~Entity()
-{
- /* As another object will stop listening and call removeListener when it is
- deleted, the following assertion ensures that all the calls to
- removeListener have been performed will this object was still alive. It
- is not strictly necessary, as there are cases where no removal is
- performed (e.g. ~SpawnArea). But this is rather exceptional, so keep the
- assertion to catch all the other forgotten calls to removeListener. */
- assert(mListeners.empty());
-}
-
-void Entity::addListener(const EventListener *l)
-{
- mListeners.insert(l);
-}
-
-void Entity::removeListener(const EventListener *l)
-{
- mListeners.erase(l);
-}
-
-void Entity::inserted()
-{
- for (Listeners::iterator i = mListeners.begin(),
- i_end = mListeners.end(); i != i_end;)
- {
- const EventListener &l = **i;
- ++i; // In case the listener removes itself from the list on the fly.
- if (l.dispatch->inserted) l.dispatch->inserted(&l, this);
- }
-}
-
-void Entity::removed()
-{
- for (Listeners::iterator i = mListeners.begin(),
- i_end = mListeners.end(); i != i_end;)
- {
- const EventListener &l = **i;
- ++i; // In case the listener removes itself from the list on the fly.
- if (l.dispatch->removed) l.dispatch->removed(&l, this);
- }
-}
diff --git a/src/game-server/entity.h b/src/game-server/entity.h
index 652db7c7..91f13699 100644
--- a/src/game-server/entity.h
+++ b/src/game-server/entity.h
@@ -23,18 +23,20 @@
#include "common/manaserv_protocol.h"
-using namespace ManaServ;
-
#include <set>
-class EventListener;
+#include <sigc++/signal.h>
+#include <sigc++/trackable.h>
+
+using namespace ManaServ;
+
class MapComposite;
/**
* Base class for in-game objects. Knows only its type and the map it resides
* on. Provides listeners.
*/
-class Entity
+class Entity : public sigc::trackable
{
public:
Entity(EntityType type, MapComposite *map = 0)
@@ -42,7 +44,7 @@ class Entity
mType(type)
{}
- virtual ~Entity();
+ virtual ~Entity() {}
/**
* Gets type of this entity.
@@ -88,29 +90,8 @@ class Entity
virtual void setMap(MapComposite *map)
{ mMap = map; }
- /**
- * Adds a new listener.
- */
- void addListener(const EventListener *);
-
- /**
- * Removes an existing listener.
- */
- void removeListener(const EventListener *);
-
- /**
- * Calls all the "inserted" listeners.
- */
- virtual void inserted();
-
- /**
- * Calls all the "removed" listeners.
- */
- virtual void removed();
-
- protected:
- typedef std::set< const EventListener * > Listeners;
- Listeners mListeners; /**< List of event listeners. */
+ sigc::signal<void, Entity *> signal_inserted;
+ sigc::signal<void, Entity *> signal_removed;
private:
MapComposite *mMap; /**< Map the entity is on */
diff --git a/src/game-server/eventlistener.h b/src/game-server/eventlistener.h
deleted file mode 100644
index 53d92077..00000000
--- a/src/game-server/eventlistener.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * The Mana Server
- * Copyright (C) 2007-2010 The Mana World Development Team
- *
- * This file is part of The Mana Server.
- *
- * The Mana Server 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 Server 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 Server. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef GAMESERVER_EVENTLISTENER_H
-#define GAMESERVER_EVENTLISTENER_H
-
-class Entity;
-class Being;
-class Character;
-
-struct EventDispatch;
-
-/**
- * Pointer to a dispatch table.
- */
-struct EventListener
-{
- const EventDispatch *dispatch;
- EventListener(const EventDispatch *d): dispatch(d) {}
-};
-
-/**
- * Dispatch table for event notification.
- */
-struct EventDispatch
-{
- /**
- * Called just after something is inserted in a map.
- */
- void (*inserted)(const EventListener *, Entity *);
-
- /**
- * Called just before something is removed from a map.
- */
- void (*removed)(const EventListener *, Entity *);
-
- /**
- * Called just after a being has died.
- */
- void (*died)(const EventListener *, Being *);
-
- /**
- * Called just before a character is deleted.
- */
- void (*disconnected)(const EventListener *, Character *);
-
- /**
- * Initializes dispatch methods as missing.
- */
- EventDispatch():
- inserted(0), removed(0), died(0), disconnected(0)
- {}
-};
-
-/**
- * Helper for using member functions as dispatch methods. The 3-level structure
- * is due to default template parameter not being allowed on functions yet.
- * Conceptually, this helper takes two parameters: the name of the member
- * variable pointing to the dispatch table and the name of the member function
- * to call on dispatch. With these two parameters, it creates a dispatch
- * method. When called, this free function forwards the call to the member
- * function.
- * Pseudo-syntax for getting a dispatch method:
- * <code>&amp;EventListenerFactory&lt; _, DispatchPointerName &gt;::create&lt; _, MemberFunctionName &gt;::function</code>
- * See the start of the spawnarea.cpp file for a complete example.
- */
-template< class T, EventListener T::*D >
-struct EventListenerFactory
-{
- template< class U, void (T::*F)(U *), class V = U >
- struct create
- {
- static void function(const EventListener *d, V *u)
- {
- /* Get the address of the T object by substracting the offset of D
- from the pointer d. */
- T *t = (T *)((char *)d -
- ((char *)&(((T *)42)->*D) - (char *)&(*(T *)42)));
- // Then call the method F of this T object.
- (t->*F)(u);
- }
- };
-};
-
-#endif
diff --git a/src/game-server/monster.cpp b/src/game-server/monster.cpp
index cdfe063a..330e3f4f 100644
--- a/src/game-server/monster.cpp
+++ b/src/game-server/monster.cpp
@@ -35,18 +35,6 @@
#include <cmath>
-struct MonsterTargetEventDispatch: EventDispatch
-{
- MonsterTargetEventDispatch()
- {
- typedef EventListenerFactory<Monster, &Monster::mTargetListener> Factory;
- removed = &Factory::create< Entity, &Monster::forgetTarget >::function;
- died = &Factory::create<Entity, &Monster::forgetTarget, Being>::function;
- }
-};
-
-static MonsterTargetEventDispatch monsterTargetEventDispatch;
-
MonsterClass::~MonsterClass()
{
for (std::vector<AttackInfo *>::iterator it = mAttacks.begin(),
@@ -67,7 +55,6 @@ double MonsterClass::getVulnerability(Element element) const
Monster::Monster(MonsterClass *specy):
Being(OBJECT_MONSTER),
mSpecy(specy),
- mTargetListener(&monsterTargetEventDispatch),
mOwner(NULL)
{
LOG_DEBUG("Monster spawned! (id: " << mSpecy->getId() << ").");
@@ -137,12 +124,6 @@ Monster::Monster(MonsterClass *specy):
Monster::~Monster()
{
- // Remove death listeners.
- for (std::map<Being *, int>::iterator i = mAnger.begin(),
- i_end = mAnger.end(); i != i_end; ++i)
- {
- i->first->removeListener(&mTargetListener);
- }
}
void Monster::update()
@@ -229,11 +210,11 @@ void Monster::refreshTarget()
// Determine how much we hate the target
int targetPriority = 0;
- std::map<Being *, int, std::greater<Being *> >::iterator angerIterator;
- angerIterator = mAnger.find(target);
+ std::map<Being *, AggressionInfo>::iterator angerIterator = mAnger.find(target);
if (angerIterator != mAnger.end())
{
- targetPriority = angerIterator->second;
+ const AggressionInfo &aggressionInfo = angerIterator->second;
+ targetPriority = aggressionInfo.anger;
}
else if (mSpecy->isAggressive())
{
@@ -359,11 +340,15 @@ int Monster::calculatePositionPriority(Point position, int targetPriority)
}
}
-void Monster::forgetTarget(Entity *t)
+void Monster::forgetTarget(Entity *entity)
{
- Being *b = static_cast< Being * >(t);
+ Being *b = static_cast< Being * >(entity);
+ {
+ AggressionInfo &aggressionInfo = mAnger[b];
+ aggressionInfo.removedConnection.disconnect();
+ aggressionInfo.diedConnection.disconnect();
+ }
mAnger.erase(b);
- b->removeListener(&mTargetListener);
if (b->getType() == OBJECT_CHARACTER)
{
@@ -375,20 +360,42 @@ void Monster::forgetTarget(Entity *t)
void Monster::changeAnger(Actor *target, int amount)
{
- if (target && (target->getType() == OBJECT_MONSTER
- || target->getType() == OBJECT_CHARACTER))
+ const EntityType type = target->getType();
+ if (type != OBJECT_MONSTER && type != OBJECT_CHARACTER)
+ return;
+
+ Being *being = static_cast< Being * >(target);
+
+ if (mAnger.find(being) != mAnger.end())
{
- Being *t = static_cast< Being * >(target);
- if (mAnger.find(t) != mAnger.end())
- {
- mAnger[t] += amount;
- }
- else
- {
- mAnger[t] = amount;
- t->addListener(&mTargetListener);
- }
+ mAnger[being].anger += amount;
+ }
+ else
+ {
+ AggressionInfo &aggressionInfo = mAnger[being];
+ aggressionInfo.anger = amount;
+
+ // Forget target either when it's removed or died, whichever
+ // happens first.
+ aggressionInfo.removedConnection =
+ being->signal_removed.connect(sigc::mem_fun(this, &Monster::forgetTarget));
+ aggressionInfo.diedConnection =
+ being->signal_died.connect(sigc::mem_fun(this, &Monster::forgetTarget));
+ }
+}
+
+std::map<Being *, int> Monster::getAngerList() const
+{
+ std::map<Being *, int> result;
+ std::map<Being *, AggressionInfo>::const_iterator i, i_end;
+
+ for (i = mAnger.begin(), i_end = mAnger.end(); i != i_end; ++i)
+ {
+ const AggressionInfo &aggressionInfo = i->second;
+ result.insert(std::make_pair(i->first, aggressionInfo.anger));
}
+
+ return result;
}
int Monster::damage(Actor *source, const Damage &damage)
@@ -399,9 +406,7 @@ int Monster::damage(Actor *source, const Damage &damage)
newDamage.delta = newDamage.delta * factor;
int HPLoss = Being::damage(source, newDamage);
if (source)
- {
changeAnger(source, HPLoss);
- }
if (HPLoss && source && source->getType() == OBJECT_CHARACTER)
{
diff --git a/src/game-server/monster.h b/src/game-server/monster.h
index 73fec6aa..3313345c 100644
--- a/src/game-server/monster.h
+++ b/src/game-server/monster.h
@@ -22,7 +22,6 @@
#define MONSTER_H
#include "game-server/being.h"
-#include "game-server/eventlistener.h"
#include "common/defines.h"
#include "scripting/script.h"
#include "utils/string.h"
@@ -31,6 +30,9 @@
#include <vector>
#include <string>
+#include <sigc++/connection.h>
+
+class Character;
class ItemClass;
class Script;
@@ -315,8 +317,7 @@ class Monster : public Being
*/
void changeAnger(Actor *target, int amount);
- const std::map<Being *, int> &getAngerList() const
- { return mAnger; }
+ std::map<Being *, int> getAngerList() const;
/**
* Calls the damage function in Being and updates the aggro list
@@ -326,7 +327,7 @@ class Monster : public Being
/**
* Removes a being from the anger list.
*/
- void forgetTarget(Entity *being);
+ void forgetTarget(Entity *entity);
/**
* Called when an attribute modifier is changed.
@@ -351,10 +352,16 @@ class Monster : public Being
MonsterClass *mSpecy;
/** Aggression towards other beings. */
- std::map<Being *, int> mAnger;
-
- /** Listener for updating the anger list. */
- EventListener mTargetListener;
+ struct AggressionInfo {
+ AggressionInfo()
+ : anger(0)
+ {}
+
+ int anger;
+ sigc::connection removedConnection;
+ sigc::connection diedConnection;
+ };
+ std::map<Being *, AggressionInfo> mAnger;
/**
* Character who currently owns this monster (killsteal protection).
diff --git a/src/game-server/quest.cpp b/src/game-server/quest.cpp
index 4d659227..c28a4213 100644
--- a/src/game-server/quest.cpp
+++ b/src/game-server/quest.cpp
@@ -18,24 +18,27 @@
* along with The Mana Server. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <cassert>
-#include <list>
-#include <map>
-#include <string>
-
#include "game-server/quest.h"
#include "game-server/accountconnection.h"
#include "game-server/character.h"
-#include "game-server/eventlistener.h"
#include "utils/logger.h"
+#include <cassert>
+#include <list>
+#include <map>
+#include <string>
+
+#include <sigc++/connection.h>
+
typedef std::list< QuestCallback * > QuestCallbacks;
typedef std::map< std::string, QuestCallbacks > PendingVariables;
struct PendingQuest
{
Character *character;
+ sigc::connection removedConnection;
+ sigc::connection disconnectedConnection;
PendingVariables variables;
};
@@ -72,22 +75,6 @@ void setQuestVar(Character *ch, const std::string &name,
accountHandler->updateCharacterVar(ch, name, value);
}
-/**
- * Listener for deleting related quests when a character disappears.
- */
-struct QuestDeathListener: EventDispatch
-{
- static void partialRemove(const EventListener *, Entity *);
-
- static void fullRemove(const EventListener *, Character *);
-
- QuestDeathListener()
- {
- removed = &partialRemove;
- disconnected = &fullRemove;
- }
-};
-
void QuestRefCallback::triggerCallback(Character *ch,
const std::string &value) const
{
@@ -103,10 +90,7 @@ void QuestRefCallback::triggerCallback(Character *ch,
s->execute();
}
-static QuestDeathListener questDeathDummy;
-static EventListener questDeathListener(&questDeathDummy);
-
-void QuestDeathListener::partialRemove(const EventListener *, Entity *t)
+static void partialRemove(Entity *t)
{
int id = static_cast< Character * >(t)->getDatabaseID();
PendingVariables &variables = pendingQuests[id].variables;
@@ -119,11 +103,18 @@ void QuestDeathListener::partialRemove(const EventListener *, Entity *t)
// The listener is kept in case a fullRemove is needed later.
}
-void QuestDeathListener::fullRemove(const EventListener *, Character *ch)
+static void fullRemove(Character *ch)
{
- ch->removeListener(&questDeathListener);
+ int id = ch->getDatabaseID();
+
+ {
+ PendingQuest &pendingQuest = pendingQuests[id];
+ pendingQuest.removedConnection.disconnect();
+ pendingQuest.disconnectedConnection.disconnect();
+ }
+
// Remove anything related to this character.
- pendingQuests.erase(ch->getDatabaseID());
+ pendingQuests.erase(id);
}
void recoverQuestVar(Character *ch, const std::string &name,
@@ -134,11 +125,19 @@ void recoverQuestVar(Character *ch, const std::string &name,
PendingQuests::iterator i = pendingQuests.lower_bound(id);
if (i == pendingQuests.end() || i->first != id)
{
- i = pendingQuests.insert(i, std::make_pair(id, PendingQuest()));
- i->second.character = ch;
- /* Register a listener, because we cannot afford to get invalid
- pointers, when we finally recover the variable. */
- ch->addListener(&questDeathListener);
+ PendingQuest pendingQuest;
+ pendingQuest.character = ch;
+
+ /* Connect to removed and disconnected signals, because we cannot
+ * afford to get invalid pointers, when we finally recover the
+ * variable.
+ */
+ pendingQuest.removedConnection =
+ ch->signal_removed.connect(sigc::ptr_fun(partialRemove));
+ pendingQuest.disconnectedConnection =
+ ch->signal_disconnected.connect(sigc::ptr_fun(fullRemove));
+
+ i = pendingQuests.insert(i, std::make_pair(id, pendingQuest));
}
i->second.variables[name].push_back(f);
accountHandler->requestCharacterVar(ch, name);
@@ -149,12 +148,14 @@ void recoveredQuestVar(int id,
const std::string &value)
{
PendingQuests::iterator i = pendingQuests.find(id);
- if (i == pendingQuests.end()) return;
+ if (i == pendingQuests.end())
+ return;
- Character *ch = i->second.character;
- ch->removeListener(&questDeathListener);
+ PendingQuest &pendingQuest = i->second;
+ pendingQuest.removedConnection.disconnect();
+ pendingQuest.disconnectedConnection.disconnect();
- PendingVariables &variables = i->second.variables;
+ PendingVariables &variables = pendingQuest.variables;
PendingVariables::iterator j = variables.find(name);
if (j == variables.end())
{
@@ -162,6 +163,7 @@ void recoveredQuestVar(int id,
return;
}
+ Character *ch = pendingQuest.character;
ch->questCache[name] = value;
// Call the registered callbacks.
diff --git a/src/game-server/spawnarea.cpp b/src/game-server/spawnarea.cpp
index 155d4c0d..73dca6b2 100644
--- a/src/game-server/spawnarea.cpp
+++ b/src/game-server/spawnarea.cpp
@@ -25,18 +25,6 @@
#include "game-server/state.h"
#include "utils/logger.h"
-struct SpawnAreaEventDispatch : EventDispatch
-{
- SpawnAreaEventDispatch()
- {
- typedef EventListenerFactory< SpawnArea, &SpawnArea::mSpawnedListener >
- Factory;
- removed = &Factory::create< Entity, &SpawnArea::decrease >::function;
- }
-};
-
-static SpawnAreaEventDispatch spawnAreaEventDispatch;
-
SpawnArea::SpawnArea(MapComposite *map,
MonsterClass *specy,
const Rectangle &zone,
@@ -44,7 +32,6 @@ SpawnArea::SpawnArea(MapComposite *map,
int spawnRate):
Entity(OBJECT_OTHER, map),
mSpecy(specy),
- mSpawnedListener(&spawnAreaEventDispatch),
mZone(zone),
mMaxBeings(maxBeings),
mSpawnRate(spawnRate),
@@ -102,7 +89,9 @@ void SpawnArea::update()
if (c)
{
- being->addListener(&mSpawnedListener);
+ being->signal_removed.connect(
+ sigc::mem_fun(this, &SpawnArea::decrease));
+
being->setMap(map);
being->setPosition(position);
being->clearDestination();
@@ -125,8 +114,7 @@ void SpawnArea::update()
}
}
-void SpawnArea::decrease(Entity *t)
+void SpawnArea::decrease(Entity *)
{
--mNumBeings;
- t->removeListener(&mSpawnedListener);
}
diff --git a/src/game-server/spawnarea.h b/src/game-server/spawnarea.h
index cc0642f1..628c072e 100644
--- a/src/game-server/spawnarea.h
+++ b/src/game-server/spawnarea.h
@@ -21,7 +21,6 @@
#ifndef SPAWNAREA_H
#define SPAWNAREA_H
-#include "game-server/eventlistener.h"
#include "game-server/entity.h"
#include "utils/point.h"
@@ -47,7 +46,6 @@ class SpawnArea : public Entity
private:
MonsterClass *mSpecy; /**< Specy of monster that spawns in this area. */
- EventListener mSpawnedListener; /**< Tracking of spawned monsters. */
Rectangle mZone;
int mMaxBeings; /**< Maximum population of this area. */
int mSpawnRate; /**< Number of beings spawning per minute. */
diff --git a/src/game-server/state.cpp b/src/game-server/state.cpp
index ede94f86..a688caca 100644
--- a/src/game-server/state.cpp
+++ b/src/game-server/state.cpp
@@ -498,7 +498,7 @@ bool GameState::insert(Entity *ptr)
if (!ptr->isVisible())
{
map->insert(ptr);
- ptr->inserted();
+ ptr->signal_inserted.emit(ptr);
return true;
}
@@ -523,7 +523,7 @@ bool GameState::insert(Entity *ptr)
return false;
}
- obj->inserted();
+ obj->signal_inserted.emit(obj);
// DEBUG INFO
switch (obj->getType())
@@ -596,7 +596,7 @@ void GameState::remove(Entity *ptr)
MapComposite *map = ptr->getMap();
int visualRange = Configuration::getValue("game_visualRange", 448);
- ptr->removed();
+ ptr->signal_removed.emit(ptr);
// DEBUG INFO
switch (ptr->getType())
diff --git a/src/scripting/lua.cpp b/src/scripting/lua.cpp
index 545e365e..880216d2 100644
--- a/src/scripting/lua.cpp
+++ b/src/scripting/lua.cpp
@@ -1709,7 +1709,11 @@ static int chr_get_post(lua_State *s)
static int being_register(lua_State *s)
{
Being *being = checkBeing(s, 1);
- being->addListener(getScript(s)->getScriptListener());
+ Script *script = getScript(s);
+
+ being->signal_died.connect(sigc::mem_fun(script, &Script::processDeathEvent));
+ being->signal_removed.connect(sigc::mem_fun(script, &Script::processRemoveEvent));
+
return 0;
}
diff --git a/src/scripting/luascript.cpp b/src/scripting/luascript.cpp
index 4104bc89..f4ea39ac 100644
--- a/src/scripting/luascript.cpp
+++ b/src/scripting/luascript.cpp
@@ -265,8 +265,6 @@ void LuaScript::processRemoveEvent(Entity *entity)
// being. This might be very interesting for scripting quests.
execute();
}
-
- entity->removeListener(getScriptListener());
}
/**
diff --git a/src/scripting/luascript.h b/src/scripting/luascript.h
index 7631d982..9515bf0e 100644
--- a/src/scripting/luascript.h
+++ b/src/scripting/luascript.h
@@ -28,6 +28,8 @@ extern "C" {
#include "scripting/script.h"
+class Character;
+
/**
* Implementation of the Script class for Lua.
*/
diff --git a/src/scripting/script.cpp b/src/scripting/script.cpp
index 3e299461..63ab7ff4 100644
--- a/src/scripting/script.cpp
+++ b/src/scripting/script.cpp
@@ -40,8 +40,7 @@ Script::Ref Script::mUpdateCallback;
Script::Script():
mCurrentThread(0),
- mMap(0),
- mEventListener(&scriptEventDispatch)
+ mMap(0)
{}
Script::~Script()
diff --git a/src/scripting/script.h b/src/scripting/script.h
index 238bc34c..8dee23a9 100644
--- a/src/scripting/script.h
+++ b/src/scripting/script.h
@@ -23,19 +23,21 @@
#include "common/inventorydata.h"
#include "common/manaserv_protocol.h"
-#include "game-server/eventlistener.h"
#include <list>
#include <string>
#include <vector>
+#include <sigc++/trackable.h>
+
+class Being;
class MapComposite;
class Entity;
/**
* Abstract interface for calling functions written in an external language.
*/
-class Script
+class Script : public sigc::trackable
{
public:
/**
@@ -216,9 +218,6 @@ class Script
MapComposite *getMap() const
{ return mMap; }
- EventListener *getScriptListener()
- { return &mEventListener; }
-
virtual void processDeathEvent(Being *entity) = 0;
virtual void processRemoveEvent(Entity *entity) = 0;
@@ -235,7 +234,6 @@ class Script
private:
MapComposite *mMap;
- EventListener mEventListener; /**< Tracking of being deaths. */
std::vector<Thread*> mThreads;
static Ref mCreateNpcDelayedCallback;
@@ -245,16 +243,4 @@ class Script
friend class Thread;
};
-struct ScriptEventDispatch: EventDispatch
-{
- ScriptEventDispatch()
- {
- typedef EventListenerFactory< Script, &Script::mEventListener > Factory;
- died = &Factory::create< Being, &Script::processDeathEvent >::function;
- removed = &Factory::create< Entity, &Script::processRemoveEvent >::function;
- }
-};
-
-static ScriptEventDispatch scriptEventDispatch;
-
#endif // SCRIPTING_SCRIPT_H