| // MorgenGrauen MUDlib |
| // |
| // room/exits.c -- room exits handling |
| // |
| // $Id: exits.c 9497 2016-02-21 14:20:03Z Zesstra $ |
| |
| /* |
| * Exits of the room (obvious ones, doors, and special ones) |
| * we define the following function for easy reference: |
| * GetExits() - return a string containing an "Obvious Exits" Statement |
| * |
| * The exits are implemented as properties P_EXITS |
| * They are stored locally (_set_xx, _query_xx) |
| * as mapping to speed up the routines in this module. |
| * |
| */ |
| |
| #pragma strong_types |
| #pragma save_types |
| #pragma pedantic |
| #pragma range_check |
| #pragma no_clone |
| |
| #define NEED_PROTOTYPES |
| #include <thing/properties.h> |
| #include <moving.h> |
| #include <room/exits.h> |
| #include <hook.h> |
| #include <exploration.h> |
| #undef NEED_PROTOTYPES |
| |
| #include <sys_debug.h> |
| #include <config.h> |
| #include <properties.h> |
| #include <defines.h> |
| #include <daemon.h> |
| #include <doorroom.h> |
| #include <routingd.h> |
| |
| #define NUMBERS ({ "zwei", "drei", "vier", "fuenf", "sechs", "sieben", "acht" }) |
| |
| |
| // Hilfsfunktion, die bei kaputten Exits eine Notrettung betreibt, aber |
| // trotzdem auf Debug eine Meldung macht. |
| static mapping rescueExit() |
| { |
| catch(raise_error(sprintf( |
| "room/exits.c: Forgotten ::create()? " |
| "P_EXITS in %O is 0!\n", this_object()));publish); |
| |
| return ([:2]); |
| } |
| |
| |
| static mapping _set_exits( mapping map_ldfied ) |
| { |
| if( mappingp(map_ldfied) ) |
| return Set( P_EXITS, map_ldfied ); |
| return 0; |
| } |
| |
| |
| static mapping _query_exits() |
| { |
| if( (!previous_object() || object_name(previous_object()) != DOOR_MASTER) |
| && QueryProp(P_DOOR_INFOS) ) |
| call_other( DOOR_MASTER, "init_doors" ); |
| |
| mapping exits = Query(P_EXITS) || rescueExit(); |
| |
| return filter(exits, function int (string key, mixed val) |
| {return stringp(val[0]);} ); |
| } |
| |
| |
| static int _set_special_exits( mapping map_ldfied ) |
| { |
| return -1; |
| } |
| |
| |
| static mapping _query_special_exits() |
| { |
| mapping exits = Query(P_EXITS) || rescueExit(); |
| |
| return filter(exits, function int (string key, mixed val) |
| {return closurep(val[0]);} ); |
| } |
| |
| |
| void reset() |
| {} |
| |
| |
| protected void create() |
| { |
| offerHook(H_HOOK_EXIT_USE, 1); |
| SetProp( P_EXITS, ([:2]) ); |
| } |
| |
| protected void create_super() { |
| set_next_reset(-1); |
| } |
| |
| protected void _AddExit(string|string* cmd, string|closure room, |
| string message) |
| { |
| mapping exita; |
| |
| exita = Query(P_EXITS) || rescueExit(); |
| |
| if ( !closurep(room) ) |
| { |
| object router; |
| |
| room = _MakePath(room); |
| |
| if ( !clonep(this_object()) && objectp(router = find_object(ROUTER)) ) |
| { |
| router->RegisterExit( object_name(this_object()), cmd, room ); |
| } |
| } |
| |
| if( stringp(cmd) ) |
| { |
| exita += ([ cmd : room; message ]); |
| } |
| else |
| { |
| foreach(string c : cmd) |
| { |
| if (stringp(c)) |
| exita += ([ c : room; message ]); |
| } |
| } |
| |
| Set( P_EXITS, exita ); |
| } |
| |
| void AddExit(string|string* cmd, closure|string dest) |
| { |
| string msg; |
| if ( stringp(dest) ) |
| { |
| int s; |
| if( (s = member(dest, '#')) != -1 ) |
| { |
| msg = dest[0..s-1]; |
| dest = dest[s+1..]; |
| } |
| } |
| _AddExit(cmd, dest, msg); |
| } |
| |
| void RemoveExit(string|string* cmd ) |
| { |
| mapping exita; |
| |
| if ( !cmd ) { |
| SetProp(P_EXITS, ([:2]) ); |
| return; |
| } |
| |
| if ( stringp(cmd) ) |
| cmd = ({ cmd }); |
| |
| exita = Query(P_EXITS, F_VALUE) || rescueExit(); |
| foreach(string c : cmd) |
| m_delete( exita, c ); |
| |
| Set( P_EXITS, exita, F_VALUE ); |
| } |
| |
| |
| void AddSpecialExit(string|string* cmd, string|closure functionname ) |
| { |
| |
| if ( stringp(functionname) ) |
| functionname = symbol_function( functionname, this_object() ); |
| |
| if ( !closurep(functionname) ) |
| { |
| catch(raise_error(sprintf( "method %O doesn't exist\n", |
| functionname)); publish); |
| return; |
| } |
| |
| AddExit( cmd, functionname ); |
| } |
| |
| |
| void RemoveSpecialExit(string|string* cmd) |
| { |
| RemoveExit( cmd ); |
| } |
| |
| |
| varargs string GetExits( object viewer ) |
| { |
| string *indices, *hidden; |
| string exits; |
| |
| if ( QueryProp(P_DOOR_INFOS) ) |
| call_other( DOOR_MASTER, "init_doors" ); |
| |
| indices = m_indices( Query(P_EXITS) || rescueExit() ); |
| |
| if ( pointerp(hidden = QueryProp(P_HIDE_EXITS)) ) |
| indices -= hidden; |
| |
| int n=sizeof(indices); |
| switch (n) { |
| case 0: |
| return "Es gibt keine sichtbaren Ausgaenge.\n"; |
| |
| case 1: |
| return "Es gibt einen sichtbaren Ausgang: " + indices[0] + ".\n"; |
| |
| case 2: case 3: case 4: case 5: case 6: case 7: case 8: |
| exits = "Es gibt " + NUMBERS[n-2] + " sichtbare Ausgaenge: "; |
| break; |
| |
| default: |
| exits = "Es gibt viele sichtbare Ausgaenge: "; |
| } |
| exits += CountUp(indices); |
| return break_string( exits+".", 78 ); |
| } |
| |
| |
| // Richtungsbefehle nur interpretieren, wenn der Spieler *im* Raum steht und |
| // nicht davor (Transporter etc.)/o |
| void init() |
| { |
| if ( environment(this_player()) == this_object() ) |
| add_action( "_normalfunction", "", 1 ); |
| } |
| |
| |
| /* not only normal exits are handled here */ |
| |
| int _normalfunction() |
| { |
| int ret; |
| mapping exits = Query(P_EXITS, F_VALUE) || ([:3]); |
| if (!member(exits,query_verb())) |
| return 0; |
| |
| string verb = query_verb(); |
| string destroom = exits[query_verb(),0]; |
| string message = exits[query_verb(),1]; |
| |
| mixed hres = HookFlow(H_HOOK_EXIT_USE, ({verb, destroom, message})); |
| if(hres && pointerp(hres) && sizeof(hres)>H_RETDATA) |
| { |
| if(hres[H_RETCODE]==H_CANCELLED) |
| { |
| return 1; |
| } |
| else if(hres[H_RETCODE]==H_ALTERED |
| && pointerp(hres[H_RETDATA]) |
| && sizeof(hres[H_RETDATA]) >= 3) |
| { |
| <string|closure>* hdata = hres[H_RETDATA]; |
| if (!stringp(hdata[0]) |
| || (!stringp(hdata[1]) && !closurep(hdata[1])) |
| || (hdata[2] && !stringp(hdata[2])) ) |
| raise_error(sprintf("Invalide Daten aus H_HOOK_EXIT_USE: %.150O\n", |
| hdata)); |
| verb = hdata[0]; |
| destroom = hdata[1]; |
| message = hdata[2]; |
| } |
| } |
| |
| if( closurep(destroom) ) |
| { |
| ret = funcall( destroom, verb ); |
| |
| if(ret==MOVE_OK) |
| { |
| GiveEP( EP_EXIT, verb ); |
| } |
| |
| return ret; |
| } |
| |
| if (!stringp(message)) |
| { |
| if( member( ({ "sueden", "suedwesten", "westen","nordwesten", "norden", |
| "nordosten", "osten","suedosten" }), verb ) != -1 ) |
| { |
| message = "nach " + capitalize(verb); |
| } |
| else if ( member( ({ "oben", "unten" }), verb ) != -1 ) |
| { |
| message = "nach " + verb; |
| } |
| else |
| { |
| message = verb; |
| } |
| } |
| |
| ret = this_player()->move( destroom, M_GO, message ); |
| |
| if (ret==MOVE_OK) |
| { |
| GiveEP( EP_EXIT, verb ); |
| } |
| |
| return ret; |
| } |
| |
| static string _MakePath( string str ) |
| { |
| string *comp; |
| |
| comp = explode( object_name(this_object()), "/" ) - ({""}); |
| |
| switch( str[0] ){ |
| case '.': |
| str = "/" + implode( comp[0..<2], "/" ) + "/" + str; |
| break; |
| |
| case '~': |
| str = "/" + comp[0] + "/" + (comp[0] == "d" ? comp[1] + "/" : "") |
| +REAL_UID(this_object()) + str[1..]; |
| break; |
| } |
| |
| return MASTER->_get_path( str, getuid(this_object()) ); |
| } |
| |