blob: 9fbe3811bdbf17a4884ff82bb0857e4505ada6f2 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// transport.c -- Basisklasse fuer Schiffe und aehnliche Transporter
4//
5// $Id: transport.c 9400 2015-12-11 21:56:14Z Zesstra $
Zesstra@Morgengrauen2315aa12016-10-30 22:36:26 +01006#pragma strong_types,rtt_checks
MG Mud User88f12472016-06-24 23:31:02 +02007#pragma range_check
8#pragma no_clone
MG Mud User88f12472016-06-24 23:31:02 +02009
10inherit "/std/thing/moving";
11inherit "/std/room";
12
13#include <properties.h>
14#include <moving.h>
15#include <defines.h>
16#include <language.h>
17#include <transport.h>
18#include <regexp.h>
Zesstra179db0d2016-11-26 13:13:41 +010019#include <hook.h>
20
MG Mud User88f12472016-06-24 23:31:02 +020021
22/* transport.c
23 *
24 * Ueberarbeitete und
25 * erweiterte Version : Tilly@MorgenGrauen, 10.01.02
26 * Basierend auf : transport.c@SilberLand (Woody@SilberLand), 05.12.99
27 * Basierend auf : Hates und Rumatas generisches Transport Objekt
28 * MorgenGrauen 15.02.93
29 */
30
31/*
32 ********************* Variablen *********************
33 */
34
35// TODO: langfristig waer ja private schoen...
36//
37// Datenstruktur von 'route' (bei HP_ROOM)
38// 0 ({string ID, : HP_ROOM
39// 1 string room, : Dateiname Zielraum
40// 2 int stay, : Dauer Haltezeit
41// 3 int next, : Dauer naechste Fahrtzeit
42// 4 string code, : Haltestellenname fuer QueryArrived
43// 5 mixed dest, : Haltestellen-IDs fuer HasRoute (reise nach)
44// 6 mixed deststr }): unbenutzt.
45//
46// Datenstruktur von 'route' (bei HP_MSG, HP_FUN)
47// 0 ({string ID, : HP_MSG
48// 1 string message, : Meldung oder string fun : Funktionsname
49// 2 int next}) : Dauer bis zum naechsten Ereignis
50nosave mixed *route; /* Liste der Haltepunkte. */
51nosave int rpos; /* Momentane Position in obiger Liste. */
52nosave string roomCode; /* Code des aktuellen Raumes (oder 0). */
Zesstrae805e3a2018-02-12 19:48:06 +010053// Letzter Spielerkontakt. Das muss != 0 sein (sonst funktioniert der
54// Mechanismus zum Fortsetzen der Route nach einer Pause nicht ordentlich,
55// daher wird es auf 1 initialisiert.
56nosave int meet_last_player = 1;
Zesstra7842b8e2019-07-04 21:55:39 +020057// Dauer der Route
58nosave int route_time;
Zesstra179db0d2016-11-26 13:13:41 +010059
60private void unsubscribe_init();
61private int subscribe_init();
Zesstra72843372018-02-12 21:34:49 +010062void changeHp();
MG Mud User88f12472016-06-24 23:31:02 +020063
64/*
65 ********** Management der builtin-properties **********
66 */
67
68string _query_short()
Zesstra866a3442022-05-07 12:34:13 +020069{
70 if (roomCode) return Query(P_SHORT, F_VALUE);
71 return 0;
72}
73
74// Waehrend der Reise echt unsichtbar und nicht-interagierbar machen, ausser
75// fuer PL innerhalb des Transporters.
76// Ansonsten koennten z.B. Spieler, die im Hafen einen angelegten Transporter
77// betrachten, ihn dadurch als Referenzobjekt haben und Details am
78// unsichtbaren, reisenden Transporter betrachten.
79visible int _query_invis()
80{
Bugfixe50c0d62024-04-02 22:06:37 +020081 if(!roomCode &&
Bugfix0212bb42024-04-05 14:02:59 +020082 (!PL || (environment(PL) != ME && query_verb() != "reise")))
Bugfixe50c0d62024-04-02 22:06:37 +020083 {
84 return 1;
85 }
Zesstra866a3442022-05-07 12:34:13 +020086 return Query(P_INVIS, F_VALUE);
MG Mud User88f12472016-06-24 23:31:02 +020087}
88
89mixed _query_transparent()
Zesstra866a3442022-05-07 12:34:13 +020090{
MG Mud User88f12472016-06-24 23:31:02 +020091 if (roomCode) return Query(P_TRANSPARENT);
Zesstra866a3442022-05-07 12:34:13 +020092 return 0;
MG Mud User88f12472016-06-24 23:31:02 +020093}
94
Zesstra179db0d2016-11-26 13:13:41 +010095static mixed *_set_route(mixed *r) { return route = r; }
96static mixed *_query_route() { return route; }
97static int _query_mnpc_last_meet() { return meet_last_player; }
MG Mud User88f12472016-06-24 23:31:02 +020098
99/*
100 **************** Zugriffsfunktionen ***************
101 */
102
Zesstra179db0d2016-11-26 13:13:41 +0100103public void Halt()
MG Mud User88f12472016-06-24 23:31:02 +0200104{
Zesstra179db0d2016-11-26 13:13:41 +0100105 // stop, but keep rpos counter.
MG Mud User88f12472016-06-24 23:31:02 +0200106 while (remove_call_out( "changeHp" )>-1);
107 while (remove_call_out( "disconnect" )>-1);
108}
109
110// Aktualisiert/Setzt die Route im TravelD, wenn erlaubt (d.h. kein
111// P_NO_TRAVELING)
112private void ReportRoute()
113{
114 if(!QueryProp(P_NO_TRAVELING))
115 {
116 mixed tmp = filter(route, function int (mixed arr)
117 {
118 return arr[0] == HP_ROOM;
119 } );
120 string *route = map(tmp, function string (mixed arr)
121 { return arr[1]; }
122 );
123 TRAVELD->AddRoute(object_name(this_object()),route);
124 }
125}
126
Zesstra179db0d2016-11-26 13:13:41 +0100127public varargs void Start(int pos)
MG Mud User88f12472016-06-24 23:31:02 +0200128{
129 Halt();
Zesstra5d2ace02017-06-20 23:21:36 +0200130 // negative pos sind ein Fehler
131 if (pos<0)
132 raise_error(sprintf("Start(): Positionszaehler < 0: %d\n",pos));
133
134 // wenn pos zu gross fuer die Route ist, rpos auf Ende der Route setzen
135 // (i.e. sizeof(route)-1), damit bei der naechsten Bewegung am Anfang der
136 // Route begonnen wird.
137 rpos = min(pos, sizeof(route)-1);
138
MG Mud User88f12472016-06-24 23:31:02 +0200139 // Tell TRAVELD our current route
140 ReportRoute();
Zesstrac786fee2018-02-12 20:31:29 +0100141 // changeHp() inkrementiert zu Beginn rpos um 1. D.h. damit wir keinen
142 // Haltepunkt ueberspringen, muss dieses vorweg kompensiert werden. Da dies
143 // wiederum den Transporter aber ggf. buggen laesst (rpos<0), darf das
144 // changeHp() hier nicht asynchron per call_out gerufen werden.
145 --rpos;
146 changeHp();
MG Mud User88f12472016-06-24 23:31:02 +0200147}
148
Zesstra179db0d2016-11-26 13:13:41 +0100149// continues the current route at the point we stopped.
150public int Continue()
151{
152 if (find_call_out("changeHp") == -1
153 && find_call_out("disconnect") == -1)
154 {
Zesstra019987a2017-10-24 22:36:08 +0200155 // Nach einer Pause wird die Route am aktuellen Haltepunkt fortgesetzt
156 // (im Regelfall also am Ende der Route). Am Routenende wird auch
157 // geprueft, wann der letzte Spielerkontakt war. Das darf nach einem
158 // Continue() aber nicht passieren, sonst wuerde der Transporter ggf.
159 // sofort wieder anhalten.
160 meet_last_player*=-1; // neg. vorzeichen als Markierung
Zesstra179db0d2016-11-26 13:13:41 +0100161 unsubscribe_init();
162 Start(rpos);
163 return 1;
164 }
165 return 0;
166}
167
168// pauses the transporter temporarily in a way that it continues along its
169// route as soon as a living enters one of the stop points. If that is not
170// possible, we do nothing.
171public int Pause()
172{
173 // ok, stop
174 if (subscribe_init() == 1)
175 {
176 Halt();
177 return 1;
178 }
179 return 0;
180}
181
MG Mud User88f12472016-06-24 23:31:02 +0200182void SetTravelCmds()
183{
184 if (pointerp(QueryProp(P_LEAVECMDS)))
185 AddCmd(QueryProp(P_LEAVECMDS),"GoOutside");
186 if (pointerp(QueryProp(P_ENTERCMDS)))
187 AddCmd(QueryProp(P_ENTERCMDS),"GoInside");
188 if (pointerp(QueryProp(P_TRAVEL_CMDS)))
189 AddCmd(QueryProp(P_TRAVEL_CMDS),"GoInAndOutside");
190 return;
191}
192
193mixed HasRoute(mixed dest)
194{
Arathornb3051452021-05-13 21:13:03 +0200195 int i,s;
MG Mud User88f12472016-06-24 23:31:02 +0200196 object ob;
197 mixed harb;
198
199 s = sizeof(route);
200
201 for (i = rpos;i <= rpos+s-1;i++)
202 {
203 if (route[i%s][0] == HP_ROOM)
204 {
205 if (member(route[i%s][5],dest) != -1 &&
206 objectp(ob=load_object(route[i%s][1])) &&
207 pointerp(harb=ob->QueryProp(P_HARBOUR)) &&
208 sizeof(harb))
209 {
210 return ({ route[i%s][1], harb[0] });
211 }
212 }
213 }
214 return 0;
215}
216
217public varargs void AddRoute(string room, int stay, int next,
218 string harbour_desc, string|string* dest_ids, string deststr)
219{
220 // Daten aus dem Zielanleger abfragen.
221 <string|string*>* harbour = room->QueryProp(P_HARBOUR)||({});
222 string* harbour_ids = ({});
223
224 // IDs des Zielanlegers fuer Syntaxpruefung
225 if ( sizeof(harbour)==2 )
226 {
227 if ( pointerp(harbour[1]) )
228 harbour_ids = harbour[1];
229 else
230 harbour_ids = ({harbour[1]});
231 }
232
233 // <dest_ids> in ein Array umwandeln, ist dann ggf. leer
234 if ( !dest_ids )
235 {
236 dest_ids = ({});
237 }
238 if ( stringp(dest_ids) )
239 {
240 dest_ids = ({dest_ids});
241 }
242
243 // explizit angegebene IDs stehen jetzt in <dest_ids>, die IDs des
244 // Zielhafens aus P_HARBOUR werden addiert.
245 dest_ids += harbour_ids;
246
247 // Ist <dest> immer noch leer, versuchen wir, aus <harbour_desc> ein paar
248 // Stichwoerter zu erzeugen, die man als Zielangabe in der Syntax
249 // "reise nach <ziel>" verwenden kann.
250 if ( !sizeof(dest_ids) )
251 {
252 // Grossgeschriebene Begriffe in <harbour_desc> in <dest> eintragen. Dazu:
253 // 1) <code> erstmal so zerschneiden, dass alle ueblichen Satzzeichen
254 // rausfliegen (es gibt Transporter, die sowas in <harbour_desc>
255 // uebergeben).
256 dest_ids = regexplode(harbour_desc, "[(),.;:&\+_ ]",
257 RE_OMIT_DELIM|RE_GLOBAL);
258 // 2a) So filtern, dass nur grossgeschriebene Woerter uebrig bleiben,
259 // von 1) uebriggebliebene Leerstrings gleich mit wegwerfen.
260 // 2b) Ergebnis kleinschreiben, damit die Syntaxpruefung damit arbeiten
261 // kann.
262 dest_ids = map( filter(dest_ids, function int (string key) {
263 return (key!="" && key[0]>='A' && key[0]<='Z');
264 }), #'lower_case);
265 }
266 // Sollte <dest> jetzt immer noch leer sein, wurde an allen drei Stellen
267 // nichts oder nur Muell uebergeben.
268 if ( !sizeof(dest_ids) )
269 {
270 raise_error("Transporterfehlfunktion in AddRoute(): Identifikations"
271 "matrix unzureichend definiert. Transporter unbenutzbar fuer "
272 "Spieler. Bitte mindestens eine Ziel-ID via P_HARBOUR oder als "
273 "Argument to AddRoute().");
274 }
275 route += ({ ({ HP_ROOM, room, stay, next, harbour_desc, dest_ids,
276 deststr }) });
Zesstra7842b8e2019-07-04 21:55:39 +0200277 route_time += stay + next;
MG Mud User88f12472016-06-24 23:31:02 +0200278}
279
Zesstra7842b8e2019-07-04 21:55:39 +0200280varargs void AddMsg(string msg, int next)
MG Mud User88f12472016-06-24 23:31:02 +0200281{
Zesstra7842b8e2019-07-04 21:55:39 +0200282 route += ({ ({ HP_MSG, msg, next }) });
283 route_time += next;
MG Mud User88f12472016-06-24 23:31:02 +0200284}
285
Zesstra7842b8e2019-07-04 21:55:39 +0200286void AddFun(string fun, int next)
287{
288 route += ({ ({ HP_FUN, fun, next }) });
289 route_time += next;
290}
MG Mud User88f12472016-06-24 23:31:02 +0200291
292string QueryArrived() { return roomCode; }
293
294mixed* QueryPosition()
295{
296 return ({ route[rpos][1],route[(rpos+1)<sizeof(route)?(rpos+1):0][1] });
297}
298
299object* QueryPassengers()
300{
301 return filter(all_inventory(),#'query_once_interactive);
302}
303
304varargs string *QueryHarbours(int textflag)
305{
306 string *ret = ({});
307
308 foreach( mixed* entry : route )
309 {
310 if ( entry[0] == HP_ROOM )
311 {
312 if ( textflag )
313 {
314 string *hp_ids = entry[1]->QueryProp(P_HARBOUR)[1];
315 if (pointerp(hp_ids) && sizeof(hp_ids))
316 {
317 string *h = map( explode(hp_ids[0]," "), #'capitalize);
318 ret += ({ implode(h, " ") });
319 }
320 }
321 else
322 {
323 ret += ({ entry[1] });
324 }
325 }
326 }
327 return ret;
328}
329
330// beim zerstoeren sollte auch die route und der Transporter aus dem traveld
331// abgemeldet werden.
332public varargs int remove(int silent)
333{
334 TRAVELD->RemoveTransporter(this_object());
335 return ::remove(silent);
336}
337
338void RemoveRoute()
339{
340 Halt();
341 route = ({ });
342 rpos = 0;
Zesstra7842b8e2019-07-04 21:55:39 +0200343 route_time = 0;
MG Mud User88f12472016-06-24 23:31:02 +0200344 TRAVELD->RemoveTransporter(this_object());
345}
346
347varargs int Enter(object who)
348{
349 string *emsg;
350 mixed efail;
351
352 if (!objectp(who)) who = this_player();
353 if (environment(who) == this_object())
354 {
355 tell_object(who,"Da bist Du doch bereits, schon vergessen?\n");
356 return 1;
357 }
358 if (!QueryArrived()) return 0;
359 if (QueryProp(P_MAX_PASSENGERS) &&
360 (sizeof(QueryPassengers()) >= QueryProp(P_MAX_PASSENGERS)))
361 {
362 if (pointerp(efail=QueryProp(P_ENTERFAIL)))
363 {
364 if (sizeof(efail) == 2)
365 tell_room(this_object(),who->Name(WER,2)+" "+process_string(efail[1])+
366 ".\n",({who}));
367 tell_object(who,process_string(efail[0])+".\n");
368 }
369 else if (stringp(efail))
370 tell_object(who,process_string(efail)+".\n");
371 else if (closurep(efail)) funcall(efail);
372 return 1;
373 }
374
375 tell_object(who,"Du betrittst "+name(WEN,1)+".\n");
376 if (pointerp(emsg=QueryProp(P_ENTERMSG)) && sizeof(emsg) == 2)
377 return who->move(this_object(),M_GO,"",process_string(emsg[0]),
378 process_string(emsg[1]));
379 return who->move(this_object(),M_GO,
380 name(WEN,1),"betritt","kommt herein");
381}
382
383varargs int Leave(object who)
384{
385 string *lmsg;
386 mixed lfail;
387
388 if (!objectp(who)) who = this_player();
389 if (environment(who) != this_object())
390 {
391 if (QueryArrived())
392 {
393 tell_object(who,"Dafuer muesstest Du erstmal dort sein.\n");
394 return 1;
395 }
396 return 0;
397 }
398 if (!QueryArrived())
399 {
400 if (lfail=QueryProp(P_LEAVEFAIL))
401 {
402 if (pointerp(lfail) && sizeof(lfail))
403 {
404 if (sizeof(lfail) == 2)
405 tell_room(this_object(),who->Name(WER,2)+" "+process_string(
406 lfail[1])+".\n",({who}));
407 tell_object(who,process_string(lfail[0])+".\n");
408 }
409 else if (stringp(lfail))
410 tell_object(who,process_string(lfail)+".\n");
411 else if (closurep(lfail)) funcall(lfail);
412 return 1;
413 }
414 tell_object(who,"Fehler beim Verlassen des Transporters.\n"
415 "Bitte zustaendigen Magier verstaendigen.\n");
416 return 1;
417 }
418
419 if (who->QueryProp(P_TRAVEL_INFO)) who->SetProp(P_TRAVEL_INFO,0);
420 tell_object(who,"Du verlaesst "+name(WEN,1)+".\n");
421 if (pointerp(lmsg=QueryProp(P_LEAVEMSG)) && sizeof(lmsg) == 2)
422 return who->move(environment(),M_GO,"",process_string(lmsg[0]),
423 process_string(lmsg[1]));
424 return who->move(environment(),M_GO,
425 name(WEN,1),"verlaesst","kommt herein");
426}
427
428/*
429 ****************** Internal Functions ******************
430 */
431
432static int GoInside(string str)
433{
434 _notify_fail("Was moechtest Du denn genau?\n");
435 if (stringp(str) && id(str)) {
436 Enter();
437 return 1;
438 }
439 return 0;
440}
441
442static int GoOutside(string str)
443{
444 _notify_fail("Was moechtest Du denn genau?\n");
445 if (stringp(str) && id(str)) {
446 Leave();
447 return 1;
448 }
449 return 0;
450}
451
452static int GoInAndOutside(string str)
453{
454 string to;
455
456 _notify_fail("Was moechtest Du denn genau?\n");
457 if (!sizeof(str)) return 0;
458 if ((sscanf(str,"auf %s",to) == 1 || sscanf(str,"in %s",to) == 1) && id(to))
459 return Enter(),1;
460 if ((sscanf(str,"von %s",to) == 1 || sscanf(str,"aus %s",to) == 1) && id(to))
461 return Leave(),1;
462 return 0;
463}
464
465protected void create()
466{
467 ::create();
468
469 route = ({});
470
471 SetProp(P_LEAVEFAIL,"Das ist momentan viel zu gefaehrlich");
472 SetProp(P_ENTERFAIL,"Dort ist kein Platz mehr fuer Dich");
473 SetProp(P_TRANSPARENT,1);
474
475 AddId("Transporter");
Zesstra179db0d2016-11-26 13:13:41 +0100476
MG Mud User88f12472016-06-24 23:31:02 +0200477 call_out("SetTravelCmds",1);
478}
479
480static varargs void disconnect(int change, int change_time)
481{
482 object room;
483 mixed *departmsg;
484
485 departmsg = QueryProp(P_DEPARTMSG);
486
487 if ((room = environment()) && pointerp(departmsg))
488 {
489 tell_room(this_object(),process_string(departmsg[0]));
490 tell_room(room,process_string(departmsg[1]));
491 }
492
493 roomCode = 0;
494
495 if (change) call_out("changeHp",change_time);
496}
497
498static varargs void connect(string room, string code)
499{
500 mixed *arrivemsg, *t;
Arathornb3051452021-05-13 21:13:03 +0200501 object *trav;
MG Mud User88f12472016-06-24 23:31:02 +0200502 int i;
503
504 if (roomCode) disconnect();
505
506 roomCode = code?code:"";
507
508 if (catch(move(room,M_SILENT|M_NOCHECK);publish))
509 {
510 roomCode = 0;
511 return;
512 }
513
514 arrivemsg = QueryProp(P_ARRIVEMSG);
515
516 if (pointerp(arrivemsg))
517 {
518 tell_room(this_object(),process_string(arrivemsg[0]));
519 tell_room(room,process_string(arrivemsg[1]));
520 }
521
522 trav = filter(all_inventory(this_object()),#'living);
523
524 i = sizeof(trav);
525 while(i--)
526 {
527 if (pointerp(t = trav[i]->QueryProp(P_TRAVEL_INFO))&&
528 t[0]==this_object()&&t[2]==room)
529 {
530 if (trav[i]->InFight())
531 tell_object(trav[i],break_string("Du solltest Deinen Kampf "
532 "schnell beenden,denn eigentlich wolltest Du hier "
533 "aussteigen.",78));
534 else
535 Leave(trav[i]);
536 if (environment(trav[i])!=this_object())
537 trav[i]->SetProp(P_TRAVEL_INFO,0);
538 }
539 }
540 trav = filter(all_inventory(find_object(room))-trav,#'living);
541 i=sizeof(trav);
542 while(i--)
543 {
544 if (objectp(trav[i]) && pointerp(t = trav[i]->QueryProp(P_TRAVEL_INFO))&&
545 t[0] == environment(trav[i]) && t[1] == this_object())
546 {
547 if ( trav[i]->InFight() )
548 tell_object(trav[i],
549 break_string("Du solltest Deinen Kampf schnell beenden, denn "
550 "eigentlich wolltest Du mit "+name(WEM,1)+
551 " reisen.",78));
552 else
553 Enter(trav[i]);
554 if (environment(trav[i]) == this_object())
555 {
556 t[0] = this_object();
557 trav[i]->SetProp(P_TRAVEL_INFO,t);
558 }
559 }
560 }
561}
562
563// this object never performs any clean-up, the driver should not call it
564// again.
565int clean_up(int arg) { return 0; }
566
Zesstra5b71ebb2018-03-07 20:50:35 +0100567public varargs void init(object origin)
Zesstra179db0d2016-11-26 13:13:41 +0100568{
Zesstra5b71ebb2018-03-07 20:50:35 +0100569 "*"::init(origin);
Zesstra179db0d2016-11-26 13:13:41 +0100570 // if we have player contact (even if the player is just in the same
571 // environment), we update the time.
572 if (this_player() && query_once_interactive(this_player()))
Bugfix4df578b2019-03-13 18:36:59 +0100573 {
574 meet_last_player = time();
575 // Wenn jemand in uns ist, auch falls noetig die Route fortsetzen,
576 // denn wir haben natuerlich nicht H_HOOK_INIT in uns selbst abonniert.
Arathorn303ade72022-12-09 21:53:06 +0100577 // Aber auch nur, wenn nicht jemand schon nen zeitverzögertes
578 // Continue per Hook getriggert hat.
579 if(environment(PL)==ME && find_call_out(#'Continue)==-1)
Bugfix4df578b2019-03-13 18:36:59 +0100580 Continue();
581 }
Zesstra179db0d2016-11-26 13:13:41 +0100582}
583
584// we try to continue our route once some living triggers init.
585private mixed InitHookCallback(object source, int hookid, mixed hookdata)
586{
Arathorn303ade72022-12-09 21:53:06 +0100587 if (hookid == H_HOOK_INIT && previous_object() == source &&
588 find_call_out(#'Continue)==-1)
589 call_out(#'Continue, 0);
Zesstra179db0d2016-11-26 13:13:41 +0100590 return ({H_NO_MOD, hookdata});
591}
592
593// subscribes to H_HOOK_INIT in all rooms along the route
Zesstra658871d2019-07-04 21:34:02 +0200594// == 1 for success, < -1 if not (at least one hook failed, all registration
595// were already subscribed).
Zesstra179db0d2016-11-26 13:13:41 +0100596private int subscribe_init()
597{
598 // subscribe to the H_HOOK_INIT of all rooms in the route...
Zesstra179db0d2016-11-26 13:13:41 +0100599 foreach(mixed* arr : route)
600 {
601 if (arr[0] == HP_ROOM)
602 {
Bugfix7c642a72021-05-16 13:05:52 +0200603 int res = arr[1]->HRegisterToHook(H_HOOK_INIT, #'InitHookCallback,
604 H_HOOK_LIBPRIO(1), H_LISTENER,
605 0);
606 // 1 == Erfolg, -3 == bereits registriert
607 if(res != 1 && res != -3)
Zesstra658871d2019-07-04 21:34:02 +0200608 {
609 // von allen H_HOOK_INIT wieder abmelden...
610 unsubscribe_init();
611 return -1;
612 }
Zesstra179db0d2016-11-26 13:13:41 +0100613 }
614 }
Zesstra658871d2019-07-04 21:34:02 +0200615 return 1;
Zesstra179db0d2016-11-26 13:13:41 +0100616}
617
618// unsubscribes from all the H_HOOK_INIT.
619private void unsubscribe_init()
620{
621 foreach(mixed* arr : route)
622 {
623 if (arr[0] == HP_ROOM)
624 arr[1]->HUnregisterFromHook(H_HOOK_INIT, #'InitHookCallback);
625 }
626}
627
628private int maybe_pause()
629{
Zesstra7842b8e2019-07-04 21:55:39 +0200630 // we check for time of last player contact. If we did not meet any players
631 // for 2 round-trips, we try to pause.
632 if (meet_last_player < time() - (2*route_time) )
Zesstra179db0d2016-11-26 13:13:41 +0100633 {
Zesstra677b5722019-07-04 22:10:01 +0200634 // we don't stop if players are currently at one of our stops
635 foreach(mixed* arr : route)
636 {
637 if (arr[0] == HP_ROOM)
638 {
639 object room = find_object(arr[1]);
640 if(room &&
641 sizeof(filter(all_inventory(room), #'interactive)))
642 return 0; // no pause
643 }
644 }
645 // and we don't stop if players currently are in the transporter.
646 if (sizeof(filter(all_inventory(this_object()), #'interactive)))
647 return 0;
648 // ok, pause machen
649 return Pause();
Zesstra179db0d2016-11-26 13:13:41 +0100650 }
651 return 0;
652}
653
MG Mud User88f12472016-06-24 23:31:02 +0200654void changeHp()
655{
Zesstrafffd2a82017-10-24 22:03:27 +0200656 // Nicht am Ende der Route? Eins weiter.
657 if (rpos < sizeof(route) - 1)
658 ++rpos;
659 else
MG Mud User88f12472016-06-24 23:31:02 +0200660 {
Zesstra019987a2017-10-24 22:36:08 +0200661 // Routenende
662 // Nach einem expliziten Continue() ist meet_last_player < 0. Dann wird
663 // nicht geprueft, ob wir sofort wieder anhalten. Auch muss dann die Route
664 // nicht uebermittelt werden (hat Start() schon gemacht).
665 if (meet_last_player >= 0)
666 {
667 // TRAVELD die aktuelle Route uebermitteln
668 ReportRoute();
669 // everytime, we pass the end of our route, we check if we should
670 // pause our service.
671 if (maybe_pause())
672 return;
673 }
674 else
675 // Wieder pruefen im naechsten Durchlauf.
676 meet_last_player=abs(meet_last_player);
677
Zesstrafffd2a82017-10-24 22:03:27 +0200678 // wenn keine Pause, wieder zum Anfang der Route bewegen.
679 rpos = 0;
MG Mud User88f12472016-06-24 23:31:02 +0200680 }
Zesstrafffd2a82017-10-24 22:03:27 +0200681
MG Mud User88f12472016-06-24 23:31:02 +0200682 if (route[rpos][0] == HP_MSG)
683 {
684 call_out("changeHp",route[rpos][2]);
685 tell_room(this_object(),route[rpos][1]);
686 }
687 else if (route[rpos][0] == HP_FUN)
688 {
689 call_out("changeHp",route[rpos][2]);
690 call_other(this_object(),route[rpos][1]);
691 }
692 else
693 {
694 call_out("disconnect",route[rpos][2],1,route[rpos][3]);
695 connect(route[rpos][1],route[rpos][4]);
696 }
697}
698