blob: b5c352b0cea94e116d71fc0764db65173184b432 [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
20#pragma pedantic
21#pragma range_check
22#pragma no_clone
23
24#define NEED_PROTOTYPES
25#include <thing/properties.h>
26#include <moving.h>
27#include <room/exits.h>
28#include <hook.h>
29#include <exploration.h>
30#undef NEED_PROTOTYPES
31
32#include <sys_debug.h>
33#include <config.h>
34#include <properties.h>
35#include <defines.h>
36#include <daemon.h>
37#include <doorroom.h>
38#include <routingd.h>
39
40#define NUMBERS ({ "zwei", "drei", "vier", "fuenf", "sechs", "sieben", "acht" })
41
42
43// Hilfsfunktion, die bei kaputten Exits eine Notrettung betreibt, aber
44// trotzdem auf Debug eine Meldung macht.
45static mapping rescueExit()
46{
47 catch(raise_error(sprintf(
48 "room/exits.c: Forgotten ::create()? "
49 "P_EXITS in %O is 0!\n", this_object()));publish);
50
51 return ([:2]);
52}
53
54
55static mapping _set_exits( mapping map_ldfied )
56{
57 if( mappingp(map_ldfied) )
58 return Set( P_EXITS, map_ldfied );
59 return 0;
60}
61
62
63static mapping _query_exits()
64{
65 if( (!previous_object() || object_name(previous_object()) != DOOR_MASTER)
66 && QueryProp(P_DOOR_INFOS) )
67 call_other( DOOR_MASTER, "init_doors" );
68
69 mapping exits = Query(P_EXITS) || rescueExit();
70
71 return filter(exits, function int (string key, mixed val)
72 {return stringp(val[0]);} );
73}
74
75
76static int _set_special_exits( mapping map_ldfied )
77{
78 return -1;
79}
80
81
82static mapping _query_special_exits()
83{
84 mapping exits = Query(P_EXITS) || rescueExit();
85
86 return filter(exits, function int (string key, mixed val)
87 {return closurep(val[0]);} );
88}
89
90
91void reset()
92{}
93
94
95protected void create()
96{
97 offerHook(H_HOOK_EXIT_USE, 1);
98 SetProp( P_EXITS, ([:2]) );
Zesstra179db0d2016-11-26 13:13:41 +010099 // Falls dieser Raum ein Haltepunkt von Transportern ist, werden diese
100 // Transporter informiert, dass dieser Raum neugeladen wurde - evtl. will
101 // der Transporter jetzt diesen Raum ansteuern, wenn er pausiert war.
102 object *trans = TRAVELD->HasTransporter(this_object());
103 if (pointerp(trans))
104 {
105 foreach (object t : trans)
106 {
107 t->Continue();
108 }
109 }
MG Mud User88f12472016-06-24 23:31:02 +0200110}
111
112protected void create_super() {
113 set_next_reset(-1);
114}
115
116protected void _AddExit(string|string* cmd, string|closure room,
117 string message)
118{
119 mapping exita;
120
121 exita = Query(P_EXITS) || rescueExit();
122
123 if ( !closurep(room) )
124 {
125 object router;
126
127 room = _MakePath(room);
128
129 if ( !clonep(this_object()) && objectp(router = find_object(ROUTER)) )
130 {
131 router->RegisterExit( object_name(this_object()), cmd, room );
132 }
133 }
134
135 if( stringp(cmd) )
136 {
137 exita += ([ cmd : room; message ]);
138 }
139 else
140 {
141 foreach(string c : cmd)
142 {
143 if (stringp(c))
144 exita += ([ c : room; message ]);
145 }
146 }
147
148 Set( P_EXITS, exita );
149}
150
151void AddExit(string|string* cmd, closure|string dest)
152{
153 string msg;
154 if ( stringp(dest) )
155 {
156 int s;
157 if( (s = member(dest, '#')) != -1 )
158 {
159 msg = dest[0..s-1];
160 dest = dest[s+1..];
161 }
162 }
163 _AddExit(cmd, dest, msg);
164}
165
166void RemoveExit(string|string* cmd )
167{
168 mapping exita;
169
170 if ( !cmd ) {
171 SetProp(P_EXITS, ([:2]) );
172 return;
173 }
174
175 if ( stringp(cmd) )
176 cmd = ({ cmd });
177
178 exita = Query(P_EXITS, F_VALUE) || rescueExit();
179 foreach(string c : cmd)
180 m_delete( exita, c );
181
182 Set( P_EXITS, exita, F_VALUE );
183}
184
185
186void AddSpecialExit(string|string* cmd, string|closure functionname )
187{
188
189 if ( stringp(functionname) )
190 functionname = symbol_function( functionname, this_object() );
191
192 if ( !closurep(functionname) )
193 {
194 catch(raise_error(sprintf( "method %O doesn't exist\n",
195 functionname)); publish);
196 return;
197 }
198
199 AddExit( cmd, functionname );
200}
201
202
203void RemoveSpecialExit(string|string* cmd)
204{
205 RemoveExit( cmd );
206}
207
208
209varargs string GetExits( object viewer )
210{
211 string *indices, *hidden;
212 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();
261 string destroom = exits[query_verb(),0];
262 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{
328 string *comp;
329
330 comp = explode( object_name(this_object()), "/" ) - ({""});
331
332 switch( str[0] ){
333 case '.':
334 str = "/" + implode( comp[0..<2], "/" ) + "/" + str;
335 break;
336
337 case '~':
338 str = "/" + comp[0] + "/" + (comp[0] == "d" ? comp[1] + "/" : "")
339 +REAL_UID(this_object()) + str[1..];
340 break;
341 }
342
343 return MASTER->_get_path( str, getuid(this_object()) );
344}
345