blob: 20253bce7d702a2105fbfbf53d6bd5ead0ff523b [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// room/exits.c -- room exits handling
4//
5// $Id: exits.c 9497 2016-02-21 14:20:03Z Zesstra $
6
7/*
8 * Exits of the room (obvious ones, doors, and special ones)
9 * we define the following function for easy reference:
10 * GetExits() - return a string containing an "Obvious Exits" Statement
11 *
12 * The exits are implemented as properties P_EXITS
13 * They are stored locally (_set_xx, _query_xx)
14 * as mapping to speed up the routines in this module.
15 *
16 */
17
18#pragma strong_types
19#pragma save_types
MG Mud User88f12472016-06-24 23:31:02 +020020#pragma range_check
21#pragma no_clone
22
23#define NEED_PROTOTYPES
24#include <thing/properties.h>
25#include <moving.h>
26#include <room/exits.h>
27#include <hook.h>
28#include <exploration.h>
29#undef NEED_PROTOTYPES
30
31#include <sys_debug.h>
32#include <config.h>
33#include <properties.h>
34#include <defines.h>
35#include <daemon.h>
36#include <doorroom.h>
37#include <routingd.h>
38
39#define NUMBERS ({ "zwei", "drei", "vier", "fuenf", "sechs", "sieben", "acht" })
40
41
42// Hilfsfunktion, die bei kaputten Exits eine Notrettung betreibt, aber
43// trotzdem auf Debug eine Meldung macht.
44static mapping rescueExit()
45{
46 catch(raise_error(sprintf(
47 "room/exits.c: Forgotten ::create()? "
48 "P_EXITS in %O is 0!\n", this_object()));publish);
49
50 return ([:2]);
51}
52
53
54static mapping _set_exits( mapping map_ldfied )
55{
56 if( mappingp(map_ldfied) )
57 return Set( P_EXITS, map_ldfied );
58 return 0;
59}
60
61
62static mapping _query_exits()
63{
64 if( (!previous_object() || object_name(previous_object()) != DOOR_MASTER)
65 && QueryProp(P_DOOR_INFOS) )
66 call_other( DOOR_MASTER, "init_doors" );
67
68 mapping exits = Query(P_EXITS) || rescueExit();
69
70 return filter(exits, function int (string key, mixed val)
71 {return stringp(val[0]);} );
72}
73
74
75static int _set_special_exits( mapping map_ldfied )
76{
77 return -1;
78}
79
80
81static mapping _query_special_exits()
82{
83 mapping exits = Query(P_EXITS) || rescueExit();
84
85 return filter(exits, function int (string key, mixed val)
86 {return closurep(val[0]);} );
87}
88
89
90void reset()
91{}
92
93
94protected void create()
95{
96 offerHook(H_HOOK_EXIT_USE, 1);
97 SetProp( P_EXITS, ([:2]) );
Zesstra179db0d2016-11-26 13:13:41 +010098 // Falls dieser Raum ein Haltepunkt von Transportern ist, werden diese
99 // Transporter informiert, dass dieser Raum neugeladen wurde - evtl. will
100 // der Transporter jetzt diesen Raum ansteuern, wenn er pausiert war.
101 object *trans = TRAVELD->HasTransporter(this_object());
102 if (pointerp(trans))
103 {
104 foreach (object t : trans)
105 {
106 t->Continue();
107 }
108 }
MG Mud User88f12472016-06-24 23:31:02 +0200109}
110
111protected void create_super() {
112 set_next_reset(-1);
113}
114
115protected void _AddExit(string|string* cmd, string|closure room,
116 string message)
117{
118 mapping exita;
119
120 exita = Query(P_EXITS) || rescueExit();
121
122 if ( !closurep(room) )
123 {
124 object router;
125
126 room = _MakePath(room);
127
128 if ( !clonep(this_object()) && objectp(router = find_object(ROUTER)) )
129 {
130 router->RegisterExit( object_name(this_object()), cmd, room );
131 }
132 }
133
134 if( stringp(cmd) )
135 {
136 exita += ([ cmd : room; message ]);
137 }
138 else
139 {
140 foreach(string c : cmd)
141 {
142 if (stringp(c))
143 exita += ([ c : room; message ]);
144 }
145 }
146
147 Set( P_EXITS, exita );
148}
149
150void AddExit(string|string* cmd, closure|string dest)
151{
152 string msg;
153 if ( stringp(dest) )
154 {
155 int s;
156 if( (s = member(dest, '#')) != -1 )
157 {
158 msg = dest[0..s-1];
159 dest = dest[s+1..];
160 }
161 }
162 _AddExit(cmd, dest, msg);
163}
164
165void RemoveExit(string|string* cmd )
166{
167 mapping exita;
168
169 if ( !cmd ) {
170 SetProp(P_EXITS, ([:2]) );
171 return;
172 }
173
174 if ( stringp(cmd) )
175 cmd = ({ cmd });
176
177 exita = Query(P_EXITS, F_VALUE) || rescueExit();
178 foreach(string c : cmd)
179 m_delete( exita, c );
180
181 Set( P_EXITS, exita, F_VALUE );
182}
183
184
185void AddSpecialExit(string|string* cmd, string|closure functionname )
186{
187
188 if ( stringp(functionname) )
189 functionname = symbol_function( functionname, this_object() );
190
191 if ( !closurep(functionname) )
192 {
193 catch(raise_error(sprintf( "method %O doesn't exist\n",
194 functionname)); publish);
195 return;
196 }
197
198 AddExit( cmd, functionname );
199}
200
201
202void RemoveSpecialExit(string|string* cmd)
203{
204 RemoveExit( cmd );
205}
206
207
208varargs string GetExits( object viewer )
209{
Arathorn9845d112020-01-08 22:02:03 +0100210 string *indices;
211 int|string* hidden;
MG Mud User88f12472016-06-24 23:31:02 +0200212 string exits;
213
214 if ( QueryProp(P_DOOR_INFOS) )
215 call_other( DOOR_MASTER, "init_doors" );
216
217 indices = m_indices( Query(P_EXITS) || rescueExit() );
218
219 if ( pointerp(hidden = QueryProp(P_HIDE_EXITS)) )
220 indices -= hidden;
221
222 int n=sizeof(indices);
223 switch (n) {
224 case 0:
225 return "Es gibt keine sichtbaren Ausgaenge.\n";
226
227 case 1:
228 return "Es gibt einen sichtbaren Ausgang: " + indices[0] + ".\n";
229
230 case 2: case 3: case 4: case 5: case 6: case 7: case 8:
231 exits = "Es gibt " + NUMBERS[n-2] + " sichtbare Ausgaenge: ";
232 break;
233
234 default:
235 exits = "Es gibt viele sichtbare Ausgaenge: ";
236 }
237 exits += CountUp(indices);
238 return break_string( exits+".", 78 );
239}
240
241
242// Richtungsbefehle nur interpretieren, wenn der Spieler *im* Raum steht und
243// nicht davor (Transporter etc.)/o
Zesstra5b71ebb2018-03-07 20:50:35 +0100244public varargs void init(object origin)
MG Mud User88f12472016-06-24 23:31:02 +0200245{
246 if ( environment(this_player()) == this_object() )
247 add_action( "_normalfunction", "", 1 );
248}
249
250
251/* not only normal exits are handled here */
252
253int _normalfunction()
254{
255 int ret;
256 mapping exits = Query(P_EXITS, F_VALUE) || ([:3]);
257 if (!member(exits,query_verb()))
258 return 0;
259
260 string verb = query_verb();
Zesstra298c3de2019-04-25 14:12:35 +0200261 string|closure destroom = exits[query_verb(),0];
MG Mud User88f12472016-06-24 23:31:02 +0200262 string message = exits[query_verb(),1];
263
264 mixed hres = HookFlow(H_HOOK_EXIT_USE, ({verb, destroom, message}));
265 if(hres && pointerp(hres) && sizeof(hres)>H_RETDATA)
266 {
267 if(hres[H_RETCODE]==H_CANCELLED)
268 {
269 return 1;
270 }
271 else if(hres[H_RETCODE]==H_ALTERED
272 && pointerp(hres[H_RETDATA])
273 && sizeof(hres[H_RETDATA]) >= 3)
274 {
275 <string|closure>* hdata = hres[H_RETDATA];
276 if (!stringp(hdata[0])
277 || (!stringp(hdata[1]) && !closurep(hdata[1]))
278 || (hdata[2] && !stringp(hdata[2])) )
279 raise_error(sprintf("Invalide Daten aus H_HOOK_EXIT_USE: %.150O\n",
280 hdata));
281 verb = hdata[0];
282 destroom = hdata[1];
283 message = hdata[2];
284 }
285 }
286
287 if( closurep(destroom) )
288 {
289 ret = funcall( destroom, verb );
290
291 if(ret==MOVE_OK)
292 {
293 GiveEP( EP_EXIT, verb );
294 }
295
296 return ret;
297 }
298
299 if (!stringp(message))
300 {
301 if( member( ({ "sueden", "suedwesten", "westen","nordwesten", "norden",
302 "nordosten", "osten","suedosten" }), verb ) != -1 )
303 {
304 message = "nach " + capitalize(verb);
305 }
306 else if ( member( ({ "oben", "unten" }), verb ) != -1 )
307 {
308 message = "nach " + verb;
309 }
310 else
311 {
312 message = verb;
313 }
314 }
315
316 ret = this_player()->move( destroom, M_GO, message );
317
318 if (ret==MOVE_OK)
319 {
320 GiveEP( EP_EXIT, verb );
321 }
322
323 return ret;
324}
325
326static string _MakePath( string str )
327{
Zesstra6fa58d42018-11-08 22:21:21 +0100328 string *comp = explode( object_name(this_object()), "/" ) - ({""});
MG Mud User88f12472016-06-24 23:31:02 +0200329
Zesstra6fa58d42018-11-08 22:21:21 +0100330 switch( str[0] )
331 {
MG Mud User88f12472016-06-24 23:31:02 +0200332 case '.':
333 str = "/" + implode( comp[0..<2], "/" ) + "/" + str;
334 break;
Zesstra6fa58d42018-11-08 22:21:21 +0100335
336 // Konstruiert einen Pfad relativ zu /players/REAL_UID bzw.
337 // /d/<region>/REAL_UID/.
MG Mud User88f12472016-06-24 23:31:02 +0200338 case '~':
339 str = "/" + comp[0] + "/" + (comp[0] == "d" ? comp[1] + "/" : "")
340 +REAL_UID(this_object()) + str[1..];
341 break;
342 }
Zesstra6fa58d42018-11-08 22:21:21 +0100343 // macht den Pfad absolut und halbwegs "sane", loest .. im Pfad auf.
344 // Beruecksichtigt KEINE weiteren Platzhalter.
345 return master()->make_path_absolute(str);
MG Mud User88f12472016-06-24 23:31:02 +0200346}
347