Added public files
Roughly added all public files. Probably missed some, though.
diff --git a/std/living/moving.c b/std/living/moving.c
new file mode 100644
index 0000000..c6149ff
--- /dev/null
+++ b/std/living/moving.c
@@ -0,0 +1,457 @@
+// MorgenGrauen MUDlib
+//
+// living/moving.c -- moving of living objects
+//
+// $Id: moving.c 9448 2016-01-22 17:52:28Z Zesstra $
+#pragma strong_types
+#pragma save_types
+#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+inherit "/std/thing/moving";
+
+#define NEED_PROTOTYPES
+#include <hook.h>
+#include <living/moving.h>
+#include <living/skills.h>
+#include <thing/properties.h>
+#include <thing/description.h>
+#include <moving.h>
+#include <new_skills.h>
+#include <living.h>
+
+#undef NEED_PROTOTYPES
+
+#include <config.h>
+#include <properties.h>
+#include <language.h>
+#include <wizlevels.h>
+#include <defines.h>
+
+
+protected void create()
+{
+ if (object_name(this_object()) == __FILE__[0..<3])
+ {
+ return;
+ }
+ offerHook(H_HOOK_MOVE,1);
+}
+
+public void AddPursuer(object ob)
+{
+ mixed *pur;
+
+ if (!objectp(ob))
+ return;
+
+ if (!pointerp(pur=Query(P_PURSUERS)))
+ pur=({0,({})});
+ else if (member(pur[1],ob)!=-1)
+ return;
+
+ SetProp(P_PURSUERS,({ pur[0], pur[1]+({ob})-({0}) }));
+ ob->_SetPursued(ME);
+}
+
+public void RemovePursuer(object ob)
+{
+ mixed *pur;
+
+ if (pointerp(pur=Query(P_PURSUERS,F_VALUE))
+ && member(pur[1],ob)!=-1)
+ {
+ pur[1]-=({ob,0});
+ if (ob)
+ ob->_RemovePursued(ME);
+ if (!pur[0]&&!sizeof(pur[1]))
+ pur=0;
+ SetProp(P_PURSUERS,pur);
+ }
+}
+
+public void _SetPursued(object ob)
+{
+ mixed *pur;
+
+ if (!pointerp(pur=Query(P_PURSUERS)))
+ pur=({0,({})});
+ else
+ if (objectp(pur[0]))
+ pur[0]->RemovePursuer(ME);
+ pur[0]=ob;
+ pur[1]-=({0});
+ Set(P_PURSUERS,pur);
+}
+
+public void _RemovePursued(object ob)
+{
+ mixed *pur;
+
+ if (!pointerp(pur=Query(P_PURSUERS)) || pur[0]!=ob)
+ return;
+ pur[0]=0;
+ pur[1]-=({0});
+ if (!sizeof(pur[1]))
+ pur=0;
+ Set(P_PURSUERS,pur);
+}
+
+
+private void kampfende( object en ) {
+ if (!objectp(en)) return;
+ tell_object( ME, capitalize(en->name()) +
+ " ist jetzt hinter Dir her.\n" );
+ tell_object( en, "Du verfolgst jetzt " + name(WEN) + ".\n" );
+ en->InsertSingleEnemy(ME);
+}
+
+private int _is_learner(object pl) {
+ return IS_LEARNER(pl);
+}
+
+
+// a) Pruefungen, ob das move erlaubt ist.
+// b) zum Ueberschreiben
+protected int PreventMove(object dest, object oldenv, int method) {
+
+ // M_NOCHECK? -> Bewegung eh erlaubt (und Rueckgabewert wuerde ignoriert),
+ // aber PreventInsert/PreventLeave() rufen und ignorieren.
+ if ((method&M_NOCHECK)) {
+ // erst PreventLeaveLiving() rufen...
+ if(environment())
+ environment()->PreventLeaveLiving(this_object(), dest);
+ // dann PreventInsertLiving() im Ziel-Env.
+ dest->PreventInsertLiving(this_object());
+ // und raus...
+ return(0);
+ }
+
+ // bei Lebewesen muss die Bewegungsmethode M_GO und M_TPORT sein. Dies ist
+ // gleichzeigt die Restriktion gegen das Nehmen von Lebewesen, da dort
+ // M_GET/M_GIVE/M_PUT etc. verwendet wuerde. Bei M_GO und M_TPORT findet
+ // keine Pruefung statt, ob das Objekt ins Ziel 'reinpasst' (Gewicht, Anzahl
+ // Objekte usw.).
+ // Ich finde es etwas merkwuerdig gebaut (Zesstra).
+ if ( !(method & (M_GO | M_TPORT)) )
+ return ME_PLAYER;
+
+ // alte und neue Umgebung auf NO_TPORT pruefen.
+ if ( (method & M_TPORT) ) {
+ if ( environment() &&
+ (environment()->QueryProp(P_NO_TPORT) & (NO_TPORT_OUT|NO_TPORT)) )
+ return ME_CANT_TPORT_OUT;
+ else if ( dest->QueryProp(P_NO_TPORT) & (NO_TPORT_IN|NO_TPORT) )
+ return ME_CANT_TPORT_IN;
+ }
+
+ // erst PreventLeaveLiving() testen...
+ if( environment() && environment()->PreventLeaveLiving(this_object(), dest))
+ return ME_CANT_LEAVE_ENV;
+ // dann PreventInsertLiving() im Ziel-Env
+ if (dest->PreventInsertLiving(this_object()))
+ return ME_CANT_BE_INSERTED;
+
+ return 0;
+}
+
+// Krams nach dem Move machen und nebenbei zum Ueberschreiben.
+protected void NotifyMove(object dest, object oldenv, int method) {
+ mixed res;
+ object enem;
+
+ // Begruessungsschlag fuer die Gegener
+ if ( !(method & M_NO_ATTACK) )
+ InitAttack();
+
+ if (!objectp(ME)) return;
+
+ // Verfolger nachholen.
+ if ( pointerp(res = Query(P_PURSUERS)) && sizeof(res[1]) ) {
+ while ( remove_call_out( "TakeFollowers" ) >= 0 );
+
+ call_out( "TakeFollowers", 0 );
+ }
+
+ // und noch das Team nachholen.
+ if ( oldenv != dest
+ && objectp(ME)
+ && QueryProp(P_TEAM_AUTOFOLLOW)
+ && objectp( enem = IsTeamLeader() ) )
+ enem->StartFollow(oldenv); // Teamverfolgung
+
+}
+
+varargs public int move( object|string dest, int method, string direction,
+ string textout, string textin )
+{
+ int para, nightvis, invis, tmp;
+ object oldenv, *inv;
+ string fn,vc;
+ mixed res;
+ mixed hookData, hookRes;
+
+ if (!objectp(dest) && !stringp(dest))
+ raise_error(sprintf("Wrong argument 1 to move(). 'dest' must be a "
+ "string or object! Argument was: %.100O\n",
+ dest));
+
+ // altes Env erstmal merken.
+ oldenv = environment();
+
+ //erstmal den richtigen Zielraum suchen, bevor irgendwelche Checks gemacht
+ //werden...
+ // Ist der Spieler in einer Parallelwelt?
+ if ( (para = QueryProp(P_PARA)) && intp(para) ) {
+ fn = objectp(dest) ? object_name(dest) : dest;
+
+ // Falls der Zielraum nicht schon explizit in der Parallelwelt ist,
+ // neuen Zielraum suchen. Aber nur, wenn fn kein # enthaelt (also kein
+ // Clone ist), sonst wuerde eine Bewegung nach raum#42^para versucht,
+ // was dann buggt. ;-) Problem wird offenbar, wenn ein Para-Lebewesen
+ // im create() eines VC-Raums in Para in den Raum bewegt wird, da
+ // dieser dann noch nicht vom Driver umbenannt wurde und raum#42
+ // heisst.
+ if ( !sizeof(regexp( ({ fn }), "\\^[1-9][0-9]*$" )) &&
+ strrstr(fn,"#")==-1 )
+ {
+ fn += "^" + para;
+
+ // Der Parallelwelt-Raum muss existieren und fuer Spieler
+ // freigegeben sein, damit er zum neuen Ziel wird. Ansonsten
+ // duerfen nur NPCs, Testspieler und Magier herein.
+ if ( (find_object(fn)
+ || ((file_size(fn+".c")>0 ||
+ (file_size(vc=implode(explode(fn,"/")[0..<2],"/")+
+ "/virtual_compiler.c")>0 &&
+ !catch(tmp=(int)call_other(vc,"QueryValidObject",fn);
+ publish) && tmp>0)) &&
+ !catch(load_object(fn);publish) )) &&
+ (!interactive(ME) || !fn->QueryProp(P_NO_PLAYERS) ||
+ (method & M_NOCHECK) || IS_LEARNER(ME) ||
+ (stringp(res = QueryProp(P_TESTPLAYER)) &&
+ IS_LEARNER( lower_case(res) ))) )
+ {
+ dest = fn;
+ }
+ else
+ {
+ // Wir bleiben in der Normalwelt.
+ para = 0;
+ }
+ }
+ }
+
+ // jetzt erstmal Hooks abpruefen, da sie ggf. die Daten aendern.
+ // alten P_TMP_MOVE_HOOK pruefen.
+ if ( res = QueryProp(P_TMP_MOVE_HOOK) ){
+ if ( pointerp(res) && sizeof(res) >= 3
+ && intp(res[0]) && time()<res[0]
+ && objectp(res[1]) && stringp(res[2]) ){
+ if ( res = call_other( res[1], res[2], dest, method, direction,
+ textout, textin ) ){
+ if ( pointerp(res) && sizeof(res) == 5 ){
+ dest = res[0];
+ method = res[1];
+ direction = res[2];
+ textout = res[3];
+ textin = res[4];
+ }
+ else if ( intp(res) && res == -1 )
+ return ME_CANT_LEAVE_ENV;
+ }
+ } else
+ SetProp( P_TMP_MOVE_HOOK, 0 );
+ }
+ // move hook nach neuem Hooksystem triggern.
+ hookData=({dest,method,direction,textout,textin});
+ hookRes=HookFlow(H_HOOK_MOVE,hookData);
+ if(hookRes && pointerp(hookRes) && sizeof(hookRes)>H_RETDATA) {
+ if(hookRes[H_RETCODE]==H_CANCELLED) {
+ return ME_CANT_LEAVE_ENV;
+ }
+ else if(hookRes[H_RETCODE]==H_ALTERED && hookRes[H_RETDATA] &&
+ pointerp(hookRes[H_RETDATA]) && sizeof(hookRes[H_RETDATA])>=5 ){
+ dest = hookRes[H_RETDATA][0];
+ method = hookRes[H_RETDATA][1];
+ direction = hookRes[H_RETDATA][2];
+ textout = hookRes[H_RETDATA][3];
+ textin = hookRes[H_RETDATA][4];
+ }
+ }
+
+ // dest auf Object normieren
+ if (stringp(dest)) dest=load_object(dest);
+
+ // jetzt Checks durchfuehren, ob das Move durchgefuehrt werden darf.
+ if (tmp=PreventMove(dest, oldenv, method)) {
+ // auf gueltigen Fehler pruefen, wer weiss, was Magier da evtl.
+ // versehentlich zurueckgeben.
+ if (VALID_MOVE_ERROR(tmp))
+ return(tmp);
+ else
+ return(ME_DONT_WANT_TO_BE_MOVED);
+ }
+
+ if ( invis = QueryProp(P_INVIS) )
+ method |= M_SILENT;
+
+ if ( objectp(oldenv) ) {
+ if ( !(method & M_SILENT) ) {
+ string *mout;
+ if ( !textout ){
+ if ( method & M_TPORT )
+ textout = (string) QueryProp(P_MMSGOUT) ||
+ (string) QueryProp(P_MSGOUT);
+ else
+ textout = (mout = explode( (string)
+ QueryProp(P_MSGOUT) || "",
+ "#" ))[0]
+ || (string)QueryProp(P_MMSGOUT);
+ }
+
+ if ( !sizeof(direction) )
+ direction = 0;
+
+ inv = all_inventory(environment()) - ({ this_object() });
+ inv = filter( inv, #'living/*'*/ );
+ inv -= filter_objects( inv, "CannotSee", 1 );
+
+ filter( inv, #'tell_object/*'*/,
+ Name( WER, 2 ) + " " + textout +
+ (direction ? " " + direction : "") +
+ (sizeof(mout) > 1 ? mout[1] : "") + ".\n" );
+ }
+ // Magier sehen auch Bewegungen, die M_SILENT sind
+ else if ( interactive(ME) ){
+ inv = (all_inventory(environment()) & users())
+ - ({ this_object() });
+ inv = filter( inv, #'_is_learner/*'*/ );
+
+ if ( invis )
+ fn = "(" + capitalize(getuid(ME)) + ") verschwindet "
+ "unsichtbar.\n";
+ else
+ fn = capitalize(getuid(ME)) + " verschwindet ganz leise.\n";
+
+ filter( inv, #'tell_object/*'*/, fn );
+ }
+
+ // Nackenschlag beim Fluechten:
+ if ( !(method & M_NO_ATTACK) && objectp(ME) )
+ ExitAttack();
+ //falls nach ExitAttack() das Living nicht mehr existiert, muss das
+ //move() auch nicht mehr fortgesetzt werden. Weiter unten gibt es auch
+ //min. eine Stelle, die nicht prueft und ggf. buggt. Daher erfolgt
+ //hier ggf. ein Abbruch. 15.11.06 Zesstra
+ if (!objectp(ME)) return(ME_WAS_DESTRUCTED);
+
+ // Nackenschlag kann ME in den Todesraum bewegt haben...
+ if ( oldenv == environment() ) {
+ // Fuer alle anwesenden gegner kampfende() aufrufen
+ filter((QueryEnemies()[0] & all_inventory(oldenv))-({0}),
+ #'kampfende);
+ // Bugs im exit() sind ohne catch() einfach mist.
+ catch(environment()->exit(ME, dest);publish);
+ }
+ }
+
+ // irgendwas kann das Objekt zerstoert haben, z.B. env->exit().
+ if (!objectp(ME)) return(ME_WAS_DESTRUCTED);
+
+ if ( oldenv != environment() )
+ // Der Nackenschlag oder exit() koennen einen schon bewegt haben.
+ // Und wenn es in den Todesraum ist. ;^)
+ return MOVE_OK;
+
+ SetProp( P_PREPARED_SPELL, 0 ); // Spruchvorbereitung abgebrochen
+ SetProp( P_LAST_MOVE, time() ); // Zeitpunkt der letzten Bewegung
+
+ move_object(ME, dest);
+ if (!objectp(ME))
+ return(ME_WAS_DESTRUCTED);
+
+ dest = environment();
+
+ nightvis = UseSkill(SK_NIGHTVISION);
+ // Meldungen an nicht-Blinde ausgeben, falls keine 'stille' Bewegung
+ if ( !(method & M_SILENT) ) {
+ if ( !textin ) {
+ if ( method & M_TPORT )
+ textin = (string) QueryProp(P_MMSGIN);
+ else
+ textin = (string) QueryProp(P_MSGIN);
+ }
+
+ inv = all_inventory(environment()) - ({ this_object() });
+ inv = filter( inv, #'living/*'*/ );
+ inv -= filter_objects( inv, "CannotSee", 1 );
+ filter( inv, #'tell_object/*'*/,
+ capitalize(name( WER, 0 )) + " " + textin + ".\n" );
+ }
+ // sonst: Magier sehen auch M_SILENT-Bewegungen, hier also nur an Magier
+ // ausgeben, alle anderen sehen eh nix.
+ else if ( interactive(ME) ) {
+ inv = (all_inventory(environment()) & users()) - ({this_object()});
+ inv = filter( inv, #'_is_learner/*'*/ );
+ if ( invis )
+ fn = "(" + capitalize(getuid(ME)) + ") taucht unsichtbar auf.\n";
+ else
+ fn = capitalize(getuid(ME)) + " schleicht leise herein.\n";
+ filter( inv, #'tell_object, fn );
+ }
+
+ // "Objekt" ueber das Move informieren.
+ NotifyMove(dest, oldenv, method);
+
+ // InitAttack() in NotifyMove() kann das Objekt zerstoert haben.
+ if (!objectp(ME))
+ return(ME_WAS_DESTRUCTED);
+
+ //scheint wohl geklappt zu haben.
+ return MOVE_OK;
+}
+
+public void TakeFollowers()
+{
+ mixed *f,env;
+ int meth,i,r;
+
+ f=Query(P_PURSUERS);
+ if (!pointerp(f))
+ return;
+ env=environment();
+ if(object_name(env) == "/room/netztot") return;
+ foreach(object follower: f[1]-({0}) ) {
+ // die pruefung auf objectp ist nicht verrueckt, es kann theo. sein, dass
+ // Verfolger im PreventFollow() oder in ihrem move/init andere Verfolger
+ // zerstoeren.
+ if (objectp(follower) && environment(follower)!=env) {
+ //meth=M_NOCHECK;
+ meth=M_GO;
+ if (follower->Query(P_FOLLOW_SILENT))
+ meth|=M_SILENT|M_NO_SHOW;
+ catch(r=follower->PreventFollow(env);publish);
+ if (!r)
+ follower->move(env,meth);
+ else if (r==2)
+ RemovePursuer(follower);
+ }
+ }
+}
+
+varargs public int remove()
+{ object team;
+
+ if (environment())
+ {
+ if ( objectp(team=Query(P_TEAM)) )
+ catch(team->RemoveMember(ME);publish);
+
+ environment()->NotifyRemove(ME);
+ }
+ destruct(ME);
+ return 1;
+}
+