MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame^] | 1 | // MorgenGrauen MUDlib |
| 2 | // |
| 3 | // thing/moving.c -- object moving |
| 4 | // |
| 5 | // $Id: moving.c 8892 2014-08-04 19:48:28Z Zesstra $ |
| 6 | |
| 7 | #pragma strict_types |
| 8 | #pragma save_types |
| 9 | #pragma range_check |
| 10 | #pragma no_clone |
| 11 | #pragma pedantic |
| 12 | |
| 13 | #include <defines.h> |
| 14 | #include <moving.h> |
| 15 | #include <properties.h> |
| 16 | #define NEED_PROTOTYPES |
| 17 | #include <thing/properties.h> |
| 18 | |
| 19 | // Das Objekt bewegen. |
| 20 | // Rueckgabe 1 ist Erfolg, <=0 ist Fehler |
| 21 | |
| 22 | // a) P_NODROP/P_NOGET-Behandlung. |
| 23 | // b) zum Ueberschreiben |
| 24 | protected int PreventMove(object dest, object oldenv, int method) { |
| 25 | int tmp; |
| 26 | |
| 27 | // M_NOCHECK? -> Bewegung eh erlaubt (und Rueckgabewert wuerde ignoriert) |
| 28 | if ((method&M_NOCHECK)) { |
| 29 | // Bei M_NOCHECK zwar Prevent* aufrufen, aber das Resultat ignorieren |
| 30 | if (oldenv) oldenv->PreventLeave(this_object(),dest); |
| 31 | dest->PreventInsert(this_object()); |
| 32 | |
| 33 | return 0; // das wars, rest ist egal. |
| 34 | } |
| 35 | |
| 36 | // P_NODROP verhindert weggeben |
| 37 | if ((method & (M_PUT|M_GIVE)) && QueryProp(P_NODROP)) |
| 38 | return ME_CANT_BE_DROPPED; |
| 39 | |
| 40 | // P_NOGET verhindert nehmen |
| 41 | if ((method & (M_GET|M_GIVE)) && QueryProp(P_NOGET)) |
| 42 | return ME_CANT_BE_TAKEN; |
| 43 | |
| 44 | // Gewicht ermitteln |
| 45 | if ( !(tmp = (int)QueryProp(P_TOTAL_WEIGHT)) ) |
| 46 | tmp = (int)QueryProp(P_WEIGHT); |
| 47 | |
| 48 | // Ist das Objekt nicht zu schwer? |
| 49 | if ( (tmp = (int)dest->MayAddWeight(tmp)) < 0) { |
| 50 | if ( tmp == -2 ) return ME_TOO_HEAVY_FOR_ENV; |
| 51 | return ME_TOO_HEAVY; |
| 52 | } |
| 53 | |
| 54 | // Ist das Zielobjekt schon voll? |
| 55 | if ( !dest->MayAddObject(this_object()) ) |
| 56 | return TOO_MANY_OBJECTS; |
| 57 | |
| 58 | // Darf hinausbewegt werden? |
| 59 | if ( oldenv && oldenv->PreventLeave(this_object(), dest) ) |
| 60 | return ME_CANT_LEAVE_ENV; |
| 61 | |
| 62 | // Darf hineinbewegt werden? |
| 63 | if ( dest->PreventInsert(this_object()) ) |
| 64 | return ME_CANT_BE_INSERTED; |
| 65 | |
| 66 | return(0); |
| 67 | } |
| 68 | |
| 69 | // zum Ueberschreiben... |
| 70 | protected void NotifyMove(object dest, object oldenv, int method) { |
| 71 | } |
| 72 | |
| 73 | varargs int move( object|string dest, int method ) |
| 74 | { |
| 75 | object oldenv; |
| 76 | int tmp; |
| 77 | string fn,vc; |
| 78 | mixed sens; |
| 79 | |
| 80 | if (!objectp(dest) && !stringp(dest)) |
| 81 | raise_error(sprintf("Wrong argument 1 to move(). 'dest' must be a " |
| 82 | "string or object! Argument was: %.100O\n", |
| 83 | dest)); |
| 84 | |
| 85 | // Jetzige Umgebung merken |
| 86 | oldenv = environment(); |
| 87 | |
| 88 | // Bewegung in Para-Welt-Raeume? |
| 89 | // tmp ist die Ziel-Parallelweltnummer |
| 90 | if (!environment()||!living(environment())|| |
| 91 | !intp(tmp =(int)environment()->Query(P_PARA))) |
| 92 | tmp=0; |
| 93 | |
| 94 | // Wenn das Objekt von einem in der Parawelt befindlichen Spieler |
| 95 | // oder NPC bewegt wird, sollte es auch wieder in der Parawelt landen. |
| 96 | // Um Rechenzeit zu sparen, wird angenommen, dass bei Bewegungen in |
| 97 | // das Inv oder Env des Spielers 'dest' als Objekt uebergeben wird, |
| 98 | // wohingegen bei Bewegungen in Nachbarraeume (die eigentlich nur |
| 99 | // interessant sind) 'dest' als Filename angegeben wird. |
| 100 | if (tmp&&!objectp(dest)&&!environment(dest)) { |
| 101 | // Falls der Zielraum nicht schon explizit in der Parallelwelt ist, |
| 102 | // neuen Zielraum suchen. Aber nur, wenn das Ziel kein Clone ist. Sonst |
| 103 | // buggt, wenn man versucht, nach raum#42^para zu bewegen. |
| 104 | if (!IS_PARA(dest) && strrstr(dest,"#")==-1) { |
| 105 | fn=dest+"^"+tmp; |
| 106 | |
| 107 | // Der Parawelt-Raum wird nur zum Ziel, wenn er a) existiert |
| 108 | // und b) auch von Spielern betreten werden darf. Letzteres |
| 109 | // Kriterium kann nur mit im Objekt gesetzter Property |
| 110 | // P_TESTPLAYER umgangen werden. |
| 111 | if ( (find_object(fn) || ((file_size(fn+".c")>0|| |
| 112 | (file_size(vc=implode(explode(fn,"/")[0..<2],"/")+ |
| 113 | "/virtual_compiler.c")>0 && |
| 114 | !catch(tmp=(int)call_other(vc,"QueryValidObject",fn); |
| 115 | publish) && tmp>0)) && |
| 116 | !catch(load_object( fn );publish))) && |
| 117 | (!fn->QueryProp(P_NO_PLAYERS) || QueryProp(P_TESTPLAYER)) ) |
| 118 | dest = fn; |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | // dest auf Objekt normieren. |
| 123 | if (stringp(dest)) |
| 124 | dest = load_object(dest); |
| 125 | |
| 126 | // testen, ob das Objekt bewegt werden will |
| 127 | if (tmp=PreventMove(dest, oldenv, method)) { |
| 128 | // auf gueltigen Fehler pruefen, wer weiss, was Magier da evtl. |
| 129 | // versehentliche zurueckgeben. |
| 130 | if (VALID_MOVE_ERROR(tmp)) |
| 131 | return(tmp); |
| 132 | else |
| 133 | return(ME_DONT_WANT_TO_BE_MOVED); |
| 134 | } |
| 135 | |
| 136 | // Sensitive Objekte muessen entfernt werden |
| 137 | sens = QueryProp(P_SENSITIVE); |
| 138 | |
| 139 | if (sens && environment()) |
| 140 | { |
| 141 | environment()->RemoveSensitiveObject( this_object() ); |
| 142 | if (!objectp(ME)) |
| 143 | return ME_WAS_DESTRUCTED; |
| 144 | } |
| 145 | // Bewegen |
| 146 | move_object(ME, dest); |
| 147 | |
| 148 | //falls (sich) das objekt im init() zerstoert (wurde). (Die u. stehenden |
| 149 | //Funktionsaufrufe werden dann vom Driver eh groesstenteils ignoriert.) |
| 150 | if (!objectp(this_object())) return(ME_WAS_DESTRUCTED); |
| 151 | |
| 152 | // Objekt informieren. ;-) |
| 153 | NotifyMove(environment(), oldenv, method); |
| 154 | |
| 155 | // Alte Umgebung informieren |
| 156 | if (oldenv) oldenv->NotifyLeave(this_object(), dest); |
| 157 | |
| 158 | // Wenn das Objekt eine Umgebung hat, selbige informieren |
| 159 | if (environment()) { |
| 160 | if (sens) |
| 161 | { |
| 162 | environment()->InsertSensitiveObject(this_object(),sens); |
| 163 | if (!objectp(ME)) return ME_WAS_DESTRUCTED; |
| 164 | } |
| 165 | environment()->NotifyInsert(this_object(), oldenv); |
| 166 | } |
| 167 | //wurde das Objekt vielleicht noch zerstoert? |
| 168 | if (!objectp(ME)) return(ME_WAS_DESTRUCTED); |
| 169 | |
| 170 | //scheint wohl alles ok zu sein. |
| 171 | return MOVE_OK; |
| 172 | } |
| 173 | |
| 174 | // Das Objekt zerstoeren |
| 175 | varargs int remove(int silent) |
| 176 | { |
| 177 | if (environment() ) { |
| 178 | if(QueryProp(P_SENSITIVE)) |
| 179 | environment()->RemoveSensitiveObject(this_object()); |
| 180 | environment()->NotifyRemove(this_object()); |
| 181 | } |
| 182 | if (objectp(this_object())) |
| 183 | destruct(this_object()); |
| 184 | return 1; |
| 185 | } |
| 186 | |
| 187 | public string NotifyDestruct(object caller) { |
| 188 | // Lichtsystem mit der aenderung versorgen. :-/ |
| 189 | foreach(object env : all_environment() || ({})) { |
| 190 | // Ja. Man ruft die _set_xxx()-Funktionen eigentlich nicht direkt auf. |
| 191 | // Aber das Lichtsystem ist schon *so* rechenintensiv und gerade der |
| 192 | // P_LAST_CONTENT_CHANGE-Cache wird *so* oft benoetigt, dass es mir |
| 193 | // da um jedes bisschen Rechenzeit geht. |
| 194 | // Der Zweck heiligt ja bekanntlich die Mittel. ;-) |
| 195 | // |
| 196 | // Tiamak |
| 197 | env->_set_last_content_change(); |
| 198 | } |
| 199 | return 0; |
| 200 | } |
| 201 | |