blob: af68623a4e6bcf7699b101ba98f4f78e4393ebc8 [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>
Arathorndddb3ae2020-09-06 13:11:42 +020020#include <break_string.h>
Zesstra179db0d2016-11-26 13:13:41 +010021
MG Mud User88f12472016-06-24 23:31:02 +020022
23/* transport.c
24 *
25 * Ueberarbeitete und
26 * erweiterte Version : Tilly@MorgenGrauen, 10.01.02
27 * Basierend auf : transport.c@SilberLand (Woody@SilberLand), 05.12.99
28 * Basierend auf : Hates und Rumatas generisches Transport Objekt
29 * MorgenGrauen 15.02.93
30 */
31
32/*
33 ********************* Variablen *********************
34 */
35
36// TODO: langfristig waer ja private schoen...
37//
38// Datenstruktur von 'route' (bei HP_ROOM)
39// 0 ({string ID, : HP_ROOM
40// 1 string room, : Dateiname Zielraum
41// 2 int stay, : Dauer Haltezeit
42// 3 int next, : Dauer naechste Fahrtzeit
43// 4 string code, : Haltestellenname fuer QueryArrived
44// 5 mixed dest, : Haltestellen-IDs fuer HasRoute (reise nach)
45// 6 mixed deststr }): unbenutzt.
46//
47// Datenstruktur von 'route' (bei HP_MSG, HP_FUN)
48// 0 ({string ID, : HP_MSG
49// 1 string message, : Meldung oder string fun : Funktionsname
50// 2 int next}) : Dauer bis zum naechsten Ereignis
51nosave mixed *route; /* Liste der Haltepunkte. */
52nosave int rpos; /* Momentane Position in obiger Liste. */
53nosave string roomCode; /* Code des aktuellen Raumes (oder 0). */
Zesstrae805e3a2018-02-12 19:48:06 +010054// Letzter Spielerkontakt. Das muss != 0 sein (sonst funktioniert der
55// Mechanismus zum Fortsetzen der Route nach einer Pause nicht ordentlich,
56// daher wird es auf 1 initialisiert.
57nosave int meet_last_player = 1;
Zesstra7842b8e2019-07-04 21:55:39 +020058// Dauer der Route
59nosave int route_time;
Zesstra179db0d2016-11-26 13:13:41 +010060
61private void unsubscribe_init();
62private int subscribe_init();
Zesstra72843372018-02-12 21:34:49 +010063void changeHp();
MG Mud User88f12472016-06-24 23:31:02 +020064
65/*
66 ********** Management der builtin-properties **********
67 */
68
69string _query_short()
Zesstra866a3442022-05-07 12:34:13 +020070{
71 if (roomCode) return Query(P_SHORT, F_VALUE);
72 return 0;
73}
74
75// Waehrend der Reise echt unsichtbar und nicht-interagierbar machen, ausser
76// fuer PL innerhalb des Transporters.
77// Ansonsten koennten z.B. Spieler, die im Hafen einen angelegten Transporter
78// betrachten, ihn dadurch als Referenzobjekt haben und Details am
79// unsichtbaren, reisenden Transporter betrachten.
80visible int _query_invis()
81{
Bugfixe50c0d62024-04-02 22:06:37 +020082 if(!roomCode &&
Bugfix0212bb42024-04-05 14:02:59 +020083 (!PL || (environment(PL) != ME && query_verb() != "reise")))
Bugfixe50c0d62024-04-02 22:06:37 +020084 {
85 return 1;
86 }
Zesstra866a3442022-05-07 12:34:13 +020087 return Query(P_INVIS, F_VALUE);
MG Mud User88f12472016-06-24 23:31:02 +020088}
89
90mixed _query_transparent()
Zesstra866a3442022-05-07 12:34:13 +020091{
MG Mud User88f12472016-06-24 23:31:02 +020092 if (roomCode) return Query(P_TRANSPARENT);
Zesstra866a3442022-05-07 12:34:13 +020093 return 0;
MG Mud User88f12472016-06-24 23:31:02 +020094}
95
Zesstra179db0d2016-11-26 13:13:41 +010096static mixed *_set_route(mixed *r) { return route = r; }
97static mixed *_query_route() { return route; }
98static int _query_mnpc_last_meet() { return meet_last_player; }
MG Mud User88f12472016-06-24 23:31:02 +020099
100/*
101 **************** Zugriffsfunktionen ***************
102 */
103
Zesstra179db0d2016-11-26 13:13:41 +0100104public void Halt()
MG Mud User88f12472016-06-24 23:31:02 +0200105{
Zesstra179db0d2016-11-26 13:13:41 +0100106 // stop, but keep rpos counter.
MG Mud User88f12472016-06-24 23:31:02 +0200107 while (remove_call_out( "changeHp" )>-1);
108 while (remove_call_out( "disconnect" )>-1);
109}
110
111// Aktualisiert/Setzt die Route im TravelD, wenn erlaubt (d.h. kein
112// P_NO_TRAVELING)
113private void ReportRoute()
114{
115 if(!QueryProp(P_NO_TRAVELING))
116 {
117 mixed tmp = filter(route, function int (mixed arr)
118 {
119 return arr[0] == HP_ROOM;
120 } );
121 string *route = map(tmp, function string (mixed arr)
122 { return arr[1]; }
123 );
124 TRAVELD->AddRoute(object_name(this_object()),route);
125 }
126}
127
Zesstra179db0d2016-11-26 13:13:41 +0100128public varargs void Start(int pos)
MG Mud User88f12472016-06-24 23:31:02 +0200129{
130 Halt();
Zesstra5d2ace02017-06-20 23:21:36 +0200131 // negative pos sind ein Fehler
132 if (pos<0)
133 raise_error(sprintf("Start(): Positionszaehler < 0: %d\n",pos));
134
135 // wenn pos zu gross fuer die Route ist, rpos auf Ende der Route setzen
136 // (i.e. sizeof(route)-1), damit bei der naechsten Bewegung am Anfang der
137 // Route begonnen wird.
138 rpos = min(pos, sizeof(route)-1);
139
MG Mud User88f12472016-06-24 23:31:02 +0200140 // Tell TRAVELD our current route
141 ReportRoute();
Zesstrac786fee2018-02-12 20:31:29 +0100142 // changeHp() inkrementiert zu Beginn rpos um 1. D.h. damit wir keinen
143 // Haltepunkt ueberspringen, muss dieses vorweg kompensiert werden. Da dies
144 // wiederum den Transporter aber ggf. buggen laesst (rpos<0), darf das
145 // changeHp() hier nicht asynchron per call_out gerufen werden.
146 --rpos;
147 changeHp();
MG Mud User88f12472016-06-24 23:31:02 +0200148}
149
Zesstra179db0d2016-11-26 13:13:41 +0100150// continues the current route at the point we stopped.
151public int Continue()
152{
153 if (find_call_out("changeHp") == -1
154 && find_call_out("disconnect") == -1)
155 {
Zesstra019987a2017-10-24 22:36:08 +0200156 // Nach einer Pause wird die Route am aktuellen Haltepunkt fortgesetzt
157 // (im Regelfall also am Ende der Route). Am Routenende wird auch
158 // geprueft, wann der letzte Spielerkontakt war. Das darf nach einem
159 // Continue() aber nicht passieren, sonst wuerde der Transporter ggf.
160 // sofort wieder anhalten.
161 meet_last_player*=-1; // neg. vorzeichen als Markierung
Zesstra179db0d2016-11-26 13:13:41 +0100162 unsubscribe_init();
163 Start(rpos);
164 return 1;
165 }
166 return 0;
167}
168
169// pauses the transporter temporarily in a way that it continues along its
170// route as soon as a living enters one of the stop points. If that is not
171// possible, we do nothing.
172public int Pause()
173{
174 // ok, stop
175 if (subscribe_init() == 1)
176 {
177 Halt();
178 return 1;
179 }
180 return 0;
181}
182
MG Mud User88f12472016-06-24 23:31:02 +0200183void SetTravelCmds()
184{
185 if (pointerp(QueryProp(P_LEAVECMDS)))
186 AddCmd(QueryProp(P_LEAVECMDS),"GoOutside");
187 if (pointerp(QueryProp(P_ENTERCMDS)))
188 AddCmd(QueryProp(P_ENTERCMDS),"GoInside");
189 if (pointerp(QueryProp(P_TRAVEL_CMDS)))
190 AddCmd(QueryProp(P_TRAVEL_CMDS),"GoInAndOutside");
191 return;
192}
193
194mixed HasRoute(mixed dest)
195{
Arathornb3051452021-05-13 21:13:03 +0200196 int i,s;
MG Mud User88f12472016-06-24 23:31:02 +0200197 object ob;
198 mixed harb;
199
200 s = sizeof(route);
201
202 for (i = rpos;i <= rpos+s-1;i++)
203 {
204 if (route[i%s][0] == HP_ROOM)
205 {
206 if (member(route[i%s][5],dest) != -1 &&
207 objectp(ob=load_object(route[i%s][1])) &&
208 pointerp(harb=ob->QueryProp(P_HARBOUR)) &&
209 sizeof(harb))
210 {
211 return ({ route[i%s][1], harb[0] });
212 }
213 }
214 }
215 return 0;
216}
217
218public varargs void AddRoute(string room, int stay, int next,
219 string harbour_desc, string|string* dest_ids, string deststr)
220{
221 // Daten aus dem Zielanleger abfragen.
222 <string|string*>* harbour = room->QueryProp(P_HARBOUR)||({});
223 string* harbour_ids = ({});
224
225 // IDs des Zielanlegers fuer Syntaxpruefung
226 if ( sizeof(harbour)==2 )
227 {
228 if ( pointerp(harbour[1]) )
229 harbour_ids = harbour[1];
230 else
231 harbour_ids = ({harbour[1]});
232 }
233
234 // <dest_ids> in ein Array umwandeln, ist dann ggf. leer
235 if ( !dest_ids )
236 {
237 dest_ids = ({});
238 }
239 if ( stringp(dest_ids) )
240 {
241 dest_ids = ({dest_ids});
242 }
243
244 // explizit angegebene IDs stehen jetzt in <dest_ids>, die IDs des
245 // Zielhafens aus P_HARBOUR werden addiert.
246 dest_ids += harbour_ids;
247
248 // Ist <dest> immer noch leer, versuchen wir, aus <harbour_desc> ein paar
249 // Stichwoerter zu erzeugen, die man als Zielangabe in der Syntax
250 // "reise nach <ziel>" verwenden kann.
251 if ( !sizeof(dest_ids) )
252 {
253 // Grossgeschriebene Begriffe in <harbour_desc> in <dest> eintragen. Dazu:
254 // 1) <code> erstmal so zerschneiden, dass alle ueblichen Satzzeichen
255 // rausfliegen (es gibt Transporter, die sowas in <harbour_desc>
256 // uebergeben).
257 dest_ids = regexplode(harbour_desc, "[(),.;:&\+_ ]",
258 RE_OMIT_DELIM|RE_GLOBAL);
259 // 2a) So filtern, dass nur grossgeschriebene Woerter uebrig bleiben,
260 // von 1) uebriggebliebene Leerstrings gleich mit wegwerfen.
261 // 2b) Ergebnis kleinschreiben, damit die Syntaxpruefung damit arbeiten
262 // kann.
263 dest_ids = map( filter(dest_ids, function int (string key) {
264 return (key!="" && key[0]>='A' && key[0]<='Z');
265 }), #'lower_case);
266 }
267 // Sollte <dest> jetzt immer noch leer sein, wurde an allen drei Stellen
268 // nichts oder nur Muell uebergeben.
269 if ( !sizeof(dest_ids) )
270 {
271 raise_error("Transporterfehlfunktion in AddRoute(): Identifikations"
272 "matrix unzureichend definiert. Transporter unbenutzbar fuer "
273 "Spieler. Bitte mindestens eine Ziel-ID via P_HARBOUR oder als "
274 "Argument to AddRoute().");
275 }
276 route += ({ ({ HP_ROOM, room, stay, next, harbour_desc, dest_ids,
277 deststr }) });
Zesstra7842b8e2019-07-04 21:55:39 +0200278 route_time += stay + next;
MG Mud User88f12472016-06-24 23:31:02 +0200279}
280
Zesstra7842b8e2019-07-04 21:55:39 +0200281varargs void AddMsg(string msg, int next)
MG Mud User88f12472016-06-24 23:31:02 +0200282{
Zesstra7842b8e2019-07-04 21:55:39 +0200283 route += ({ ({ HP_MSG, msg, next }) });
284 route_time += next;
MG Mud User88f12472016-06-24 23:31:02 +0200285}
286
Zesstra7842b8e2019-07-04 21:55:39 +0200287void AddFun(string fun, int next)
288{
289 route += ({ ({ HP_FUN, fun, next }) });
290 route_time += next;
291}
MG Mud User88f12472016-06-24 23:31:02 +0200292
293string QueryArrived() { return roomCode; }
294
295mixed* QueryPosition()
296{
297 return ({ route[rpos][1],route[(rpos+1)<sizeof(route)?(rpos+1):0][1] });
298}
299
300object* QueryPassengers()
301{
302 return filter(all_inventory(),#'query_once_interactive);
303}
304
305varargs string *QueryHarbours(int textflag)
306{
307 string *ret = ({});
308
309 foreach( mixed* entry : route )
310 {
311 if ( entry[0] == HP_ROOM )
312 {
313 if ( textflag )
314 {
315 string *hp_ids = entry[1]->QueryProp(P_HARBOUR)[1];
316 if (pointerp(hp_ids) && sizeof(hp_ids))
317 {
318 string *h = map( explode(hp_ids[0]," "), #'capitalize);
319 ret += ({ implode(h, " ") });
320 }
321 }
322 else
323 {
324 ret += ({ entry[1] });
325 }
326 }
327 }
328 return ret;
329}
330
331// beim zerstoeren sollte auch die route und der Transporter aus dem traveld
332// abgemeldet werden.
333public varargs int remove(int silent)
334{
335 TRAVELD->RemoveTransporter(this_object());
336 return ::remove(silent);
337}
338
339void RemoveRoute()
340{
341 Halt();
342 route = ({ });
343 rpos = 0;
Zesstra7842b8e2019-07-04 21:55:39 +0200344 route_time = 0;
MG Mud User88f12472016-06-24 23:31:02 +0200345 TRAVELD->RemoveTransporter(this_object());
346}
347
348varargs int Enter(object who)
349{
350 string *emsg;
351 mixed efail;
352
353 if (!objectp(who)) who = this_player();
354 if (environment(who) == this_object())
355 {
356 tell_object(who,"Da bist Du doch bereits, schon vergessen?\n");
357 return 1;
358 }
359 if (!QueryArrived()) return 0;
360 if (QueryProp(P_MAX_PASSENGERS) &&
361 (sizeof(QueryPassengers()) >= QueryProp(P_MAX_PASSENGERS)))
362 {
363 if (pointerp(efail=QueryProp(P_ENTERFAIL)))
364 {
365 if (sizeof(efail) == 2)
366 tell_room(this_object(),who->Name(WER,2)+" "+process_string(efail[1])+
367 ".\n",({who}));
368 tell_object(who,process_string(efail[0])+".\n");
369 }
370 else if (stringp(efail))
371 tell_object(who,process_string(efail)+".\n");
372 else if (closurep(efail)) funcall(efail);
373 return 1;
374 }
375
376 tell_object(who,"Du betrittst "+name(WEN,1)+".\n");
377 if (pointerp(emsg=QueryProp(P_ENTERMSG)) && sizeof(emsg) == 2)
378 return who->move(this_object(),M_GO,"",process_string(emsg[0]),
379 process_string(emsg[1]));
380 return who->move(this_object(),M_GO,
381 name(WEN,1),"betritt","kommt herein");
382}
383
384varargs int Leave(object who)
385{
386 string *lmsg;
387 mixed lfail;
388
389 if (!objectp(who)) who = this_player();
390 if (environment(who) != this_object())
391 {
392 if (QueryArrived())
393 {
394 tell_object(who,"Dafuer muesstest Du erstmal dort sein.\n");
395 return 1;
396 }
397 return 0;
398 }
399 if (!QueryArrived())
400 {
401 if (lfail=QueryProp(P_LEAVEFAIL))
402 {
403 if (pointerp(lfail) && sizeof(lfail))
404 {
405 if (sizeof(lfail) == 2)
406 tell_room(this_object(),who->Name(WER,2)+" "+process_string(
407 lfail[1])+".\n",({who}));
408 tell_object(who,process_string(lfail[0])+".\n");
409 }
410 else if (stringp(lfail))
411 tell_object(who,process_string(lfail)+".\n");
412 else if (closurep(lfail)) funcall(lfail);
413 return 1;
414 }
415 tell_object(who,"Fehler beim Verlassen des Transporters.\n"
416 "Bitte zustaendigen Magier verstaendigen.\n");
417 return 1;
418 }
419
420 if (who->QueryProp(P_TRAVEL_INFO)) who->SetProp(P_TRAVEL_INFO,0);
421 tell_object(who,"Du verlaesst "+name(WEN,1)+".\n");
422 if (pointerp(lmsg=QueryProp(P_LEAVEMSG)) && sizeof(lmsg) == 2)
423 return who->move(environment(),M_GO,"",process_string(lmsg[0]),
424 process_string(lmsg[1]));
425 return who->move(environment(),M_GO,
426 name(WEN,1),"verlaesst","kommt herein");
427}
428
429/*
430 ****************** Internal Functions ******************
431 */
432
433static int GoInside(string str)
434{
435 _notify_fail("Was moechtest Du denn genau?\n");
436 if (stringp(str) && id(str)) {
437 Enter();
438 return 1;
439 }
440 return 0;
441}
442
443static int GoOutside(string str)
444{
445 _notify_fail("Was moechtest Du denn genau?\n");
446 if (stringp(str) && id(str)) {
447 Leave();
448 return 1;
449 }
450 return 0;
451}
452
453static int GoInAndOutside(string str)
454{
455 string to;
456
457 _notify_fail("Was moechtest Du denn genau?\n");
458 if (!sizeof(str)) return 0;
459 if ((sscanf(str,"auf %s",to) == 1 || sscanf(str,"in %s",to) == 1) && id(to))
460 return Enter(),1;
461 if ((sscanf(str,"von %s",to) == 1 || sscanf(str,"aus %s",to) == 1) && id(to))
462 return Leave(),1;
463 return 0;
464}
465
466protected void create()
467{
468 ::create();
469
470 route = ({});
471
472 SetProp(P_LEAVEFAIL,"Das ist momentan viel zu gefaehrlich");
473 SetProp(P_ENTERFAIL,"Dort ist kein Platz mehr fuer Dich");
474 SetProp(P_TRANSPARENT,1);
475
476 AddId("Transporter");
Zesstra179db0d2016-11-26 13:13:41 +0100477
MG Mud User88f12472016-06-24 23:31:02 +0200478 call_out("SetTravelCmds",1);
479}
480
481static varargs void disconnect(int change, int change_time)
482{
Arathorndddb3ae2020-09-06 13:11:42 +0200483 string* departmsg = ({string*})QueryProp(P_DEPARTMSG);
484 string departmsg_me = regreplace(departmsg[0], "@WO", QueryArrived(), 1);
485 string departmsg_env = regreplace(departmsg[1], "@WO", QueryArrived(), 1);
MG Mud User88f12472016-06-24 23:31:02 +0200486
Arathorndddb3ae2020-09-06 13:11:42 +0200487 send_room(this_object(),
488 break_string(departmsg_me, 78, 0, BS_LEAVE_MY_LFS),
489 MT_LOOK|MT_LISTEN);
MG Mud User88f12472016-06-24 23:31:02 +0200490
Arathorndddb3ae2020-09-06 13:11:42 +0200491 if (objectp(environment()))
MG Mud User88f12472016-06-24 23:31:02 +0200492 {
Arathorndddb3ae2020-09-06 13:11:42 +0200493 send_room(environment(),
494 break_string(departmsg_env, 78, 0, BS_LEAVE_MY_LFS),
495 MT_LOOK|MT_LISTEN);
MG Mud User88f12472016-06-24 23:31:02 +0200496 }
497
498 roomCode = 0;
499
500 if (change) call_out("changeHp",change_time);
501}
502
503static varargs void connect(string room, string code)
504{
Arathorndddb3ae2020-09-06 13:11:42 +0200505 mixed *t;
506 object *trav, ob;
507 string *trs, *msgs;
MG Mud User88f12472016-06-24 23:31:02 +0200508 int i;
509
510 if (roomCode) disconnect();
511
512 roomCode = code?code:"";
513
514 if (catch(move(room,M_SILENT|M_NOCHECK);publish))
515 {
516 roomCode = 0;
517 return;
518 }
519
Arathorndddb3ae2020-09-06 13:11:42 +0200520 string* arrivemsg = ({string*})QueryProp(P_ARRIVEMSG);
521 string arrivemsg_me = regreplace(arrivemsg[0], "@WO", QueryArrived(), 1);
522 string arrivemsg_env = regreplace(arrivemsg[1], "@WO", QueryArrived(), 1);
MG Mud User88f12472016-06-24 23:31:02 +0200523
Arathorndddb3ae2020-09-06 13:11:42 +0200524 send_room(this_object(),
525 break_string(arrivemsg_me, 78, 0, BS_LEAVE_MY_LFS),
526 MT_LOOK|MT_LISTEN);
527 send_room(room,
528 break_string(arrivemsg_env, 78, 0, BS_LEAVE_MY_LFS),
529 MT_LOOK|MT_LISTEN);
MG Mud User88f12472016-06-24 23:31:02 +0200530
531 trav = filter(all_inventory(this_object()),#'living);
532
533 i = sizeof(trav);
534 while(i--)
535 {
536 if (pointerp(t = trav[i]->QueryProp(P_TRAVEL_INFO))&&
537 t[0]==this_object()&&t[2]==room)
538 {
539 if (trav[i]->InFight())
540 tell_object(trav[i],break_string("Du solltest Deinen Kampf "
541 "schnell beenden,denn eigentlich wolltest Du hier "
542 "aussteigen.",78));
543 else
544 Leave(trav[i]);
545 if (environment(trav[i])!=this_object())
546 trav[i]->SetProp(P_TRAVEL_INFO,0);
547 }
548 }
549 trav = filter(all_inventory(find_object(room))-trav,#'living);
550 i=sizeof(trav);
551 while(i--)
552 {
553 if (objectp(trav[i]) && pointerp(t = trav[i]->QueryProp(P_TRAVEL_INFO))&&
554 t[0] == environment(trav[i]) && t[1] == this_object())
555 {
556 if ( trav[i]->InFight() )
557 tell_object(trav[i],
558 break_string("Du solltest Deinen Kampf schnell beenden, denn "
559 "eigentlich wolltest Du mit "+name(WEM,1)+
560 " reisen.",78));
561 else
562 Enter(trav[i]);
563 if (environment(trav[i]) == this_object())
564 {
565 t[0] = this_object();
566 trav[i]->SetProp(P_TRAVEL_INFO,t);
567 }
568 }
569 }
570}
571
572// this object never performs any clean-up, the driver should not call it
573// again.
574int clean_up(int arg) { return 0; }
575
Zesstra5b71ebb2018-03-07 20:50:35 +0100576public varargs void init(object origin)
Zesstra179db0d2016-11-26 13:13:41 +0100577{
Zesstra5b71ebb2018-03-07 20:50:35 +0100578 "*"::init(origin);
Zesstra179db0d2016-11-26 13:13:41 +0100579 // if we have player contact (even if the player is just in the same
580 // environment), we update the time.
581 if (this_player() && query_once_interactive(this_player()))
Bugfix4df578b2019-03-13 18:36:59 +0100582 {
583 meet_last_player = time();
584 // Wenn jemand in uns ist, auch falls noetig die Route fortsetzen,
585 // denn wir haben natuerlich nicht H_HOOK_INIT in uns selbst abonniert.
Arathorn303ade72022-12-09 21:53:06 +0100586 // Aber auch nur, wenn nicht jemand schon nen zeitverzögertes
587 // Continue per Hook getriggert hat.
588 if(environment(PL)==ME && find_call_out(#'Continue)==-1)
Bugfix4df578b2019-03-13 18:36:59 +0100589 Continue();
590 }
Zesstra179db0d2016-11-26 13:13:41 +0100591}
592
593// we try to continue our route once some living triggers init.
594private mixed InitHookCallback(object source, int hookid, mixed hookdata)
595{
Arathorn303ade72022-12-09 21:53:06 +0100596 if (hookid == H_HOOK_INIT && previous_object() == source &&
597 find_call_out(#'Continue)==-1)
598 call_out(#'Continue, 0);
Zesstra179db0d2016-11-26 13:13:41 +0100599 return ({H_NO_MOD, hookdata});
600}
601
602// subscribes to H_HOOK_INIT in all rooms along the route
Zesstra658871d2019-07-04 21:34:02 +0200603// == 1 for success, < -1 if not (at least one hook failed, all registration
604// were already subscribed).
Zesstra179db0d2016-11-26 13:13:41 +0100605private int subscribe_init()
606{
607 // subscribe to the H_HOOK_INIT of all rooms in the route...
Zesstra179db0d2016-11-26 13:13:41 +0100608 foreach(mixed* arr : route)
609 {
610 if (arr[0] == HP_ROOM)
611 {
Bugfix7c642a72021-05-16 13:05:52 +0200612 int res = arr[1]->HRegisterToHook(H_HOOK_INIT, #'InitHookCallback,
613 H_HOOK_LIBPRIO(1), H_LISTENER,
614 0);
615 // 1 == Erfolg, -3 == bereits registriert
616 if(res != 1 && res != -3)
Zesstra658871d2019-07-04 21:34:02 +0200617 {
618 // von allen H_HOOK_INIT wieder abmelden...
619 unsubscribe_init();
620 return -1;
621 }
Zesstra179db0d2016-11-26 13:13:41 +0100622 }
623 }
Zesstra658871d2019-07-04 21:34:02 +0200624 return 1;
Zesstra179db0d2016-11-26 13:13:41 +0100625}
626
627// unsubscribes from all the H_HOOK_INIT.
628private void unsubscribe_init()
629{
630 foreach(mixed* arr : route)
631 {
632 if (arr[0] == HP_ROOM)
633 arr[1]->HUnregisterFromHook(H_HOOK_INIT, #'InitHookCallback);
634 }
635}
636
637private int maybe_pause()
638{
Zesstra7842b8e2019-07-04 21:55:39 +0200639 // we check for time of last player contact. If we did not meet any players
640 // for 2 round-trips, we try to pause.
641 if (meet_last_player < time() - (2*route_time) )
Zesstra179db0d2016-11-26 13:13:41 +0100642 {
Zesstra677b5722019-07-04 22:10:01 +0200643 // we don't stop if players are currently at one of our stops
644 foreach(mixed* arr : route)
645 {
646 if (arr[0] == HP_ROOM)
647 {
648 object room = find_object(arr[1]);
649 if(room &&
650 sizeof(filter(all_inventory(room), #'interactive)))
651 return 0; // no pause
652 }
653 }
654 // and we don't stop if players currently are in the transporter.
655 if (sizeof(filter(all_inventory(this_object()), #'interactive)))
656 return 0;
657 // ok, pause machen
658 return Pause();
Zesstra179db0d2016-11-26 13:13:41 +0100659 }
660 return 0;
661}
662
MG Mud User88f12472016-06-24 23:31:02 +0200663void changeHp()
664{
Zesstrafffd2a82017-10-24 22:03:27 +0200665 // Nicht am Ende der Route? Eins weiter.
666 if (rpos < sizeof(route) - 1)
667 ++rpos;
668 else
MG Mud User88f12472016-06-24 23:31:02 +0200669 {
Zesstra019987a2017-10-24 22:36:08 +0200670 // Routenende
671 // Nach einem expliziten Continue() ist meet_last_player < 0. Dann wird
672 // nicht geprueft, ob wir sofort wieder anhalten. Auch muss dann die Route
673 // nicht uebermittelt werden (hat Start() schon gemacht).
674 if (meet_last_player >= 0)
675 {
676 // TRAVELD die aktuelle Route uebermitteln
677 ReportRoute();
678 // everytime, we pass the end of our route, we check if we should
679 // pause our service.
680 if (maybe_pause())
681 return;
682 }
683 else
684 // Wieder pruefen im naechsten Durchlauf.
685 meet_last_player=abs(meet_last_player);
686
Zesstrafffd2a82017-10-24 22:03:27 +0200687 // wenn keine Pause, wieder zum Anfang der Route bewegen.
688 rpos = 0;
MG Mud User88f12472016-06-24 23:31:02 +0200689 }
Zesstrafffd2a82017-10-24 22:03:27 +0200690
MG Mud User88f12472016-06-24 23:31:02 +0200691 if (route[rpos][0] == HP_MSG)
692 {
693 call_out("changeHp",route[rpos][2]);
694 tell_room(this_object(),route[rpos][1]);
695 }
696 else if (route[rpos][0] == HP_FUN)
697 {
698 call_out("changeHp",route[rpos][2]);
699 call_other(this_object(),route[rpos][1]);
700 }
701 else
702 {
703 call_out("disconnect",route[rpos][2],1,route[rpos][3]);
704 connect(route[rpos][1],route[rpos][4]);
705 }
706}
707