blob: dc724b8714daa4d74447da33e6175851a5b6dabf [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]) );
99}
100
101protected void create_super() {
102 set_next_reset(-1);
103}
104
105protected void _AddExit(string|string* cmd, string|closure room,
106 string message)
107{
108 mapping exita;
109
110 exita = Query(P_EXITS) || rescueExit();
111
112 if ( !closurep(room) )
113 {
114 object router;
115
116 room = _MakePath(room);
117
118 if ( !clonep(this_object()) && objectp(router = find_object(ROUTER)) )
119 {
120 router->RegisterExit( object_name(this_object()), cmd, room );
121 }
122 }
123
124 if( stringp(cmd) )
125 {
126 exita += ([ cmd : room; message ]);
127 }
128 else
129 {
130 foreach(string c : cmd)
131 {
132 if (stringp(c))
133 exita += ([ c : room; message ]);
134 }
135 }
136
137 Set( P_EXITS, exita );
138}
139
140void AddExit(string|string* cmd, closure|string dest)
141{
142 string msg;
143 if ( stringp(dest) )
144 {
145 int s;
146 if( (s = member(dest, '#')) != -1 )
147 {
148 msg = dest[0..s-1];
149 dest = dest[s+1..];
150 }
151 }
152 _AddExit(cmd, dest, msg);
153}
154
155void RemoveExit(string|string* cmd )
156{
157 mapping exita;
158
159 if ( !cmd ) {
160 SetProp(P_EXITS, ([:2]) );
161 return;
162 }
163
164 if ( stringp(cmd) )
165 cmd = ({ cmd });
166
167 exita = Query(P_EXITS, F_VALUE) || rescueExit();
168 foreach(string c : cmd)
169 m_delete( exita, c );
170
171 Set( P_EXITS, exita, F_VALUE );
172}
173
174
175void AddSpecialExit(string|string* cmd, string|closure functionname )
176{
177
178 if ( stringp(functionname) )
179 functionname = symbol_function( functionname, this_object() );
180
181 if ( !closurep(functionname) )
182 {
183 catch(raise_error(sprintf( "method %O doesn't exist\n",
184 functionname)); publish);
185 return;
186 }
187
188 AddExit( cmd, functionname );
189}
190
191
192void RemoveSpecialExit(string|string* cmd)
193{
194 RemoveExit( cmd );
195}
196
197
198varargs string GetExits( object viewer )
199{
200 string *indices, *hidden;
201 string exits;
202
203 if ( QueryProp(P_DOOR_INFOS) )
204 call_other( DOOR_MASTER, "init_doors" );
205
206 indices = m_indices( Query(P_EXITS) || rescueExit() );
207
208 if ( pointerp(hidden = QueryProp(P_HIDE_EXITS)) )
209 indices -= hidden;
210
211 int n=sizeof(indices);
212 switch (n) {
213 case 0:
214 return "Es gibt keine sichtbaren Ausgaenge.\n";
215
216 case 1:
217 return "Es gibt einen sichtbaren Ausgang: " + indices[0] + ".\n";
218
219 case 2: case 3: case 4: case 5: case 6: case 7: case 8:
220 exits = "Es gibt " + NUMBERS[n-2] + " sichtbare Ausgaenge: ";
221 break;
222
223 default:
224 exits = "Es gibt viele sichtbare Ausgaenge: ";
225 }
226 exits += CountUp(indices);
227 return break_string( exits+".", 78 );
228}
229
230
231// Richtungsbefehle nur interpretieren, wenn der Spieler *im* Raum steht und
232// nicht davor (Transporter etc.)/o
233void init()
234{
235 if ( environment(this_player()) == this_object() )
236 add_action( "_normalfunction", "", 1 );
237}
238
239
240/* not only normal exits are handled here */
241
242int _normalfunction()
243{
244 int ret;
245 mapping exits = Query(P_EXITS, F_VALUE) || ([:3]);
246 if (!member(exits,query_verb()))
247 return 0;
248
249 string verb = query_verb();
250 string destroom = exits[query_verb(),0];
251 string message = exits[query_verb(),1];
252
253 mixed hres = HookFlow(H_HOOK_EXIT_USE, ({verb, destroom, message}));
254 if(hres && pointerp(hres) && sizeof(hres)>H_RETDATA)
255 {
256 if(hres[H_RETCODE]==H_CANCELLED)
257 {
258 return 1;
259 }
260 else if(hres[H_RETCODE]==H_ALTERED
261 && pointerp(hres[H_RETDATA])
262 && sizeof(hres[H_RETDATA]) >= 3)
263 {
264 <string|closure>* hdata = hres[H_RETDATA];
265 if (!stringp(hdata[0])
266 || (!stringp(hdata[1]) && !closurep(hdata[1]))
267 || (hdata[2] && !stringp(hdata[2])) )
268 raise_error(sprintf("Invalide Daten aus H_HOOK_EXIT_USE: %.150O\n",
269 hdata));
270 verb = hdata[0];
271 destroom = hdata[1];
272 message = hdata[2];
273 }
274 }
275
276 if( closurep(destroom) )
277 {
278 ret = funcall( destroom, verb );
279
280 if(ret==MOVE_OK)
281 {
282 GiveEP( EP_EXIT, verb );
283 }
284
285 return ret;
286 }
287
288 if (!stringp(message))
289 {
290 if( member( ({ "sueden", "suedwesten", "westen","nordwesten", "norden",
291 "nordosten", "osten","suedosten" }), verb ) != -1 )
292 {
293 message = "nach " + capitalize(verb);
294 }
295 else if ( member( ({ "oben", "unten" }), verb ) != -1 )
296 {
297 message = "nach " + verb;
298 }
299 else
300 {
301 message = verb;
302 }
303 }
304
305 ret = this_player()->move( destroom, M_GO, message );
306
307 if (ret==MOVE_OK)
308 {
309 GiveEP( EP_EXIT, verb );
310 }
311
312 return ret;
313}
314
315static string _MakePath( string str )
316{
317 string *comp;
318
319 comp = explode( object_name(this_object()), "/" ) - ({""});
320
321 switch( str[0] ){
322 case '.':
323 str = "/" + implode( comp[0..<2], "/" ) + "/" + str;
324 break;
325
326 case '~':
327 str = "/" + comp[0] + "/" + (comp[0] == "d" ? comp[1] + "/" : "")
328 +REAL_UID(this_object()) + str[1..];
329 break;
330 }
331
332 return MASTER->_get_path( str, getuid(this_object()) );
333}
334