summaryrefslogtreecommitdiff
path: root/src/game-server
diff options
context:
space:
mode:
Diffstat (limited to 'src/game-server')
-rw-r--r--src/game-server/character.cpp26
-rw-r--r--src/game-server/character.h25
-rw-r--r--src/game-server/mapcomposite.cpp2
-rw-r--r--src/game-server/npc.cpp46
-rw-r--r--src/game-server/npc.h31
5 files changed, 100 insertions, 30 deletions
diff --git a/src/game-server/character.cpp b/src/game-server/character.cpp
index bf16e268..ccd629e8 100644
--- a/src/game-server/character.cpp
+++ b/src/game-server/character.cpp
@@ -86,6 +86,7 @@ Character::Character(MessageIn &msg):
mRecalculateLevel(true),
mParty(0),
mTransaction(TRANS_NONE),
+ mTalkNpcId(0),
mNpcThread(0)
{
const AttributeManager::AttributeScope &attr =
@@ -696,6 +697,31 @@ AttribmodResponseCode Character::useCorrectionPoint(size_t attribute)
return ATTRIBMOD_OK;
}
+void Character::startNpcThread(Script::Thread *thread, int npcId)
+{
+ mNpcThread = thread;
+ mTalkNpcId = npcId;
+
+ resumeNpcThread();
+}
+
+void Character::resumeNpcThread()
+{
+ Script *script = ScriptManager::currentState();
+
+ assert(script->getCurrentThread() == mNpcThread);
+
+ if (script->resume())
+ {
+ MessageOut msg(GPMSG_NPC_CLOSE);
+ msg.writeInt16(mTalkNpcId);
+ gameHandler->sendTo(this, msg);
+
+ mTalkNpcId = 0;
+ mNpcThread = 0;
+ }
+}
+
void Character::disconnected()
{
mConnected = false;
diff --git a/src/game-server/character.h b/src/game-server/character.h
index 1b31c611..1f82a101 100644
--- a/src/game-server/character.h
+++ b/src/game-server/character.h
@@ -348,12 +348,31 @@ class Character : public Being
void setCorrectionPoints(int points) { mCorrectionPoints = points; }
int getCorrectionPoints() const { return mCorrectionPoints; }
- void setNpcThread(Script::Thread *thread)
- { mNpcThread = thread; }
+ /**
+ * Starts the given NPC thread.
+ *
+ * Should be called immediately after creating the thread and pushing
+ * the NPC function and its parameters.
+ */
+ void startNpcThread(Script::Thread *thread, int npcId);
+
+ /**
+ * Resumes the given NPC thread of this character and sends the NPC
+ * close message to the player when the script is done.
+ *
+ * Should be called after preparing the current Script instance for
+ * resuming the thread and pushing the parameters the script expects.
+ */
+ void resumeNpcThread();
+
+ /**
+ * Returns the NPC thread in use by this character, if any.
+ */
Script::Thread *getNpcThread() const
{ return mNpcThread; }
+
/**
* Gets the way the actor is blocked by other things on the map
*/
@@ -472,6 +491,8 @@ class Character : public Being
int mParty; /**< Party id of the character */
TransactionType mTransaction; /**< Trade/buy/sell action the character is involved in. */
std::map<int, int> mKillCount; /**< How many monsters the character has slain of each type */
+
+ int mTalkNpcId; /**< Public ID of NPC the character is talking to, if any */
Script::Thread *mNpcThread; /**< Script thread executing NPC interaction, if any */
static Script::Ref mDeathCallback;
diff --git a/src/game-server/mapcomposite.cpp b/src/game-server/mapcomposite.cpp
index a0d48f5b..6b2b74f9 100644
--- a/src/game-server/mapcomposite.cpp
+++ b/src/game-server/mapcomposite.cpp
@@ -769,12 +769,14 @@ void MapComposite::initializeContent()
else if (utils::compareStrI(type, "NPC") == 0)
{
int npcId = utils::stringToInt(object->getProperty("NPC_ID"));
+ std::string gender = object->getProperty("GENDER");
std::string scriptText = object->getProperty("SCRIPT");
if (npcId && !scriptText.empty())
{
Script *script = ScriptManager::currentState();
script->loadNPC(object->getName(), npcId,
+ ManaServ::getGender(gender),
object->getX(), object->getY(),
scriptText.c_str());
}
diff --git a/src/game-server/npc.cpp b/src/game-server/npc.cpp
index aa032c98..5583c3d5 100644
--- a/src/game-server/npc.cpp
+++ b/src/game-server/npc.cpp
@@ -19,13 +19,12 @@
*/
#include "game-server/character.h"
+#include "game-server/gamehandler.h"
#include "game-server/npc.h"
+#include "net/messageout.h"
#include "scripting/script.h"
#include "scripting/scriptmanager.h"
-Script::Ref NPC::mStartCallback;
-Script::Ref NPC::mUpdateCallback;
-
NPC::NPC(const std::string &name, int id):
Being(OBJECT_NPC),
mID(id),
@@ -34,7 +33,14 @@ NPC::NPC(const std::string &name, int id):
setName(name);
}
-void NPC::enable(bool enabled)
+NPC::~NPC()
+{
+ Script *script = ScriptManager::currentState();
+ script->unref(mTalkCallback);
+ script->unref(mUpdateCallback);
+}
+
+void NPC::setEnabled(bool enabled)
{
mEnabled = enabled;
}
@@ -52,7 +58,7 @@ void NPC::update()
void NPC::prompt(Character *ch, bool restart)
{
- if (!mEnabled || !mStartCallback.isValid())
+ if (!mEnabled || !mTalkCallback.isValid())
return;
Script *script = ScriptManager::currentState();
@@ -61,12 +67,10 @@ void NPC::prompt(Character *ch, bool restart)
{
Script::Thread *thread = script->newThread();
thread->mMap = getMap();
- script->prepare(mStartCallback);
+ script->prepare(mTalkCallback);
script->push(this);
script->push(ch);
-
- if (!script->resume())
- ch->setNpcThread(thread);
+ ch->startNpcThread(thread, getPublicID());
}
else
{
@@ -75,8 +79,7 @@ void NPC::prompt(Character *ch, bool restart)
return;
script->prepareResume(thread);
- if (script->resume())
- ch->setNpcThread(0);
+ ch->resumeNpcThread();
}
}
@@ -92,8 +95,7 @@ void NPC::select(Character *ch, int index)
Script *script = ScriptManager::currentState();
script->prepareResume(thread);
script->push(index);
- if (script->resume())
- ch->setNpcThread(0);
+ ch->resumeNpcThread();
}
void NPC::integerReceived(Character *ch, int value)
@@ -108,8 +110,7 @@ void NPC::integerReceived(Character *ch, int value)
Script *script = ScriptManager::currentState();
script->prepareResume(thread);
script->push(value);
- if (script->resume())
- ch->setNpcThread(0);
+ ch->resumeNpcThread();
}
void NPC::stringReceived(Character *ch, const std::string &value)
@@ -124,6 +125,17 @@ void NPC::stringReceived(Character *ch, const std::string &value)
Script *script = ScriptManager::currentState();
script->prepareResume(thread);
script->push(value);
- if (script->resume())
- ch->setNpcThread(0);
+ ch->resumeNpcThread();
+}
+
+void NPC::setTalkCallback(Script::Ref function)
+{
+ ScriptManager::currentState()->unref(mTalkCallback);
+ mTalkCallback = function;
+}
+
+void NPC::setUpdateCallback(Script::Ref function)
+{
+ ScriptManager::currentState()->unref(mUpdateCallback);
+ mUpdateCallback = function;
}
diff --git a/src/game-server/npc.h b/src/game-server/npc.h
index 4bff9af0..f62f72c7 100644
--- a/src/game-server/npc.h
+++ b/src/game-server/npc.h
@@ -22,8 +22,8 @@
#define GAMESERVER_NPC_H
#include "game-server/being.h"
+#include "scripting/script.h"
-class Script;
class Character;
/**
@@ -34,12 +34,27 @@ class NPC : public Being
public:
NPC(const std::string &name, int id);
+ ~NPC();
+
+ /**
+ * Sets the function that should be called when this NPC is talked to.
+ */
+ void setTalkCallback(Script::Ref function);
+
+ /**
+ * Sets the function that should be called each update.
+ */
+ void setUpdateCallback(Script::Ref function);
+
+ /**
+ * Calls the update callback, if any.
+ */
void update();
/**
- * Enables the NPC
+ * Sets whether the NPC is enabled.
*/
- void enable(bool enabled);
+ void setEnabled(bool enabled);
/**
* Prompts NPC.
@@ -73,12 +88,6 @@ class NPC : public Being
virtual unsigned char getWalkMask() const
{ return 0x83; } // blocked like a monster by walls, monsters and characters ( bin 1000 0011)
- static void setStartCallback(Script *script)
- { script->assignCallback(mStartCallback); }
-
- static void setUpdateCallback(Script *script)
- { script->assignCallback(mUpdateCallback); }
-
protected:
/**
* Gets the way a monster blocks pathfinding for other objects
@@ -90,8 +99,8 @@ class NPC : public Being
unsigned short mID; /**< ID of the NPC. */
bool mEnabled; /**< Whether NPC is enabled */
- static Script::Ref mStartCallback;
- static Script::Ref mUpdateCallback;
+ Script::Ref mTalkCallback;
+ Script::Ref mUpdateCallback;
};
#endif // GAMESERVER_NPC_H