Vorbereitungen Empfang TMs, wenn offline.
Wenn ein Spieler/Magier auch in Abwesenheit TMs empfangen koennen
will, kann das Spielerobjekt beim zentralen KOBOLD (/secure/kobold)
ein "Vault" deponieren.
Ist die Empfaengerin eines TMs nicht anwesend (und auch kein anderes
Lebewesen mit dem Namen), fragt das Spielerobjekt, ob der KOBOLD
ein passendes Vault hat. Wenn ja, wird das TM dort abgelegt,
aehnlich bei beim konventionellen Kobold.
Die Vaults sind LWOs, auf welche Spielerobjekte und der KOBOLD eine
Referenz haben. Wenn das Spielerobjekt neu erzeugt wird, fragt es
beim KOBOLD, ob ein Vault existiert und bekommt ggf. eine Referenz.
Es kann dann die gespeicherten Nachrichten aus dem Vault abrufen.
Dieser Commit erzeugt das Grundgeruest von KOBOLD und der Vaults
und ermoeglicht das Speichern von Nachrichten dort.
Die tatsaechliche Moeglichkeit des Deponierens des Vaults im
KOBOLD folgt spaeter.
Change-Id: I56604858a38482c8f9844b9f371d9fb6950bf1f9
diff --git a/secure/kobold.c b/secure/kobold.c
new file mode 100644
index 0000000..b1be5aa
--- /dev/null
+++ b/secure/kobold.c
@@ -0,0 +1,103 @@
+// The Manager Kobold who supervises storage of the comm vaults for players
+//
+// no retrieval of messages by this object. Player objects retrieve their LWO
+// (Kobold-Vault) from here. The Vaults only release messages to their
+// corresponding player object
+
+#pragma strict_types,rtt_checks
+
+#include "/sys/player/comm.h"
+
+mapping vaults = ([]);
+
+protected void create()
+{
+ // TODO: Speichern in MEMORY
+}
+
+// Einlagern von Vaults durch Spieler
+public int DepositVault(lwobject "/std/player/comm_vault" vault)
+{
+ if (query_once_interactive(previous_object())) {
+ vaults[getuid(previous_object())] = vault;
+ return 1;
+ }
+ return 0;
+}
+
+// Abrufen eines Pointers auf den Vault eines Spielers
+// Natuerlich *nur* durch den Spieler mit der richtigen UUID selber.
+public lwobject "/std/player/comm_vault" RetrieveVault()
+{
+ if (query_once_interactive(previous_object()))
+ {
+ lwobject "/std/player/comm_vault" vault = vaults[getuid(previous_object())];
+ // Und noch pruefen, ob auch die UUID uebereinstimmt - es soll kein
+ // neu angelegter Spieler das Vault von einem aelteren bekommen.
+ if (vault &&
+ ({string})vault.uuid() == getuuid(previous_object()))
+ return vault;
+ }
+ return 0;
+}
+
+// Pointer auf nen Vault vergessen.
+// Im Erfolgsfall wird das Vault zurueckgeben.
+// Aufruf *nur* durch den Spieler mit der richtigen UUID selber.
+public lwobject "/std/player/comm_vault" ForgetVault()
+{
+ if (query_once_interactive(previous_object()))
+ {
+ lwobject "/std/player/comm_vault" vault = vaults[getuid(previous_object())];
+ // Und noch pruefen, ob auch die UUID uebereinstimmt - es soll kein
+ // neu angelegter Spieler das Vault von einem aelteren bekommen.
+ if (({string})vault.uuid() == getuuid(previous_object()))
+ {
+ m_delete(vaults, getuid(previous_object()));
+ return vault;
+ }
+ }
+ return 0;
+}
+
+// Prueft, ob es ein Vault fuer Spieler gibt, deren UID mit <pluid> beginnen.
+// gibt im Erfolgsfall die vollstaendige UID zurueck.
+// 0, wenn keine gefunden
+// -1 wenn es mehrere in Frage kommende UIDs gibt.
+// (match_living()-inspiriert)
+public string|int find_player(string pluid)
+{
+ string uid;
+ if (pluid in vaults)
+ return pluid; // das war einfach...
+ else
+ {
+ // Wir muessen leider alle Vaults absuchen
+ foreach(string u : vaults) {
+ if (strstr(u, pluid) == 0)
+ {
+ // wenn pluid nicht eindeutig ist und mehrere UIDs in Frage
+ // kommen, wird -1 zurueckgeben.
+ if (!uid)
+ uid = u;
+ else
+ return -1;
+ }
+ }
+ }
+ return uid;
+}
+
+public varargs int DepositMsg(string pluid, string msg, int msg_type,
+ string msg_action, string msg_prefix,
+ object origin = previous_object())
+{
+ if (!query_once_interactive(previous_object()))
+ return MSG_FAILED;
+ lwobject "/std/player/comm_vault" vault = vaults[pluid];
+ if (!vault)
+ return MSG_FAILED;
+
+ return ({int})vault.store_msg(msg, msg_type, msg_action, msg_prefix, origin);
+}
+
diff --git a/std/player/comm.c b/std/player/comm.c
index 312f7e5..2dc0601 100644
--- a/std/player/comm.c
+++ b/std/player/comm.c
@@ -18,12 +18,12 @@
#include <player/quest.h>
#include <player/gmcp.h>
#include <living/description.h>
+#include <player/comm.h>
#undef NEED_PROTOTYPES
#include <sys_debug.h>
#include <thing/properties.h>
-#include <player/comm.h>
#include <player/base.h>
#include <properties.h>
@@ -68,7 +68,6 @@
private nosave struct msg_buffer_s kobold = (<msg_buffer_s>
buf: allocate(32),
index: -1,);
-#define MAX_KOBOLD_LIMIT 256
// Colourmap
// TODO: spaeter konfigurierbar machen
@@ -777,6 +776,7 @@
string msg_action, string msg_prefix)
{
int res = ob->ReceiveMsg(msg, msg_type, msg_action, msg_prefix, ME);
+
switch(res) {
case MSG_DELIVERED:
break; // nix machen
@@ -809,6 +809,41 @@
}
}
+// aehnlich wie _send(), aber gerufen, wenn die Empfaengerin nicht online ist,
+// aber ein Kobold-Vault deponiert hat und versucht werden soll, dort eine
+// Nachricht zu hinterlegen.
+private void _send_to_kobold(string pluid, string msg, int msg_type,
+ string msg_action, string msg_prefix)
+{
+ int res = KOBOLD->DepositMsg(pluid, msg, msg_type, msg_action,
+ msg_prefix, ME);
+ switch(res) {
+ case MSG_BUFFERED:
+ ReceiveMsg(sprintf("%s ist gerade nicht online, aber Deine Botschaft "
+ "wurde von einem fuer kleinen Kobold aufgeschrieben und er wird "
+ "versuchen, sie %s bei naechster Gelegenheit zu uebermitteln. "
+ "Der Kobold macht Dich darauf aufmerksam, dass er aber keine "
+ "Uebermittlung garantieren kann.",
+ capitalize(pluid), capitalize(pluid)),
+ MT_NOTIFICATION, msg_action, 0, this_object());
+ break;
+ case MSG_BUFFER_FULL:
+ ReceiveMsg(sprintf("%s ist gerade nicht online und leider ist auf "
+ "der Schriftrolle des kleinen Kobolds kein Platz mehr fuer "
+ "Deine Botschaft. Vielleicht schickst Du %s besser einen Brief.",
+ capitalize(pluid), capitalize(pluid)),
+ MT_NOTIFICATION, msg_action, 0, this_object());
+ break;
+ default:
+ ReceiveMsg(sprintf("%s ist gerade nicht online und leider konnte "
+ "sich der kleine Kobold Deine Botschaft nicht merken. "
+ "Vielleicht schickst Du %s besser einen Brief.",
+ capitalize(pluid),capitalize(pluid)),
+ MT_NOTIFICATION, msg_action, 0, this_object());
+ break;
+ }
+}
+
// Ausgabe an das Objekt selber und Aufzeichnung in der Kommhistory, falls
// noetig. Wird bei _ausgehenden_ Nachrichten im eigenen Objekt gerufen, damit
// die Nachricht ggf. in den Kommhistory erfasst wird.
@@ -1261,7 +1296,6 @@
{
object ob;
string away,myname,ret;
- mixed it;
string *xname;
int i,visflag;
@@ -1322,26 +1356,45 @@
return 1;
}
- if (!ob=find_player(it = lower_case(who)))
+ string|int lname = lower_case(who);
+ if (!ob=find_player(lname))
{
- it = match_living(it, 0);
- if (!stringp(it))
- switch(it) {
+ lname = match_living(lname, 0);
+ if (!stringp(lname))
+ {
+ switch(lname)
+ {
case -1:
ReceiveNotify("Das war nicht eindeutig!",MA_TELL);
return 1;
case -2:
- ReceiveNotify("Kein solcher Spieler!",MA_TELL);
- return 1;
+ // check KOBOLD
+ ob = find_object(KOBOLD);
+ lname = ({string|int})ob->find_player(lower_case(who));
+ if (lname == -1) {
+ ReceiveNotify("Das war nicht eindeutig!",MA_TELL);
+ return 1;
+ }
+ else if (!stringp(lname)) {
+ ReceiveNotify("Kein solcher Spieler (online)!",MA_TELL);
+ return 1;
+ }
}
- ob = find_player(it) || find_living(it);
+ // jetzt ist ob der KOBOLD und lname die UID eines Spielers.
+ }
+ // Wenn wir noch kein ob haben, sollte lname jetzt aber durch das
+ // match_living() der Name eines Livings sein, dessen Objekt wir noch
+ // brauchen.
+ if (!ob)
+ ob = find_player(lname) || find_living(lname);
if(!ob) {
- ReceiveNotify("Kein solcher Spieler!",MA_TELL);
+ ReceiveNotify("Kein solcher Spieler (online)!",MA_TELL);
return 1;
}
}
- if(QueryProp(P_INVIS)){
+ if(QueryProp(P_INVIS))
+ {
if(!IS_LEARNER(ob))
myname = name();
else
@@ -1352,19 +1405,27 @@
else
myname=((IS_LEARNER(ME) && (QueryProp(P_CAN_FLAGS) & CAN_PRESAY)) ?
QueryProp(P_PRESAY):"") + capitalize(getuid(ME));
- if (myname && sizeof(myname)) myname=capitalize(myname);
- // erstmal an Empfaenger senden
- _send(ob, permutate(msg), MT_COMM|MT_FAR|MSG_ALERT, MA_TELL,
- myname + " teilt Dir mit: ");
+ if (myname && sizeof(myname))
+ myname=capitalize(myname);
+
+ // Wir haben Zielobjekt und unseren eigenen Namen. Erstmal an Empfaenger
+ // senden.
+ if (living(ob))
+ _send(ob, permutate(msg), MT_COMM|MT_FAR|MSG_ALERT, MA_TELL,
+ myname + " teilt Dir mit: ");
+ else
+ _send_to_kobold(lname, permutate(msg), MT_COMM|MT_FAR|MSG_ALERT, MA_TELL,
+ myname + " teilt Dir mit: ");
// dann evtl. noch an Absender ausgeben...
- if (visflag = !ob->QueryProp(P_INVIS) || IS_LEARNER(this_player()))
- _recv(ob, msg, MSGFLAG_TELL, "Du teilst " + capitalize(it) + " mit: ");
+ visflag = !ob->QueryProp(P_INVIS);
+ if (visflag || IS_LEARNER(this_player()))
+ _recv(ob, msg, MSGFLAG_TELL, "Du teilst " + capitalize(lname) + " mit: ");
// oder irgendwas anderes an den Absender ausgeben...
if (!visflag && interactive(ob))
- ReceiveNotify("Kein solcher Spieler!",MA_TELL);
+ ReceiveNotify("Kein solcher Spieler online!",MA_TELL);
else if (away = ({string})ob->QueryProp(P_AWAY))
- ReceiveMsg( break_string( away, 78, capitalize(it)
+ ReceiveMsg( break_string( away, 78, capitalize(lname)
+ " ist gerade nicht da: ", BS_INDENT_ONCE ),
MT_NOTIFICATION|MSG_DONT_WRAP|MSG_DONT_IGNORE,
MA_TELL, 0, this_object());
@@ -1376,7 +1437,7 @@
away=time2string("%h %H und %m %M",i);
ReceiveNotify(sprintf("%s ist seit %s voellig untaetig.",
- capitalize(it),away),
+ capitalize(lname),away),
MA_TELL);
}
@@ -1456,7 +1517,7 @@
Nachricht nicht in der tell_history verewigt. */
object ob;
- string who, it;
+ string who;
string msg;
string myname;
@@ -1467,25 +1528,31 @@
return 1;
}
- if (!ob=find_player(it = lower_case(who)))
+ string|int lname = lower_case(who);
+ if (!ob=find_player(lname))
{
- it = match_living(it, 0);
- if (!stringp(it))
- switch(it){
+ lname = match_living(lname, 0);
+ if (!stringp(lname))
+ {
+ switch(lname)
+ {
case -1:
- ReceiveNotify("Das war nicht eindeutig!",MA_EMOTE);
+ ReceiveNotify("Das war nicht eindeutig!",MA_TELL);
return 1;
case -2:
- ReceiveNotify("Kein solcher Spieler!",MA_EMOTE);
+ // rfluester benutzt keinen KOBOLD.
+ ReceiveNotify("Kein solcher Spieler!",MA_TELL);
return 1;
}
- ob = find_player(it);
- if(!ob) ob = find_living(it);
- if(!ob){
- ReceiveNotify("Kein solcher Spieler!",MA_EMOTE);
+ }
+ // lname sollte nun eindeutig sein.
+ ob = find_player(lname) || find_living(lname);
+ if(!ob) {
+ ReceiveNotify("Kein solcher Spieler online!",MA_TELL);
return 1;
}
}
+
if (environment(ob) == environment()) {
ReceiveNotify("Wenn jemand neben Dir steht, nimm fluester.",MA_EMOTE);
return 1;
@@ -1499,10 +1566,9 @@
// An Empfaenger senden.
_send(ob, permutate(msg), MT_COMM|MT_FAR|MSG_DONT_STORE,
MA_EMOTE, myname + " fluestert Dir aus der Ferne zu: ");
-
// wenn Empfaenger invis und wir kein Magier , ggf. fakefehler ausgeben.
if (ob->QueryProp(P_INVIS) && !IS_LEARNER(this_player())) {
- ReceiveNotify("Kein solcher Spieler!",MA_EMOTE);
+ ReceiveNotify("Kein solcher Spieler online!",MA_EMOTE);
return 1;
}
// sonst eigene Meldung via _recv() ausgeben.
diff --git a/std/player/comm_vault.c b/std/player/comm_vault.c
new file mode 100644
index 0000000..81541d6
--- /dev/null
+++ b/std/player/comm_vault.c
@@ -0,0 +1,58 @@
+#pragma strict_types, rtt_checks, lightweight
+
+#define NEED_PROTOTYPES
+#include <player/comm.h>
+
+inherit "/std/player/comm_structs";
+
+nosave string uuid;
+// nosave ist wichtig - niemand soll den buffer mit save_value() auslesen
+// koennen!
+nosave struct stored_msg_s *buffer = ({});
+
+protected void create_lw()
+{
+ uuid = getuuid(previous_object());
+}
+
+public string uuid()
+{
+ return uuid;
+}
+
+public struct stored_msg_s *Retrieve()
+{
+// if (getuid(this_object()) == getuid(previous_object()))
+ {
+ return buffer;
+ }
+ return 0;
+}
+
+public void Empty()
+{
+// if (getuid(this_object()) == getuid(previous_object()))
+ {
+ buffer = ({});
+ }
+}
+
+public int store_msg(string msg, int msg_type, string msg_action,
+ string msg_prefix, object origin)
+{
+ // Nur KOBOLD in /secure darf Nachrichten speichern und es werden nur
+ // Nachrichten von Spielern/Magiern gespeichert.
+ if (object_name(previous_object()) != KOBOLD
+ || !query_once_interactive(origin))
+ return MSG_FAILED;
+ if (sizeof(buffer) >= MAX_KOBOLD_LIMIT)
+ return MSG_BUFFER_FULL;
+
+ buffer += ({ (<stored_msg_s> msg:msg, type:msg_type,
+ prefix: msg_prefix, action: msg_action,
+ sendername: ({string})origin.query_real_name(),
+ timestamp: time())
+ });
+ return MSG_BUFFERED;
+}
+
diff --git a/sys/player/comm.h b/sys/player/comm.h
index 281881e..709931b 100644
--- a/sys/player/comm.h
+++ b/sys/player/comm.h
@@ -78,6 +78,9 @@
#define DO_REPORT_WIMPY 0x8
#define DO_REPORT_WIMPY_DIR 0x10
+// Pfad zum (Offline-) Kobold
+#define KOBOLD "/secure/kobold"
+
#endif // __PLAYER_COMM_H__
#ifdef NEED_PROTOTYPES
@@ -85,6 +88,8 @@
#ifndef __PLAYER_COMM_H_PROTO__
#define __PLAYER_COMM_H_PROTO__
+#define MAX_KOBOLD_LIMIT 256
+
// prototypes
protected varargs int _recv(object ob, string message,