| // MorgenGrauen MUDlib |
| // |
| // player/viewcmd.c -- player view command handling |
| // |
| // $Id: viewcmd.c 9548 2016-04-17 19:28:22Z Zesstra $ |
| |
| #pragma strong_types |
| #pragma save_types |
| #pragma range_check |
| #pragma no_clone |
| |
| //#include <player.h> |
| #include <properties.h> |
| #include <rooms.h> |
| #include <wizlevels.h> |
| #include <defines.h> |
| #include <moving.h> |
| #include <new_skills.h> |
| #include <ansi.h> |
| #include <notify_fail.h> |
| |
| #define NEED_PROTOTYPES |
| #include <container.h> |
| #include <thing/properties.h> |
| #include <living/put_and_get.h> |
| #include <living/description.h> |
| #include <living/put_and_get.h> |
| #include <player/command.h> |
| |
| //#define DEBUG(x, y, z) send_debug(x, y, z) |
| #define DEBUG(x, y, z) |
| |
| varargs mixed More(string str, int fflag, string returnto); |
| |
| void create() |
| { |
| Set(P_BRIEF, SAVE, F_MODE); |
| Set(P_BLIND, SAVE, F_MODE); |
| } |
| |
| int _toggle_brief() |
| { |
| int brief; |
| |
| if (query_verb()=="kurz") |
| brief=1; |
| else if (query_verb()=="ultrakurz") |
| brief=2; |
| else brief=0; |
| SetProp(P_BRIEF, brief); |
| write("Du bist nun im \""+ |
| (brief?(brief==1?"Kurz":"Ultrakurz"):"Lang")+"\"modus.\n"); |
| return 1; |
| } |
| |
| private int sortinv(mixed a, mixed b) { return a[0] > b[0]; } |
| |
| private string collectinv(mixed obj) |
| { |
| if(obj[0]=="") return 0; |
| return (obj[2] ? " " : "") |
| + obj[0] |
| + (obj[1] > 1 ? " ("+obj[1]+")" : ""); |
| } |
| |
| #define I_AUTOLOAD 1 |
| #define I_KEEP 4 |
| #define I_FORMATTED 16 |
| #define I_ARMOUR 64 |
| #define I_SORT 256 |
| #define I_WEAPON 1024 |
| #define I_FORCE_SORT 4096 |
| #define I_NO_TABLE 16384 |
| |
| private string getflags(string arg, int flags) |
| { |
| int no, i; |
| if(sizeof(arg) < 2) return 0; |
| no = (arg[0] == '-'); |
| |
| for(i = 1; i < sizeof(arg); i++) |
| { |
| switch(arg[i]) |
| { |
| case 'a': flags |= I_AUTOLOAD << no; break; |
| case 'b': flags |= I_KEEP << no; break; |
| case 'f': flags |= I_FORMATTED << no; break; |
| case 'r': flags |= I_ARMOUR << no; break; |
| case 's': flags |= I_SORT << no; break; |
| case 'w': flags |= I_WEAPON << no; break; |
| case 'v': flags |= (I_ARMOUR | I_WEAPON) << !no; break; |
| case '1': flags |= I_NO_TABLE; break; |
| // Die Option macht nur Aerger und kommentiert ist sie eh nicht. |
| // Wer das dringend braucht, soll Wargons Schiebepuzzle benutzen. |
| // |
| // Tiamak, 15.10.2000 |
| // case 'S': flags |= I_FORCE_SORT << no; break; |
| default : return arg[i..i]; // wird ausgegeben an Spieler als unbekannt. |
| } |
| } |
| return 0; |
| } |
| |
| static int _check_keep(object ob) |
| { |
| return (ob->QueryProp(P_KEEP_ON_SELL))==geteuid(ME); |
| } |
| |
| int _inventory(string str) |
| { |
| mixed *args, output; |
| int ansi, i, flags, minv; |
| mixed inventory, weapons, armours, misc; |
| string format; |
| |
| if(CannotSee()) return 1; |
| |
| if((str = _unparsed_args()) && str!="") |
| { |
| string error; |
| error = "Benutzung: i[nventar] [-/+1abfrsvw]\n"; |
| args = regexp(regexplode(str, "[-+][1abfrswv][1abfrswv]*"), |
| "[-+][1abfrswv][1abfrswv]*"); |
| if(!sizeof(args)) return (_notify_fail(error), 0); |
| if(sizeof(args = map(args, #'getflags/*'*/, &flags) - ({ 0 }))) |
| { |
| printf("%s: Unbekanntes Argument.\n"+error, implode(args, ", ")); |
| return 1; |
| } |
| } |
| // Fuer Spieler gehen nur sichtbare Objekte in den Algorithmus |
| if (IS_LEARNING(ME)) |
| inventory = all_inventory(ME); |
| else |
| inventory = filter_objects(all_inventory(ME), "short"); |
| |
| ansi = member(({"vt100", "ansi"}), QueryProp(P_TTY)) != -1; |
| minv = 1 | (flags & (I_FORMATTED | (I_FORMATTED << 1)) ? 2 : 0); |
| format = (flags & I_NO_TABLE) ? "=" : "#"; |
| |
| // if(flags & (I_FORCE_SORT | I_FORCE_SORT << 1)) |
| // { |
| // closure sf; |
| // sf = flags & I_FORCE_SORT ? #'> : #'<; |
| // s = sort_array(s, lambda(({'a, 'b}), |
| // ({#'funcall, sf, |
| // ({#'||,({#'call_other,'a,"short"}),""}), |
| // ({#'||,({#'call_other,'b,"short"}),""})}))); |
| // map_objects(s, "move", this_object()); |
| // s = all_inventory(ME); |
| // } |
| |
| if (flags & I_AUTOLOAD) |
| inventory = filter_objects(inventory,"QueryProp",P_AUTOLOADOBJ); |
| else if (flags & (I_AUTOLOAD << 1)) |
| inventory -= filter_objects(inventory,"QueryProp",P_AUTOLOADOBJ); |
| |
| if(flags & I_KEEP) |
| inventory = filter(inventory,#'_check_keep); |
| else if(flags & (I_KEEP << 1)) |
| inventory -= filter(inventory,#'_check_keep); |
| |
| armours = filter_objects(inventory, "QueryProp", P_ARMOUR_TYPE); |
| // Kleidung dazu addieren, vorher die erkannten Ruestungen abziehen, die |
| // muessen nicht nochmal durchiteriert werden. |
| armours += filter_objects(inventory-armours, "IsClothing"); |
| // Ruestungen werden hier nicht abgezogen, weil es Kram gibt, welche sowohl |
| // Ruestung als auch Waffe ist. |
| weapons = filter_objects(inventory, "QueryProp", P_WEAPON_TYPE); |
| misc = inventory - weapons - armours; // rest ;-) |
| |
| if(flags & I_WEAPON) |
| { |
| inventory = weapons; misc = ({}); |
| if(!(flags & (I_ARMOUR))) armours = ({}); |
| } |
| if(flags & I_ARMOUR) |
| { |
| inventory = armours; misc = ({}); |
| if(!(flags & I_WEAPON)) weapons = ({}); |
| } |
| if(flags & (I_WEAPON << 1)) { weapons = ({}); inventory = armours + misc; } |
| if(flags & (I_ARMOUR << 1)) { armours = ({}); inventory = weapons + misc; } |
| |
| output = ""; |
| if(flags & (I_FORMATTED | (I_FORMATTED << 1))) |
| { |
| inventory = make_invlist(this_player(), inventory, minv); |
| if(flags & (I_SORT | (I_SORT << 1))) |
| inventory = sort_array(inventory, #'sortinv/*'*/); |
| output += sprintf("%"+format+"-78s\n", |
| implode(map(inventory,#'collectinv/*'*/),"\n")); |
| } |
| else |
| { |
| if(weapons && sizeof(weapons)) |
| { |
| weapons = make_invlist(this_player(), weapons, minv); |
| if(flags & (I_SORT | (I_SORT << 1))) |
| weapons = sort_array(weapons, #'sortinv/*'*/); |
| output += (ansi?ANSI_BOLD:"") + "Waffen:" + (ansi?ANSI_NORMAL:"")+"\n" |
| + sprintf("%"+format+"-78s\n", |
| implode(map(weapons, #'collectinv/*'*/), "\n")); |
| } |
| if(armours && sizeof(armours)) |
| { |
| armours = make_invlist(this_player(), armours, minv); |
| if(flags & (I_SORT | (I_SORT << 1))) |
| armours = sort_array(armours, #'sortinv/*'*/); |
| output += (ansi?ANSI_BOLD:"") |
| + "Kleidung & Ruestungen:" + (ansi?ANSI_NORMAL:"")+"\n" |
| + sprintf("%"+format+"-78s\n", |
| implode(map(armours, #'collectinv/*'*/), "\n")); |
| } |
| if(misc && sizeof(misc)) |
| { |
| misc = make_invlist(this_player(), misc, minv); |
| if(flags & (I_SORT | (I_SORT << 1))) |
| misc = sort_array(misc, #'sortinv/*'*/); |
| output += (ansi?ANSI_BOLD:"") + "Verschiedenes:" + (ansi?ANSI_NORMAL:"")+"\n" |
| + sprintf("%"+format+"-78s\n", |
| implode(map(misc, #'collectinv/*'*/), "\n")); |
| } |
| } |
| |
| // Spielerwunsch: 'inventar' sollte doch das Bezugsobjekt auf den Spieler |
| // aendern. |
| SetProp(P_REFERENCE_OBJECT, this_object()); |
| |
| if (output=="") |
| output += (ansi?ANSI_BOLD:"")+"Die Liste ist leer."+(ansi?ANSI_NORMAL:""); |
| More(output); |
| return 1; |
| } |
| |
| private int select_sense(string str, closure transparent_check) |
| { |
| int sense = -1; |
| if(member(({"riech","rieche","schnupper","schnuppere"}),query_verb())!=-1) |
| { |
| _notify_fail("Du kannst nichts Besonderes riechen.\n"); |
| sense = SENSE_SMELL; |
| } |
| else if(member(({"lausche","lausch","hoer","hoere"}),query_verb())!=-1) |
| { |
| if(QueryProp(P_DEAF)) |
| { |
| notify_fail("Du bist taub!\n"); |
| return -1; |
| } |
| _notify_fail("Du kannst nichts Besonderes hoeren.\n"); |
| sense = SENSE_SOUND; |
| } |
| else if(member(({"taste","beruehre","beruehr"}),query_verb())!=-1) |
| { |
| sense = SENSE_TOUCH; |
| // ein "ab" ganz am Ende von str wird abgeschnitten, es soll sowohl "taste |
| // x ab" als auch "taste x" funktionieren. |
| if (str) { |
| _notify_fail("Sowas kannst Du hier nicht ertasten!\n"); |
| string *tmp = explode(str," "); |
| if (sizeof(tmp) > 1 && tmp[<1] == "ab") |
| str = implode(tmp[0..<2], " "); |
| } |
| else |
| _notify_fail("Was willst Du denn abtasten?\n"); |
| } |
| else if (member(({"lies","lese","les"}), query_verb()) > -1) |
| { |
| _notify_fail("Was willst Du lesen?\n"); |
| if ( !str ) // Kein SENSE_DEFAULT zulassen. |
| return -1; |
| if (CannotSee(1)) { |
| notify_fail("Du kannst nichts sehen!\n", NF_NL_MAX); |
| return -1; |
| } |
| sense = SENSE_READ; |
| } |
| // else ist normales Sehen/untersuchen |
| else |
| { |
| if (CannotSee(1)) { |
| notify_fail("Du kannst nichts sehen!\n", NF_NL_MAX); |
| return -1; |
| } |
| _notify_fail("Was willst Du denn untersuchen?\n"); |
| if (!str) return -1; |
| sense = SENSE_VIEW; |
| } |
| // "rieche an ..." etc.: das an rausschneiden, wird nicht gebraucht. |
| if (sizeof(str)) |
| { |
| if (sense!=SENSE_VIEW) |
| { |
| string what; |
| if (sscanf(str,"an %s",what)==1) str=what; |
| } |
| } |
| |
| switch(sense) |
| { |
| // Fuer diese Sinne muss der Container offen sein. |
| case SENSE_SMELL: |
| case SENSE_TOUCH: |
| case SENSE_SOUND: |
| transparent_check = function int (object o) |
| { return o->QueryProp(P_CNT_STATUS) == CNT_STATUS_OPEN;}; |
| break; |
| // Fuer alle anderen reicht, wenn er transparent ist. |
| default: |
| transparent_check = function int (object o) |
| { return (o->QueryProp(P_TRANSPARENT) != 0); }; |
| } |
| |
| return sense; |
| } |
| |
| private object get_ref_object(string *tokens, closure transparent_check, |
| int ref_given) |
| { |
| object ref_object; |
| |
| // im Kommando speziell beschrieben ist, wo die Suche losgehen soll, spielt |
| // das Referenzobjekt keine Rolle. |
| if (sizeof(tokens) > 1 && tokens[<1] == "hier") { |
| tokens = tokens[..<2]; |
| ref_object = environment(); |
| ref_given=1; |
| } |
| else if (sizeof(tokens) > 2 && tokens[<2] == "in") |
| { |
| if (tokens[<1] == "mir" || |
| tokens[<1] == "dir") |
| { |
| tokens = tokens[..<3]; |
| ref_object = this_object(); |
| ref_given=1; |
| } |
| else if (tokens[<1] == "raum") |
| { |
| tokens = tokens[..<3]; |
| ref_object = environment(); |
| ref_given=1; |
| } |
| } |
| else |
| { |
| // ansonsten bleibt tokens unmodifiziert und wir nehmen das |
| // Referenzobjekt (so existent). |
| ref_object = QueryProp(P_REFERENCE_OBJECT); |
| if (objectp(ref_object)) |
| { |
| // Dieses muss aber "irgendwo" in unserem Umfeld sein. |
| if (ref_object == environment() || ref_object==this_object()) |
| { |
| // Umgebung oder Spieler selber sind als Bezugsobjekt immer in |
| // Ordnung, nichts machen. |
| } |
| // Wenn es nicht wir oder environment ist, darf das Referenzobjekt |
| // nicht unsichtbar sein. |
| else if (!ref_object->short()) |
| ref_object = 0; |
| // Und nur wenn das Ref-Objekt irgendwie in unserer Umgebung ist |
| // (direkt, in uns, in einem Container etc.) kommt es in Frage. Es |
| // wird daher geprueft, ob all_environments() des Ref-Objekts auch |
| // unser environment enthaelt. |
| else |
| { |
| object *all_envs=all_environment(ref_object) |
| || ref_object->AllVirtualEnvironments() |
| || ({}); |
| int i=member(all_envs, environment()); |
| if (i >= 0) |
| { |
| // dann von dem Environment an entlanglaufen und alle |
| // intermediaeren Objekt pruefen, ob sie einsehbar und sichtbar |
| // sind. |
| foreach(object env : all_envs[..i]) { |
| // Ist eine Umgebung Living oder intransparenter Container oder |
| // unsichtbar? |
| if (living(env) || !funcall(transparent_check, env) |
| || !env->short()) |
| { |
| // Kette zum Ref-Objekt unterbrochen. Wenn das unterbrechende |
| // Env nicht dieses Living selber oder sein Env ist, wird das |
| // Referenzobjekt zusaetzlich genullt. |
| if (env != this_object() && env != environment()) |
| ref_object = 0; |
| break; |
| } |
| } |
| } |
| else |
| ref_object = 0; // nicht im Raum oder Inventory |
| } |
| } // ref_object exists |
| } |
| DEBUG(PL, sprintf("%O\n",ref_object), "get_ref_object:"); |
| return ref_object; |
| } |
| |
| // Versucht ein Basisobjekt (ggf. in env) finden, was durch <tokens> |
| // beschrieben wird. |
| // Das Basisobjekt ist das, was bei einem "detail an parent" durch parent |
| // gekennzeichnet wird oder notfalls das Ref-Objekt selber. Zu beachten ist, |
| // dass find_base() ggf. rekursiv arbeitet, um sowas wie "riss an kerze in |
| // kerzenstaender auf tisch" zu finden. detail ist dann der letzte Teil der |
| // tokens (der Anfang!), was keinen Container mehr bezeichnet, das gefundene |
| // Objekt ist der letzte Container/Item auf dem Weg zu detail. |
| // detail muss als Referenz uebergeben werden. |
| // transparent_check ist die Closure, die prueft, ob man in einen |
| // Container reinforschen (sehen, lesen, riechen, tasten etc.) kann. Sie |
| // bekommt den Container uebergeben. |
| private object find_base(object env, string *tokens, string detail, |
| closure transparent_check) |
| { |
| // zuerst pruefen, ob man in env reinsehen/reinforschen kann (in |
| // this_object() und environment() kann man immer reinsehen). |
| if (env && env != this_object() && env != environment()) |
| { |
| // Nicht in Lebewesen reingucken und nicht in intransparente/geschlossene |
| // Container |
| if (living(env) || !funcall(transparent_check, env)) |
| { |
| // suche nach Objekten in env ist jetzt zuende, weil nicht in env |
| // reinsehbar. |
| // Aber tokens koennte noch ein detail beschreiben, was der Aufrufer an |
| // env findet. Also tokens nach detail und env zurueckgeben. |
| detail = implode(tokens, " "); |
| DEBUG(PL, sprintf("Env: %O, Detail: %s\n",env, detail), |
| "find_base 1"); |
| return env; |
| } |
| } |
| // ansonsten schauen, ob in tokens noch ein (weiterer) Container beschrieben |
| // wird. |
| for (int i = sizeof(tokens)-1; i > 1; i--) |
| { |
| object ob, *objs; |
| // In env oder mir oder umgebung gucken, ob ein passendes Objekt da ist. |
| // Hierfuer werden mit jedem Schleifendurchlauf von hinten mehr worte aus |
| // tokens benutzt. (Beispiel "muenze in boerse 2") |
| // present waere schneller und die Komplexitaet von present_objects waere |
| // hier nicht noetig. Allerdings beruecksichtigt es die Sichtbarkeit und |
| // ggf. virtuell anwesende Objekte, was present nicht tut. |
| string suchid=implode(tokens[i..], " "); |
| if (env) |
| objs = env->present_objects(suchid) || ({}); |
| else |
| objs = environment()->present_objects(suchid) || |
| this_object()->present_objects(suchid); |
| // wenn nicht genau ein Objekt gefunden wird, wird weitergesucht, im |
| // naechsten Durchlauf mit einem Wort mehr aus tokens |
| if (!sizeof(objs)) |
| { |
| continue; |
| } |
| // falls mehr als ein Objekt gefunden wurden: das erste nehmen, wie |
| // ueberall sonst auch. |
| ob = objs[0]; |
| |
| // an dieser Stelle wird (noch) nicht geprueft, ob man in das gefundene |
| // Objekt hineinforschen kann. |
| |
| // Wenn passende Praeposition davor (z.B. "in" (beutel), "auf" (tisch)), |
| // rekursiv weitersuchen, ob der restliche Teil von tokens evtl. nochmal |
| // nen container in dem gefundenen Objekt bezeichnet. |
| if (tokens[i-1] == ob->QueryProp(P_PREPOSITION)) |
| return find_base(ob, tokens[..i-2], &detail, transparent_check); |
| |
| // Wenn tokens[i-1] "an" oder "am" ist, wird zwar nicht weiter verzweigt, |
| // aber vermutlich wird ein Detail an diesem Objekt gesucht, d.h. das |
| // Objekt wird env, tokens entsprechend gekuerzt und die Schleife beendet. |
| // Bemerkung: haette ob tatsaechlich eine Praeposition an|am gehabt, |
| // waeren wir vorher in find_base() verzweigt zum Suchen in dem Container. |
| if (tokens[i-1] == "an" || tokens[i-1] == "am") { |
| env = ob; |
| tokens=tokens[..i-2]; |
| break; |
| } |
| } |
| // an diesem Punkt sind in tokens nur noch worte drin, die keinen Container |
| // mehr beschreiben. Die Resttokens kommen nach <detail>, sie beschreiben |
| // dann entweder ein Objekt oder ein Detail. |
| detail = implode(tokens, " "); |
| |
| // Wenn es ein env gibt, beschreibt detail nun ein Objekt in env oder ein |
| // Detail an env, was der Aufrufer prueft. |
| // Wenn es aber kein env gibt (das passiert, wenn der Aufrufer dieser |
| // Funktion schon kein env (->Referenzobjekt) hereingegeben hat, wurde auch |
| // kein Container gefunden, der durch die tokens beschrieben wurde. Dann |
| // kann der Aufrufer noch an/in this_object() oder environment() gucken, ob |
| // was zu finden ist. |
| DEBUG(PL, sprintf("Env: %O, Detail: %s\n",env, detail), |
| "find_base 2:"); |
| return env; |
| } |
| |
| private nosave int exa_cnt; |
| private nosave int exa_time; |
| private nosave string *exa; |
| private void unt_script_dings(string str) |
| { |
| // unt-script-sucher |
| if (!sizeof(str)) return; |
| if (member(({"boden","decke","wand","waende"}),old_explode(str," ")[0]) == -1) { |
| exa_cnt -= (time() - exa_time)/2; |
| exa_time = time(); |
| exa_cnt++; |
| if (!exa) |
| exa = ({ str }); |
| else |
| exa += ({ str }); |
| if (exa_cnt > 10) { |
| log_file("ARCH/LOOK", |
| sprintf("%s: %s in %s\n%@O\n",dtime(time()),getuid(this_object()), |
| environment() ? object_name(environment()) : "???",exa), 150000); |
| exa_cnt = 0; |
| exa = ({}); |
| } |
| else if (exa_cnt < 0) { |
| exa_cnt = 0; |
| exa = ({}); |
| } |
| } |
| } |
| |
| private string nf_meldung(string detail, int sense) |
| { |
| switch(sense) |
| { |
| case SENSE_SMELL: |
| return "Du riechst nichts Besonderes.\n"; |
| case SENSE_SOUND: |
| return "Du hoerst nichts Besonderes.\n"; |
| case SENSE_TOUCH: |
| return "Du fuehlst nichts Besonderes.\n"; |
| // case SENSE_READ: |
| // default: |
| // return "siehst"; |
| } |
| return sprintf("\'%s\' siehst Du da nicht!\n",capitalize(detail)); |
| } |
| |
| private int _examine_rec(object *ref_objects, string *tokens, closure |
| transparent_check, int sense, int mode, |
| int ref_given) |
| { |
| // ref_objects sind alle in Frage kommenden Kandidaten, an denen wir suchen. |
| DEBUG(PL, sprintf("Refobjekt-Kandidaten: %O\n",ref_objects), |
| "_examine_rec 1:"); |
| |
| // Sodann ein Basisobjekt finden. Das Basisobjekt ist das, was bei einem |
| // "detail an parent" durch parent gekennzeichnet wird oder notfalls das |
| // Ref-Objekt von oben. Zu beachten ist, dass find_base() ggf. rekursiv |
| // arbeitet, um sowas wie "riss an kerze in kerzenstaender auf tisch" zu |
| // finden. detail ist dann das letzte Teil der tokens, der keinen Container |
| // mehr bezeichnet, das gefundene Objekt ist der letzte Container/Item auf |
| // dem Weg zu detail. (detail==riss, base==kerze) |
| string detail; // detail an parent |
| // das fuer parent gefundene objekt |
| object base = find_base(ref_objects[0], tokens, &detail, transparent_check); |
| // BTW: find_base liefert immer was zurueck - wenn nix gefunden wird, das |
| // ref_object, was als Start der Suche uebergeben wurde. |
| // Jetzt wird versucht, ein Objekt mit der ID "detail" in base oder |
| // ein Detail an base zu finden. |
| |
| object *objs; |
| // Wenn wir in base reingucken koennen, ermitteln wir alle zu |
| // detail in Frage kommenanden Objekte in seinem Inventar |
| if (base == this_object() || base == environment() || |
| (funcall(transparent_check, base) && !living(base))) |
| { |
| objs = base->locate_objects(detail, 1) || ({}); |
| } |
| else |
| { |
| // Basisobjekt da, aber nicht reinguckbar, also keine Objekte |
| // gefunden. base aber nicht nullen, denn es ist ja noch gueltig fuer |
| // Detailsuchen an base... |
| objs = ({}); |
| } |
| // Und in jedem Fall werden alle Objekt raussortiert, die unsichtbar sind. |
| // ;-) |
| objs = filter_objects(objs, "short"); // nur sichtbare... |
| |
| // Wenn es sichtbare gibt, werden die ggf. angeguckt. |
| if (sizeof(objs)) |
| { |
| // Objekte gefunden, mal schauen, ob die taugen (d.h. fuer den jew. Sinn |
| // Infos haben. Wenn nicht, muessen wir weitersuchen. |
| // Aber erstmal die Objekte durchlaufen. |
| foreach(object ob: objs) |
| { |
| string out; |
| if (sense == SENSE_VIEW) |
| { |
| out = ob->long(mode); |
| } |
| else if (sense == SENSE_READ) |
| { |
| // Extrawurst: P_READ_MSG auch noch abfragen. |
| out = ob->QueryProp(P_READ_MSG); |
| if (!stringp(out)) |
| out = ob->GetDetail(SENSE_DEFAULT,QueryProp(P_REAL_RACE),SENSE_READ); |
| } |
| else |
| out=ob->GetDetail(SENSE_DEFAULT,QueryProp(P_REAL_RACE),sense); |
| // Wenn was gefunden wurde, sind wir fertig. |
| if (stringp(out)) |
| { |
| SetProp(P_REFERENCE_OBJECT, ob); |
| tell_object(ME, out); |
| return 1; |
| } |
| } |
| } |
| // keine Objekte gefunden oder die hatten nix fuer unseren Sinn |
| // dabei. Also nach ordinaeren Details an base/parent suchen. |
| string out = base->GetDetail(detail, QueryProp(P_REAL_RACE), sense); |
| // Achja, Tueren gibt es ja auch noch. :-o (TODO: die solten vItems werden) |
| if (!out && sense==SENSE_VIEW) |
| out = base->GetDoorDesc(detail); |
| if (out) |
| { |
| // Detail gefunden, base darf neues Referenzobjekt werden und nach |
| // Ausgabe sind wir fertig. |
| SetProp(P_REFERENCE_OBJECT, base); |
| write(out); |
| return 1; |
| } |
| else |
| { |
| // wenn auch keine Details gefunden, dann schauen, unser Env evtl. |
| // noch nen passendes Detail oder Objekt hat. Das ist aber natuerlich |
| // nur der Fall, wenn ref_object nicht eh schon das Environment war. |
| // Ausserdem nicht machen, wenn der Nutzer ein spezifisches Referenzobjekt |
| // angegeben hat (z.B. "in raum"). |
| if (sizeof(ref_objects) > 1) |
| { |
| // Wir schauen uns ggf. weitere Kandidaten an. Bei den anderen |
| // Sinnen kein neues notify_fail, weil sonst staendig Meldungen kommen, |
| // dass x nicht da ist, nur weil es keine Beschreibung fuer den Sinn hat. |
| if (sense==SENSE_VIEW || sense==SENSE_READ) |
| { |
| // Ausgabe, was gerade angeguckt hat. |
| if (ref_objects[0] == environment()) |
| out="Sowas siehst Du hier nicht. "; |
| else if (ref_objects[0] == this_object()) |
| out="Sowas siehst Du an Dir nicht. "; |
| else |
| out="Sowas siehst Du an/in "+ref_objects[0]->name(WEM) +" nicht. "; |
| // Ausgabe, was man als naechstes anguckt. |
| if (ref_objects[1] == environment()) |
| out+="Du schaust Dich um."; |
| else |
| out+="Du schaust Dich an."; |
| |
| write(break_string(out,78)); |
| } |
| return _examine_rec(ref_objects[1..], tokens, transparent_check, |
| sense, mode, 0); |
| } |
| // Leider ist nix mehr uebrig zum angucken und in jedem Fall Ende. |
| else |
| { |
| // Wenn spezifisches ref_object vom Nutzer angegeben (ref_given!=0), |
| // gibt es eine leicht andere Meldung und das Bezugsobjekt muss weg. |
| if (ref_given) { |
| SetProp(P_REFERENCE_OBJECT, 0); |
| notify_fail(break_string(nf_meldung(detail, sense),78)); |
| } |
| // Ansonsten gibt es nur nen passendes notify_fail und Ende. |
| else if (sense==SENSE_VIEW) { |
| notify_fail(break_string("\'" + capitalize(detail) + "\'" |
| + " siehst Du auch da nicht!\n"),78); |
| } |
| else { |
| notify_fail(break_string(nf_meldung(detail, sense),78)); |
| } |
| return 0; |
| } |
| } |
| // Nie erreicht. |
| return 0; |
| } |
| |
| varargs int _examine(string str, int mode) |
| { |
| // Sinn auswaehlen, der benutzt wird. Wenn -1, abbrechen (kein Sinn bzw. |
| // Sinn erlaubt ggf. kein leeren <str> fuer Defaulmeldung). Je nach Sinn |
| // wird auch <str> modifiziert. |
| // transparent_check enthaelt spaeter die Closure, die entscheidet, |
| // ob man mit dem Sinn in einen Container reinforschen kann. |
| closure transparent_check; |
| int sense=select_sense(&str, &transparent_check); |
| if (sense<0) return 0; |
| |
| unt_script_dings(str); |
| |
| // Wenn kein str, dann SENSE_DEFAULT vom Environment ausgeben. Bei |
| // SENSE_VIEW wird das bereits bei den Aufrufern dieser Funktion gemacht und |
| // die Beschreibung der Umgebung ausgegeben. |
| if (sense!=SENSE_VIEW) |
| { |
| if (!str) |
| { |
| string detail = environment()->GetDetail(SENSE_DEFAULT, |
| QueryProp(P_REAL_RACE),sense); |
| if(!detail) |
| return 0; |
| write(detail); |
| return 1; |
| } |
| } |
| |
| string *tokens = explode(str, " "); |
| int ref_given; |
| // Das Ref-Objekt finden, das kann dann auch in tokens angegeben sein. In dem |
| // Fall wird die Liste an tokens um die Angabe des Ref-Objekts gekuerzt und |
| // ref_given gesetzt. |
| object ref_ob = get_ref_object(&tokens, transparent_check, &ref_given); |
| // Bemerkung: Das Referenzobjekt ist garantiert sichtbar, aber nicht |
| // unbedingt einsehbar. Wird weiter unten geprueft. |
| |
| // Falls nicht explizit ein Objekt als Ref-Objekt angegeben wurde, werden |
| // max. 3 Objekte angeguckt: das eigentliche Referenzobjekt, das |
| // Environment und das eigene Objekt. Da ref_object auch eines der letzten |
| // beiden sein kann, muss die Dublette ggf. raus. |
| object *ref_objects; |
| if (ref_ob) |
| { |
| ref_objects=({ref_ob}); |
| if (!ref_given) |
| ref_objects += ({environment(), this_object()}) - ref_objects; |
| |
| } |
| else |
| ref_objects = ({environment(), this_object()}); |
| |
| return _examine_rec(ref_objects, tokens, transparent_check, sense, mode, |
| ref_given); |
| } |
| |
| // Funktion fuer "schau in ..." |
| varargs int look_into(string str,int mode) |
| { |
| object *found_obs; |
| |
| if( CannotSee() ) return 1; |
| _notify_fail("Wo willst Du denn reinschauen?\n"); |
| found_obs=find_objects(str, 0, 0); |
| if (!sizeof(found_obs)) |
| { |
| if (environment() && |
| (environment()->GetDetail(str,QueryProp(P_REAL_RACE))|| |
| environment()->GetDoorDesc(str))) |
| _notify_fail("Da kannst Du so nicht reinsehen.\n"); |
| return 0; |
| } |
| |
| return _examine(str, mode); |
| } |
| |
| /* Gebe die Umgebung des aktiven Spielers zurueck, lasse dabei */ |
| /* rekursiv geschachtelte Raeume zu. */ |
| /* Wenn allow_short 0 ist, so wird immer die long-descr benutzt */ |
| varargs string env_descr(int allow_short,int flags, int force_short ) |
| { |
| object env; |
| int brief; |
| |
| env = environment(ME); |
| |
| if(!env) |
| return "Du schwebst im Nichts ... Du siehst nichts, rein gar nichts ...\n"; |
| |
| if (!force_short && (!allow_short || !QueryProp(P_BRIEF))) |
| return env->int_long(ME,ME,flags); |
| |
| if (!flags && ((brief=QueryProp(P_BRIEF))>=2)) |
| return ""; |
| |
| return env->int_short(ME,ME); |
| } |
| |
| // Kommandofunktion fuer schau. |
| // Verzweigt ggf. in _examine() fuers normale Untersuchen. |
| int _look(string str) |
| { |
| string s; |
| int flag; |
| |
| if(CannotSee()) return 1; |
| |
| // nur schau mit ggf. Flags entsorgt das Ref-Objekt und schaut die |
| // Raumbeschreibung an. |
| if(!str) |
| { |
| SetProp(P_REFERENCE_OBJECT, 0); |
| write( env_descr() ); |
| return 1; |
| } |
| if(str=="-f" || str=="genau") |
| { |
| SetProp(P_REFERENCE_OBJECT, 0); |
| write( env_descr(0,2) ); |
| return 1; |
| } |
| if(str=="-k" || str=="kurz") |
| { |
| SetProp(P_REFERENCE_OBJECT, 0); |
| write( env_descr(1,2,1) ); |
| return 1; |
| } |
| // Ansonsten wird in _examine() weitergemacht, wobei Flags vorher |
| // rausgeschnitten werden. _examine() benutzt die Flags, falls es eine |
| // Langbeschreibung eines Objektes ausgeben wird. |
| if(str[0..2]=="-f "){ |
| flag=2; |
| str=str[3..]; |
| } |
| else if(str[0..5]=="genau "){ |
| flag=2; |
| str=str[6..]; |
| } |
| else flag = 0; |
| |
| if (sscanf(str,"%s an",s)) str=s; |
| // "in mir", "in dir" soll in _examine rein, aber "in ..." in look_into(). |
| if (sscanf(str,"%s in mir",s)||sscanf(str,"%s in dir",s)) return _examine(str,flag); |
| if (sscanf(str,"in %s",s)) return look_into(s,flag); |
| // Alles andere weiter an _examine(). |
| return _examine(str,flag); |
| } |
| |
| int _equipment(string arg) |
| { |
| if (CannotSee()) return 1; |
| call_other("/std/player/invmaster/invmaster", "ShowInv", ME, arg); |
| return 1; |
| } |
| |
| static mixed _query_localcmds() |
| { |
| return |
| ({({"ausruestung", "_equipment",0,0}), |
| ({"i","_inventory",0,0}), |
| ({"inv","_inventory",0,0}), |
| ({"inventur","_inventory",0,0}), |
| ({"schau","_look",0,0}), |
| ({"schaue","_look",0,0}), |
| ({"unt","_examine",0,0}), |
| ({"untersuch","_examine",0,0}), |
| ({"betracht","_examine",0,0}), |
| ({"untersuche","_examine",0,0}), |
| ({"betrachte","_examine",0,0}), |
| ({"betr","_examine",0,0}), |
| ({"lausche","_examine",0,0}), |
| ({"lausch","_examine",0,0}), |
| ({"hoer","_examine",0,0}), |
| ({"hoere","_examine",0,0}), |
| ({"lies","_examine",0,0}), |
| ({"lese","_examine",0,0}), |
| ({"les","_examine",0,0}), |
| ({"schnupper","_examine",0,0}), |
| ({"schnuppere","_examine",0,0}), |
| ({"riech","_examine",0,0}), |
| ({"rieche","_examine",0,0}), |
| ({"taste","_examine",0,0}), |
| ({"beruehre","_examine",0,0}), |
| ({"beruehr","_examine",0,0}), |
| ({"kurz","_toggle_brief",0,0}), |
| ({"lang","_toggle_brief",0,0}), |
| ({"ultrakurz","_toggle_brief",0,0}) |
| }); |
| } |