ARDNEH
public cpp v1 · immutable/********************************************************************//* File: /global/commands/look.c *//* Code: ??? *//* Date: ?? ??? ???? *//* Func: global 'look' command *//* ----- *//* Rev.: Alfe *//* Date: *//* 22 Apr 2004 - values and descriptions for *//* describe_health() taken from ereborn's *//* monster spectacles. and changed a little *//* bit *//* 26 Oct 2001 - added checks to look_at_room() for argument *//* types *//* 17 Oct 2001 - added #include <skilltree.h> *//* 05 Oct 2001 - added #include <alignment.h> *//* 10 Jul 2001 - turn added to get_map() in look_at_room() *//* 24 Apr 1998 - E_MESSAGES added to "show" case in *//* do_action() */// - added E_MESSAGES to "look" send_event in *//* "est_" cases in do_action() */// - added E_MESSAGES to "look" send_event in *//* "cmp_" cases in do_action() *//* 18 Mar 1996 - added brief mode to look_at_room *//* 21 Feb 1996 - added #'capitalize and CL_L_RANGE-part to *//* message-returns as extra_looks in *//* look_at_thing *//* ----- *//* Rev.: ARDNEH *//* Date: *//* 04 Jul 2006 - formatting, added function headers *//* - added #pragma strong_types *//* - describe_armour() changed "armed" to *//* "armoured" ("armed" usu. means "has weapon") *//* 28 Jul 2006 - tweaked describe_light() *//* - tweaked describe_weight() *//* ----- *//* Rev.: Carador *//* Date: *//* 05 Aug 1997 - who added to get_map() in look_at_room() *//* 24 Jul 1997 - some clean up and modifies in if(!brief) *//* section of look_at_room() *//* ?? Jul 1996 - added last referenced check to *//* look_at_thing() for /bin/standard *//* ?? May 1996 - added item surface contents to *//* look_at_thing() *//* ?? Dec 1995 - changed a set of result in look_at_object() *//* to allow objects to return messages as *//* extra_looks *//* ----- *//* Rev.: Chameloid *//* Date: *//* 01 Nov 1997 - added 'from_long' to look_at_room() to not *//* add exits twice *//* ----- *//* Rev.: Coogan *//* Date: *//* 20 May 2004 - added fourth arg and varargs to *//* look_at_thing() *//* - added assert(who) and assert(obj) to *//* look_at_thing() *//* - added #include <assert.h> *//* 15 Apr 2003 - added "look_into" case to do_action() *//* 07 Nov 2002 - added "glimpse" to do_action() *//* 06 Nov 2002 - added to look_at_room() check for *//* this_player()->query_show_long_delayed() *//* 02 Nov 2002 - added extra brief (==2) to look_at_room() *//* 10 Sep 2002 - added map to look_at_room() *//* 09 Sep 2002 - added USE_COMBINE_COLOURS to look_at_room() *//* 16 May 2002 - added check for colours in look_at_room() *//* 10 May 2002 - added check for colours in look_at_room() *//* 16 Oct 2001 - added inherit "basic/coloured_string"; *//* 09 Oct 2001 - est_weight check added to do_action() *//* 19 Jun 2001 - added check for sizeof(ob) to case 1 in *//* 14 Jan 2001 - rewrote make_inventory_output() to break *//* too-long lines *//* 03 Jul 1999 - added short filter in various places *//* 28 Apr 1999 - added #include <money.h> *//* - added hide autoloads checks *//* 14 Apr 1999 - added #include <light.h> *//* - added cases INVENTORY_COMPLETELY_FACTORIZED *//* and INVENTORY_ONLY_IN_CONTAINER_FACTORIZED *//* - added test_can_see() */// - added factorize_object(), preserve_order() *//* 05 Jul 1998 - M_THE after " to " added to "show" case in *//* do_action() *//* 30 Nov 1997 - look_at_room(), if(!brief) - 'who' is the *//* person to exclude from the showed inventory *//* of the room, so better use this_player() if *//* it exists. *//* - added a string type check to verbose mode *//* 31 Aug 1997 - result check added to brief mode in *//* look_at_room(), 31-Aug-97 *//* ----- *//* Rev.: Ugh *//* Date: *//* 11 Aug 1997 - added check in look_at_room() for rooms *//* whose room-long is the empty string *//********************************************************************/#pragma strong_types#include <alignment.h>#include <assert.h>#include <closures.h>#include <describe.h>#include <event.h>#include <grammar.h>#include <is_wizard.h>#include <light.h>#include <message.h>#include <money.h>#include <prop/room.h>#include <prop/item.h>#include <prop/player.h>#include <skilltree.h>#define MAX_ITEMS 40#define INVENTORY_COMPLETELY_FACTORIZED// #define INVENTORY_ONLY_IN_CONTAINER_FACTORIZED// #define INVENTORY_TRADITIONALinherit "basic/coloured_string";inherit "basic/create";inherit "basic/math";inherit "basic/time";//------------------------------------------------------------------//// Name: create //// Func: creation of command, activate watching for verb "look" //// Args: none //// Rtrn: nothing ////------------------------------------------------------------------//void create(){ listen_event( "look" ); set_global_listening_event( "look", 1 );}//------------------------------------------------------------------//// Name: test_can_see //// Func: check for ability of player to see their environment //// Args: object who, object room //// Rtrn: string ("too bright"/"too dark") ////------------------------------------------------------------------//string test_can_see( object who, object room ){ if( who? who->test_darkness( room, 1 ) : query_light( room ) < LIGHT_DARKNESS_THRESHOLD ){ return room->query_darkness() || "It is too dark to see.\n"; } if( who? who->test_brightness( room, 1 ) : query_light( room ) > LIGHT_BRIGHTNESS_THRESHOLD ){ return room->query_brightness() || "It is too bright to see.\n"; }}//------------------------------------------------------------------//// Name: look_at_room //// Func: get the description of player's environment //// Args: mixed room, int brief, status combined, object who, //// int turn, status as_view //// Rtrn: string result ////------------------------------------------------------------------//varargs string look_at_room( mixed room, int brief, status combined, object who, int turn, status as_view){ mixed *inv, h, hh; int w, i, shift, shift2, li, ri, j; string result, past_long, *wrapped_result, verbatim_result; mixed tmp; status swapper, from_long = 0; //--------------------------------------------------------------// // argument error-checking if( !objectp( room ) ){ if( !stringp( room ) ){ raise_error( "Argument 1 to look_at_room() neither " "object nor string.\n" ); } else{ room = load_object( room ); } } if( who && !objectp( who ) ){ raise_error( "Argument 4 to look_at_room() not object.\n" ); } //--------------------------------------------------------------// // check if room is visible if( result = test_can_see( who, room ) ){ return result; } //--------------------------------------------------------------// // view mode setting if( as_view ){ brief = 1; } //--------------------------------------------------------------// // brief mode 2 if( brief == 2 ){ //----------------------------------------------------------// // get the room's description and exits tmp = room->query_property( P_LOCAL_PREPOSITION ); result = ( describe( room, 0, DESCRIBE_FULL + DESCRIBE_WITH_STATE ) || "somewhere" ); result = tmp ? tmp + " " + result : result; tmp = room->query_exit_long( 1 ); result = ( capitalize( result ) + ( tmp == "" ? "" : ". " + ( tmp || "No obvious exits" ) ) + ".\n" ); //----------------------------------------------------------// // remove viewer from room's inventory list inv = filter( all_inventory( room ), #'living ) - ({ who }); //----------------------------------------------------------// // set inv to description of itself inv = describe_list( inv, ARTICLE_A, DESCRIBE_FULL + DESCRIBE_WITH_STATE ); //----------------------------------------------------------// // append room's visible inventory, then return the result if( sizeof( inv ) ){ result += implode( map( inv[0..MAX_ITEMS], #'capitalize_coloured ), ".\n" ) + ".\n"; if( sizeof( inv ) > MAX_ITEMS ){ result += "*** TRUNCATED ***\n"; } } return result; } //--------------------------------------------------------------// // if the player's view has been delayed, remove the delay if( this_player()->query_show_long_delayed() ){ this_player()->stop_show_long_delayed(); } //--------------------------------------------------------------// // verbose mode if( !brief ){ //----------------------------------------------------------// // get the width at which to wrap the description w = this_player() && this_player()->query_property( P_DISPLAY_WIDTH ) || 79; //----------------------------------------------------------// // long + extralong without exits, exits added later result = room->query_room_long( as_view ); //----------------------------------------------------------// // check for validity of result, do nothing if not string // (this room must be very old; do nothing, rooms with write // in long have written their desc already) if( !stringp( result ) ){ from_long = 1; result = room->long(); } //----------------------------------------------------------// // a rather modern room with query_room_long() else{ if( !strlen( result ) ){ if( room->long() ){ from_long = 1; } result = room->long() || result; } //------------------------------------------------------// // add mini-map beside the long description if( stringp( result ) && this_player() && this_player()->query_property( P_LITTLEMAP ) && !room->query_property( P_NO_MAP ) ){ result = LIB_NEARBY->unbreak_long_string( result ); past_long = ""; if( !as_view && ( tmp = room->query_view() ) && sizeof( tmp ) ){ past_long += ( "You have this view: " + make_list( m_indices( tmp ) ) + ".\n" ); } //--------------------------------------------------// // add the exits here if( !from_long ){ past_long += room->query_exit_long(); }#define USE_COMBINE_COLUMNS#ifdef USE_COMBINE_COLUMNS hh = LIB_NEARBY->get_map( room, who, turn ); while( hh[0] == " " ){ hh = hh[1..]; } while( hh[<1] == " " ){ hh = hh[0..<2]; } hh = map( hh, (: $1 + " " :) ); result = LIB_STRINGS->combine_columns( hh, result + past_long, w, 0 );#else# if 1 //--------------------------------------------------// // remove colour tokens from result if it has them, // and wrap result to fit the map if( strlen_visible( result ) != strlen( result ) ){ h = wrap_coloured_line( result, w-1, 10 ); } else{ h = explode( break_string( result, w-1, 10 ), "\n" ) - ({ "" }); }# else //--------------------------------------------------// // just wrap result to fit the map h = explode( break_string( result, w-1, 10 ), "\n" ) - ({ "" });# endif# if 1 //--------------------------------------------------// // remove colour tokens from past_long if it has them, // and wrap past_long to fit the map if( strlen_visible( past_long ) != strlen( past_long ) ){ h += wrap_coloured_line( past_long, w-1, 10 ); } else{ h += explode( break_string( past_long, w-1, 10 ), "\n" ) - ({ "" }); }# else //--------------------------------------------------// // just wrap past_long to fit the map h += explode( break_string( past_long, w-1, 10 ), "\n" ) - ({ "" });# endif hh = LIB_NEARBY->get_map(room, who, turn); while( hh[0] == " " ){ hh = hh[1..]; } while( hh[<1] == " " ){ hh = hh[0..<2]; } if( sizeof( hh ) < sizeof( h ) ){ shift2 = ( sizeof( h ) - sizeof( hh ) ) / 2; } else{ shift = ( sizeof( hh ) - sizeof( h ) ) / 2; } sz = sizeof( hh ); for( i = sizeof( h ); i < sz; i++ ){ swapper ^= 1; if( swapper ){ h += ({ " " }); } else{ h = ({ " " }) + h; } } for( i = 0; i < sz; i++ ){ h[i+shift2][0..8] = hh[i]; } result = implode( h, "\n" ) + "\n";#endif // END COMBINE_COLUMNS SECTION } //------------------------------------------------------// // no map, add exits here else if( !from_long ){ result += room->query_exit_long(); } } } //--------------------------------------------------------------// // brief mode else{ tmp = room->query_property( P_LOCAL_PREPOSITION ); result = ( describe( room, 0, DESCRIBE_FULL + DESCRIBE_WITH_STATE ) || "somewhere" ); result = tmp? tmp + " " + result : result; } if( !( result && stringp( result ) ) ){ result = ""; } else if( brief && result != "" ){ result = capitalize_coloured( result + ".\n" ); } if( brief && !as_view && !room->query_property( P_NO_EXITS_IN_BRIEF ) && stringp( tmp = room->query_exit_long( 1 ) ) && strlen( tmp ) ){ result += tmp + ".\n"; } // do not look at oneself, if given: inv = ( room->get_inventory() || all_inventory( room ) ) - ({ who }); // combined inventory if( combined ){ inv = describe_list( inv, ARTICLE_A, DESCRIBE_FULL + DESCRIBE_WITH_STATE ); } // verbose inventory else{ inv = map( inv, #'describe, ARTICLE_A, DESCRIBE_FULL + DESCRIBE_WITH_STATE ) - ({ 0 }); } if( sizeof( inv ) ){ result += implode( map( inv[0..MAX_ITEMS], #'capitalize_coloured ), ".\n" ) + ".\n"; if( sizeof( inv ) > MAX_ITEMS ){ result += "*** TRUNCATED ***\n"; } } return result;}//------------------------------------------------------------------//// Name: look_at_environment //// Func: get description of an object's environment //// Args: object whose, status brief //// Rtrn: string description of environment ////------------------------------------------------------------------//varargs string look_at_environment( object whose, status brief ){ return look_at_room( environment( whose ), brief, whose->query_property( P_COMBINED ), whose );}//------------------------------------------------------------------//// Name: look_at_thing //// Func: get description of an object //// Args: object who, object ob, string id, int without_inv //// Rtrn: string description of object ////------------------------------------------------------------------//varargs string look_at_thing( object who, object ob, string id, int without_inv){ string result; mixed *inv; assert(who); assert(ob); //--------------------------------------------------------------// // check for visibility if( result = test_can_see( who, environment( who ) ) ){ return result; } //--------------------------------------------------------------// // bin/standard wants to know which was the last item the player // looked at to handle the look-failure properly. if( ob == environment( who ) ){ who->set_last_referenced( "item", id ); } result = ob->long(id); if( !result || !stringp( result ) ){ result = ""; } inv = ob->get_inventory( id ) || all_inventory( ob ); //--------------------------------------------------------------// // allow objects to return messages as extra_looks. result += implode( map( inv, lambda( ({ 'x, 'el }), ({ (#'?), ({ (#'pointerp), ({ (#'=), 'el, ({ (#'call_other), 'x, "extra_look" }) }) }), ({ (#'capitalize_coloured), ({ (#'message2string), ({ CL_L_RANGE, 'el, 0 }), who }) }), 'el }) ) ) + ({ "" }), ".\n" ); if( ob == environment( who ) || !sizeof( inv ) || ob->hide_inventory( id ) || ob->query_fakeitem_id( id ) || without_inv ){ return result; } if( who->query_property( P_COMBINED ) ){ inv = describe_list( inv, ARTICLE_A, DESCRIBE_FULL + DESCRIBE_WITH_STATE ); } else{ inv = ( map( inv, #'describe, ARTICLE_A, DESCRIBE_FULL + DESCRIBE_WITH_STATE ) - ({ 0 }) ); } if( !sizeof( inv ) ){ return result; } if( living( ob ) ){ result += ( " " + capitalize_coloured( message2string( ({ M_PRONOUN, ob, M_VERB, "are", ob }), who ) ) + " carrying" ); } // item surface contents else if( ob->query_property( P_SURFACE, id ) ){ result += ( " " + "On " + ( ob->query_objective() || "it" ) + " you can see" ); } else{ result += ( " " + capitalize_coloured( message2string( ({ M_PRONOUN, ob, M_VERB, "contain", ob }), who ) ) ); } if( who->query_property( P_ADD_INVENTORY ) ){ result += ":\n "; result += implode( map( inv[0..MAX_ITEMS], #'capitalize_coloured ), ".\n " ) + ".\n"; if( sizeof( inv ) > MAX_ITEMS ){ result += "*** TRUNCATED ***\n"; } } else{ result += " something.\n"; } return result;}//------------------------------------------------------------------//// Name: do_action //// Func: handle look-related action parsing...? //// Args: string action, mapping args //// Rtrn: int success/failure ////------------------------------------------------------------------//int do_action( string action, mapping args ){ mixed *inv, h; int i, size; object ob; switch( action ){ case "examine_all": args[G_INDIRECT, 1] = args[G_ALL, 1][0]; size = args[G_ALL, 1][1] || sizeof(args[G_ALL]); for( i = 0; i < size; i++ ){ args[G_INDIRECT] = args[G_ALL][i]; do_action( "examine", args ); } return 1; case "look": case "see": case "glimpse": send_event( "look", ([ E_AGENT: this_player(), E_TARGET: environment( this_player() ), E_TYPE: action ]), environment( this_player() ) ); return 1; case "look_view": send_event( "look", ([ E_AGENT: this_player(); 0, E_TARGET: load_object(args[G_VIEW, 1]); args[G_VIEW], E_TYPE: "look_view"; 0 ]), ({ environment( this_player() ), load_object( args[G_VIEW, 1] ) }) ); return 1; case "show_all": send_event( "look", ([ E_AGENT: this_player(), E_TARGET: args[G_LIVING], E_OBJECT: args[G_ALL_IN_INVENTORY], E_ID: args[G_ALL_IN_INVENTORY, 1], E_TYPE: action, E_MESSAGES: ([ 0: ({ M_THE, M_ARG, E_AGENT, M_ADVERBS, M_VERB, "show", M_ARG, E_AGENT, M_POSSESSIVE, M_ARG, E_AGENT, M_OBJECT, M_NONE, M_ARG, E_OBJECT, " to ", M_THE, M_OBJECT, M_ARG, E_TARGET, "." }) ]) ]), environment( this_player() ) ); return 1; case "show": send_event( "look", ([ E_AGENT: this_player(), E_TARGET: args[G_LIVING], E_OBJECT: args[G_IN_INVENTORY], E_ID: args[G_IN_INVENTORY, 1], E_TYPE: action, E_MESSAGES: ([ 0: ( ( args[G_IN_INVENTORY]-> query_fakeitem_id( args[G_IN_INVENTORY,1] ) ) ? ({ M_THE, M_ARG, E_AGENT, M_ADVERBS, M_VERB, "show", M_ARG, E_AGENT, M_POSSESSIVE, M_ARG, E_AGENT, " ", M_ARG, E_ID, " to ", M_THE, M_OBJECT, M_ARG, E_TARGET, "." }) : ({ M_THE, M_ARG, E_AGENT, M_ADVERBS, M_VERB, "show", M_ARG, E_AGENT, M_POSSESSIVE, M_ARG, E_AGENT, M_OBJECT, M_NONE, M_ARG, E_OBJECT, " to ", M_THE, M_OBJECT, M_ARG, E_TARGET, "." }) ) ]) ]), environment( this_player() ) ); return 1; case "examine_place": args = ([ G_INDIRECT: environment( this_player() ); 0 ]); return do_action( "examine", args ); case "examine": send_event( "look", ([ E_AGENT: this_player(), E_TARGET: args[G_INDIRECT], E_ID: args[G_INDIRECT, 1], E_TYPE: action ]), environment( this_player() ) ); return 1;// these two macros must be the same as in bin/standard!#define OBJECT2 "<object2>"#define LIVING2 "<living2>" case "est_weight": case "est_light": case "est_value": case "est_quality": case "est_strength": case "est_condition": case "est_alignment": case "est_age": case "est_load": case "est_weapon": case "est_armour": case "est_health": // we're coming from command 'weigh item' if( action == "est_weight" ){ if( !member( args, G_OBJECT ) ){ args[G_OBJECT] = args[G_ONLY_IN_INVENTORY]; } if( environment( args[G_OBJECT] ) != this_player() ){ return notify_fail( ({ ({ M_WRITE, M_PL_THE, M_PL_VERB, "don't", " have ", M_OBJECT, M_THE, args[G_OBJECT], " in ", M_PL_POSSESSIVE, " hands." }) }) ), 0; } } if( !args[G_OBJECT] && !args[G_LIVING] && !this_player()->query_attack() ){ return notify_fail( ({ ({ M_WRITE, "As you are not in a fight, please name a" " target of your estimation." }) }) ), 0; } send_event( "look", ([ E_AGENT: this_player(), E_TARGET: ( args[G_OBJECT] || args[G_LIVING] || this_player()->query_attack() ), E_ID: args[G_OBJECT, 1] || args[G_LIVING, 1], E_TYPE: action, E_MESSAGES: ([ 0: ({ M_THE, M_ARG, E_AGENT, M_VERB, "estimate", M_ARG, E_AGENT, M_OBJECT, M_THE, M_ARG, E_TARGET, M_ADVERBS, "." }) ]) ]), environment( this_player() ) ); return 1; case "cmp_weight": case "cmp_light": case "cmp_value": case "cmp_quality": case "cmp_strength": case "cmp_condition": case "cmp_alignment": case "cmp_age": case "cmp_load": case "cmp_weapon": case "cmp_armour": case "cmp_health": if( action == "cmp_weight" ){ if( environment( args[G_OBJECT]) != this_player() ){ return notify_fail( ({ ({ M_WRITE, M_PL_THE, M_PL_VERB, "don't", " have ", M_OBJECT, M_THE, args[G_OBJECT], " in ", M_PL_POSSESSIVE, " hands." }) }) ), 0; } if( environment( args[OBJECT2] ) != this_player() ){ return notify_fail( ({ ({ M_WRITE, M_PL_THE, M_PL_VERB, "don't", " have ", M_OBJECT, M_THE, args[OBJECT2], " in ", M_PL_POSSESSIVE, " hands." }) }) ), 0; } } if( !args[G_OBJECT] && !args[G_LIVING] && !this_player()->query_attack() ){ return notify_fail( ({ ({ M_WRITE, "Please name two targets of your" " estimation." }) }) ), 0; } { object *targets; targets = ({ ( args[G_OBJECT] || args[G_LIVING] || this_player()->query_attack() ), ( args[OBJECT2] || args[LIVING2] || this_player() ) }); if( targets[0] == targets[1] ){ return notify_fail( "You cannot compare something with itself.\n" ), 0; } send_event( "look", ([ E_AGENT: this_player(), E_TARGET: targets, E_ID: args[G_OBJECT, 1] || args[G_LIVING, 1], E_TYPE: action, E_MESSAGES: ([ 0: ({ M_THE, M_ARG, E_AGENT, M_VERB, "compare", M_ARG, E_AGENT, M_OBJECT, M_THE, M_ARG, E_TARGET, M_ADVERBS, "." }) ]) ]), environment( this_player() ) ); } return 1; case "look_into": if( !args[G_OBJECT] ){ return 0; } // a cheap test if it's a container if( !args[G_OBJECT]->query_container_max_encumbrance() ){ return notify_fail( "You can't look into " + describe( args[G_OBJECT], ARTICLE_THE ) + ".\n" ); } if( !args[G_OBJECT]->query_open() ){ return notify_fail( ({ ({ M_WRITE, "But ", M_THE, args[G_OBJECT], M_VERB, "be", args[G_OBJECT], " not open!" }) }) ); } send_event( "look", ([ E_AGENT : this_player(), E_TARGET: args[G_OBJECT], E_ID : args[G_OBJECT, 1], E_TYPE : action ]), environment( this_player() ) ); return 1; case "inventory": case "equipment": if( args[G_ALL] ){ h = args[G_ALL][0..args[G_ALL, 1][1]-1]; } else{ h = ({ this_player() }); } send_event( "look", ([ E_AGENT: this_player(), E_TARGET: h, E_ID : (args[G_ALL] ? args[G_ALL, 1][0] : 0), E_TYPE: action ]), environment( this_player() ) ); return 1; case "toggle_map": if( this_player()->query_property(P_LITTLEMAP) ){ this_player()->remove_property( P_LITTLEMAP ); write( "Map next to room descriptions turned off.\n" ); } else{ this_player()->set_property( P_LITTLEMAP ); write( "Map next to room descriptions turned on.\n" ); } break; case "toggle_combined": if( this_player()->query_property( P_COMBINED ) ){ this_player()->remove_property( P_COMBINED ); write( "Combined short descriptions turned off.\n" ); } else{ this_player()->set_property( P_COMBINED ); write( "Combined short descriptions turned on.\n" ); } break; case "toggle_inventory": if( this_player()->query_property( P_ADD_INVENTORY ) ){ this_player()->remove_property( P_ADD_INVENTORY ); write( "Adding of inventory turned off.\n" ); } else{ this_player()->set_property( P_ADD_INVENTORY ); write( "Adding of inventory turned on.\n" ); } break; case "toggle_hide_autoloads": if( this_player()->query_property( P_HIDE_AUTOLOADS ) ){ this_player()->remove_property( P_HIDE_AUTOLOADS ); message( "Hiding of autoloads in look at inventory " "turned off.\n" ); } else{ this_player()->set_property( P_HIDE_AUTOLOADS ); message( "Hiding of autoloads in look at inventory " "turned on.\n" ); } break; default: return 0; } return 1;}//------------------------------------------------------------------//// Name: factorize_object //// Func: this function and preserve_order() aree needed for //// INVENTORY_COMPLETELY_FACTORIZED //// Args: object o, string id //// Rtrn: string d ////------------------------------------------------------------------//private string factorize_object( object o, string id ){ string d; if( !o->short() ){ return 0; } d = describe( o, ARTICLE_A, DESCRIBE_FULL + DESCRIBE_WITH_STATE ); if( o->can_put_and_get() && !o->hide_inventory(id) && sizeof( all_inventory( o ) ) ){ d += LIB_ID->string_id(); } return d;}//------------------------------------------------------------------//// Name: preserve_order //// Func: this functions tries to preserve the shown order of items //// in the inventory after factorizing (the sum of all values //// of m should be o without invisible items). //// Args: mapping m, object array o //// Rtrn: mixed array result ////------------------------------------------------------------------//private mixed* preserve_order( mapping m, object *o ){ mixed * result; object ob; int i, sz; string *mi; result = ({ }); while( sizeof( o ) ){ if( !o[0]->short() ){ o -= ({ o[0] }); continue; } mi = m_indices(m); sz = sizeof( mi ); for( i = 0; i < sz; i++ ){ if( member(m[mi[i]], o[0]) > -1 ){ result += ({ m[mi[i]][0..] }); o -= m[mi[i]]; m -= ([ mi[i] ]); continue; } } } return result;}//------------------------------------------------------------------//// Name: make_inventory_output //// Func: construct the inventory output //// Args: string desc, int halfwidth //// Rtrn: string result ////------------------------------------------------------------------//private varargs string make_inventory_output( string desc, int halfwidth){ string *lines, *split_lines, verbatim_line, verbatim_line_start; string *wrapped_lines, result; int i, j, li, ri, sz; result = ""; lines = explode(desc, "\n") - ({ "" }); i = 0; if( !halfwidth ){ halfwidth = this_player()->query_property( P_DISPLAY_WIDTH ) / 2 - 1; } while( i < sizeof( lines ) ){ if( strlen( ( verbatim_line = to_verbatim( lines[i] ) ) ) > halfwidth ){ // we have to wrap this line // verbatim() usage by Coogan, 16-Oct-01 // rewritten by Coogan, 16-Oct-01 // improvements and fixes by Alfe, 17-Oct-01 // improvements and fixes by Coogan, 18-Oct-01 li = 0; ri = 0;#if 1 // Coogan, 18-Oct-01 if( verbatim_line[0..4] == " -> " ){ verbatim_line_start = verbatim_line[0..4]; wrapped_lines = explode( break_string( verbatim_line[5..], halfwidth - 5 ), "\n" ); } else{ verbatim_line_start = verbatim_line[0..1]; wrapped_lines = explode( break_string( verbatim_line[2..], halfwidth - 2 ), "\n" ); } wrapped_lines[0] = verbatim_line_start + wrapped_lines[0];#else wrapped_lines = explode( break_string( verbatim_line, halfwidth ), "\n" );#endif split_lines = ({ }); sz = sizeof( wrapped_lines ); for( j = 0; j < sz; j++ ){ li = strstr( verbatim_line, wrapped_lines[j], li ); ri = li + strlen( wrapped_lines[j] ); if( li > 0 ){ if( verbatim_line_start == " -> " ){ split_lines += ({ " " + subcoloured_string( lines[i], li, ri ) }); } else{ split_lines += ({ " " + subcoloured_string( lines[i], li, ri ) }); } } else{ split_lines += ({ subcoloured_string( lines[i], li, ri ) }); } } lines[i..i] = split_lines; // skip the inserted lines i += sizeof(split_lines) - 1; } i++; } if( sizeof( lines ) % 2 ){ lines += ({ "" }); } j = sizeof( lines ) / 2; // take care of different strlen() vs. strlen_visible(), // Coogan, 16-Oct-01 for( i = 0; i < j; i++ ){ result += sprintf( "%-" + ( halfwidth + strlen( lines[i] ) - strlen_visible( lines[i] ) + 1 ) + "s%-" + ( halfwidth + strlen( lines[i+j] ) - strlen_visible( lines[i+j] ) ) + "s\n", lines[i], lines[i+j] ); } return result;}//------------------------------------------------------------------//// Name: look_at_equipment //// Func: get list of equipment //// Args: mixed ob, string id //// Rtrn: string list of equipment ////------------------------------------------------------------------//string look_at_equipment( mixed ob, string id ){ if( pointerp( ob ) ){ return implode( map( ob, #'look_at_equipment, id ), "\n" ); } if( ob->hide_inventory( id ) ){ return "The equipment is completely hidden.\n"; } return LIB_EQUIPMENT->describe_equipment( ob );}//------------------------------------------------------------------//varargs string look_at_inventory(mixed ob, string id, int depth){ // depth argument added for INVENTORY_COMPLETELY_FACTORIZED // due to recursive behaviour, Coogan, 14-Apr-99 // added varargs modifier Alfe 2001-Oct-16 int i, j, sz, k, width; string description, s, desc, *si, *t, *s2; mixed h; object *inv, *n0, *n1, *n2, en; mapping m0, m1, m2; closure cl; //--------------------------------------------------------------// // check for inability to see due to darkness/brightness if( description = test_can_see( this_player(), environment( this_player() ) ) ){ return description; } description = ""; if( objectp( ob ) ){ ob = ({ ob }); } width = this_player()->query_property(P_DISPLAY_WIDTH) / 2 - 1;#ifdef INVENTORY_TRADITIONAL for( j = sizeof( ob ); j; j-- ){ h = 0; if( ob[<j]->query_auto_load() && !ob[<j]->query_property(P_COINS) && this_player()->query_property(P_HIDE_AUTOLOADS) ){ continue; } if( ob[<j] != this_player() && ob[<j]->hide_inventory(id) ){ continue; } h = ob[<j]->get_inventory(id) || all_inventory(ob[<j]); h = filter_objects( h, "short" ); if( this_player()->query_property( P_HIDE_AUTOLOADS ) ){ en = present_property( P_COINS, ob[<j] ); h -= filter_objects( h, "query_auto_load" ); if( en ){ h += ({ en }); } } // Ugh Jul-17-1996 if( this_player()->query_property( P_COMBINED ) ){ h = describe_list( h, ARTICLE_A, DESCRIBE_FULL + DESCRIBE_WITH_STATE + DESCRIBE_WITH_INVENTORY ); } else{ h = map( h, #'describe, ARTICLE_A, DESCRIBE_FULL + DESCRIBE_WITH_STATE ) - ({ 0 }); } for( i = sizeof( h ); i-->0; ){ h[i] = capitalize_coloured( h[i] + ".\n" ); } h = sizeof( h ) && sprintf( "%-78#s\n", implode( h, "" ) ); if( h && sizeof( ob ) > 1 ){ description += "\n"; s = describe( ob[<j], ARTICLE_THE, DESCRIBE_SHORT, -1 ); if( s ){ description += capitalize_coloured( s ) + ":\n"; } description += h; } else if( h ){ description += h; } else if( sizeof( ob ) < 2 ){ description += "Nothing.\n"; } } return description;#endif#ifdef INVENTORY_COMPLETELY_FACTORIZED switch( depth ){ case 2: desc = ""; ob = filter_objects( ob, "short" ); if( this_player()->query_property( P_COMBINED ) ){ m2 = factorize( ob, #'describe, ({ ARTICLE_A, DESCRIBE_FULL + DESCRIBE_WITH_STATE }) ); s2 = m_indices( m2 ); sz = sizeof( s2 ); for( k = 0; k < sz; k++ ){ desc += " -> " + describe( m2[s2[k]][0], ARTICLE_A, DESCRIBE_FULL + DESCRIBE_WITH_STATE, sizeof( m2[s2[k]] ) ) + "\n"; } } else{ sz = sizeof( ob ); for( k = 0; k < sz; k++ ){ desc+=" -> " + describe( ob[k], ARTICLE_A, DESCRIBE_FULL+DESCRIBE_WITH_STATE ) + "\n"; } } return desc; case 1: desc = ""; if( !sizeof( ob ) || !ob[0]->short() ){ return desc; } if( this_player()->query_property( P_COMBINED ) ){ desc += "- " + describe( ob[0], ARTICLE_A, DESCRIBE_FULL + DESCRIBE_WITH_STATE, sizeof( ob ) ) + "\n"; // open containers with contents are given // separately, if P_COMBINED if( ob[0]->can_put_and_get() && !ob[0]->hide_inventory(id) && first_inventory(ob[0]) && find_living_environment(ob[0]) == this_player() ){ desc += look_at_inventory( all_inventory( ob[j] ), id, 2 ); } }else{ sz = sizeof( ob ); for( j = 0; j < sz; j++ ){ desc += "- " + describe( ob[j], ARTICLE_A, DESCRIBE_FULL + DESCRIBE_WITH_STATE ) + "\n"; if( ob[j]->can_put_and_get() && !ob[j]->hide_inventory(id) && first_inventory(ob[j]) && find_living_environment(ob[j])==this_player() ){ desc += look_at_inventory( all_inventory( ob[j] ), id, 2 ); } } } return desc; case 0: ob -= filter_objects( ob, "hide_inventory", id ); if( !sizeof( ob ) ){ return "The complete inventory is hidden.\n"; } if( this_player()->query_property( P_COMBINED ) ){ inv = all_inventory( ob[0] ); inv = filter_objects( inv, "short" ); if( this_player()->query_property(P_HIDE_AUTOLOADS) ){ en = present_property( P_COINS,ob[0] ); inv -= filter_objects( inv, "query_auto_load" ); if( en ){ inv += ({ en }); } } m0 = factorize( inv, #'factorize_object, ({ id }) ); m0 -= ([0]); n0 = preserve_order( m0, inv ); sz = sizeof( n0 ); for( i = 0; i < sz; i++ ){ description += look_at_inventory( n0[i], id, 1 ); } }else{ sz = sizeof( ob ); for( i = 0; i < sz; i++ ){ inv = all_inventory( ob[i] ); inv = filter_objects( inv, "short" ); if( this_player()->query_property( P_HIDE_AUTOLOADS ) ){ en = present_property( P_COINS, ob[i] ); inv -= filter_objects(inv,"query_auto_load"); if( en ){ inv += ({ en }); } } description += look_at_inventory( inv, id, 1 ); } } if( description == "" ){ description = "Nothing.\n"; } break; default: return ""; } return make_inventory_output( description, width );#endif#ifdef INVENTORY_ONLY_IN_CONTAINER_FACTORIZED desc = ""; cl = lambda( ({ 'x }), ({ #'call_other, 'x, "short" }) ); ob -= filter_objects( ob, "hide_inventory", id ); ob = filter_objects( ob, "short" ); if( !sizeof( ob ) ){ return "The complete inventory is hidden.\n"; } sz = sizeof( ob ); for( k = 0; k < sz; k++ ){ if( this_player()->query_property( P_HIDE_AUTOLOADS ) && ob[k]->query_auto_load() && !ob[k]->query_property( P_COINS ) ){ continue; } inv = all_inventory(ob[k]); sz = sizeof( inv ); for( i = 0; i < sz; i++ ){ if( !inv[i]->short() ){ continue; } if( this_player()->query_property( P_HIDE_AUTOLOADS ) && // ^^^ Coogan, 28-Apr-99 inv[i]->query_auto_load() && !inv[i]->query_property(P_COINS) ){ continue; } desc += ( "- " + describe(inv[i], ARTICLE_A, DESCRIBE_FULL + DESCRIBE_WITH_STATE) + "\n" ); if( living(ob[k]) && this_player() != ob[k] || inv[i]->hide_inventory( id ) || !sizeof( filter_objects( all_inventory(inv[i]), "short" ) - ({ 0 }) ) ){ continue; } else{ h = filter( all_inventory(inv[i]), cl ) - ({ 0 }); if( this_player()->query_property(P_COMBINED) ){ h = factorize( h, #'describe, ({ ARTICLE_A, DESCRIBE_FULL + DESCRIBE_WITH_STATE }) ); si = m_indices(h); sz = sizeof( h ); for( j = 0; j < sz; j++ ){ desc += ( " -> " + describe( h[si[j]][0], ARTICLE_A, DESCRIBE_FULL + DESCRIBE_WITH_STATE, sizeof( h[si[j]] ) ) + "\n" ); } } else{ sz = sizeof( j ); for( j = 0; j < sz; j++ ){ desc += ( " -> " + describe( h[j], ARTICLE_A, DESCRIBE_FULL + DESCRIBE_WITH_STATE ) + "\n" ); } } } } if( desc == "" ){ desc = "Nothing.\n"; } description += desc; } return make_inventory_output( description );#endif}//------------------------------------------------------------------//// Name: describe_weight //// Func: get the description of a weight //// Args: int weight //// Rtrn: string description ////------------------------------------------------------------------//private string describe_weight( int weight ){ switch( weight ){ case 0: return "nothing"; case 1 .. 11: return "about as much as a coin"; case 12 .. 40: return "about as much as a mouse"; case 41 .. 50: return "about as much as a chicken egg"; case 51 .. 100: return "about as much as a salamander"; case 101 .. 300: return "about as much as an apple"; case 301 .. 1500: return "about as much as a hammer"; case 1501 .. 2500: return "about as much as a melon"; case 3001 .. 5000: return "more than a melon"; case 5001 .. 7000: return "about as much as a cat"; case 7001 .. 15000: return "about as much as a large bucket full of water"; case 15001 .. 20000: return "about as much as a dog"; case 20001 .. 25000: return "about as much as a large dog"; case 25001 .. 28500: return "about as much as a sheep"; case 28501 .. 32000: return "about as much as a large sheep"; case 32001 .. 35000: return "about as much as a very large sheep"; case 35001 .. 45000: return "about as much as a pig"; case 45001 .. 65000: return "about as much as a small adult human"; case 65001 .. 75000: return "about as much as an adult human"; case 75001 .. 91600: return "about as much as a large adult human"; case 91601 .. 180000: return "more than a human, less than a lion"; case 180001 .. 250000: return "about as much as a lion"; case 250001 .. 700000: return "more than a lion, less than a cow"; case 700001 .. 860000: return "about as much as a cow"; case 860001 .. 3000000: return "more than a cow, less than an elephant"; case 3000001 .. 7000000: return "about as much as an elephant"; default: if( weight < 0 ){ return "less than nothing"; } else{ return "more than anything you know"; } }}//------------------------------------------------------------------//// Name: describe_light //// Func: get the description of a light source //// Args: int light //// Rtrn: string description ////------------------------------------------------------------------//private string describe_light( int light ){ switch( light ){ case 0 .. LIGHT_DARKNESS_THRESHOLD / 5 - 1: return "no light"; case LIGHT_DARKNESS_THRESHOLD / 5 .. LIGHT_CANDLE * 3 / 2 - 1: return "about as much light as a candle"; case LIGHT_CANDLE * 3 / 2 .. LIGHT_TORCH * 2 / 3 - 1: return "less light than a normal torch"; case LIGHT_TORCH * 2 / 3 .. LIGHT_TORCH * 2 - 1: return "about as much light as a normal torch"; case LIGHT_TORCH * 2 .. LIGHT_LAMP * 3 - 1: return "about as much light as a normal lamp"; default: if( light < 0 ){ return "a strange darkness"; } else{ return "an awful lot of light"; } }}//------------------------------------------------------------------//// Name: describe_value //// Func: get description of an item's value //// Args: int value //// Rtrn: string description ////------------------------------------------------------------------//private string describe_value( int value ){ return LIB_MONEY->describe_money( value );}//------------------------------------------------------------------//// Name: describe_armour_quality //// Func: get description of an armour's quality //// Args: int armour class //// Rtrn: string description ////------------------------------------------------------------------//private string describe_armour_quality( int class ){ switch( class ){ case 0 : return "useless"; case 1 : return "a useful armourpart"; case 2 : return "a good armour"; case 3..4: return "a very good armour"; default : return "a fantastic armour"; }}//------------------------------------------------------------------//// Name: describe_weapon_quality //// Func: get description of a weapon's quality //// Args: int weapon class //// Rtrn: string description ////------------------------------------------------------------------//private string describe_weapon_quality( int class ){ switch( class ){ case 0 : return "useless"; case 1 .. 4: return "a rather primitive weapon"; case 5 .. 10: return "a normal weapon"; case 11 .. 15: return "a good weapon"; case 16 .. 19: return "a very good weapon, but hard to handle"; default : return "a fantastic weapon, but very hard to handle"; }}//------------------------------------------------------------------//// Name: describe_strength //// Func: get description of strength //// Args: int strength //// Rtrn: string description ////------------------------------------------------------------------//private string describe_strength( int strength ){ return "like someone with strength " + strength;}//------------------------------------------------------------------//// Name: describe_condition //// Func: get description of a target's condition //// Args: int condition //// Rtrn: string description ////------------------------------------------------------------------//private string describe_condition( int condition ){ switch( condition ){ case 0.. 50: return "like an easy target"; case 51.. 150: return "like a medium target"; case 151.. 300: return "like a tough target"; case 301..1000: return "very powerful"; default : return "extremely powerful"; }}//------------------------------------------------------------------//// Name: describe_alignment //// Func: get a description of an alignment //// Args: int alignment //// Rtrn: string description ////------------------------------------------------------------------//private string describe_alignment( int alignment ) { switch( alignment ){ case AL_DEMONIC ..AL_EVIL : return "demonic"; case AL_EVIL +1 ..AL_NASTY : return "evil"; case AL_NASTY +1 ..AL_NEUTRAL: return "nasty"; case AL_NEUTRAL+1 ..AL_NICE : return "neutral"; case AL_NICE +1 ..AL_GOOD : return "nice"; case AL_GOOD +1 ..AL_SAINTLY: return "good"; default : return "saintly"; }}//------------------------------------------------------------------//// Name: describe_age //// Func: get a description of something's age //// Args: int age (seconds) //// Rtrn: string ("description of age") ////------------------------------------------------------------------//private string describe_age( int age ){ return "about "+ implode( explode( heart_long(age), " " )[0..1]," " )+" old";}//------------------------------------------------------------------//// Name: describe_load //// Func: get a description of an amount carried //// Args: int load (percent*10) //// Rtrn: string ("description of load") ////------------------------------------------------------------------//private string describe_load(int load){ switch( load ){ case 0000: return "carry nothing"; case 0001..0100: return "carry nearly nothing"; case 0101..0300: return "carry just a few things"; case 0301..0600: return "be about half-loaded"; case 0601..0800: return "be heavily loaded"; case 0801..1000: return "be fully loaded"; default : return "be overloaded"; }}//------------------------------------------------------------------//// Name: describe_weapon //// Func: get a description of a weapon //// Args: int weapon //// Rtrn: string ("description of weapon") ////------------------------------------------------------------------//private string describe_weapon(int weapon){ return "to have "+describe_weapon_quality(weapon);}//------------------------------------------------------------------//// Name: describe_armour //// Func: get a description of armour level //// Args: int armour //// Rtrn: string ("description of armour") ////------------------------------------------------------------------//private string describe_armour( int armour ){ switch( armour ){ case 0: return "unarmoured"; case 1..2: return "lightly-armoured"; case 3..4: return "armoured"; default : return "heavily-armoured"; }}//------------------------------------------------------------------//// Name: describe_health //// Func: get a description of a health level //// Args: int health (percent) //// Rtrn: string ("description of health") ////------------------------------------------------------------------//private string describe_health( int health ){ switch( health ){ case 00: return "dead"; case 01..11: return "nearly dead"; case 12..23: return "in a bad condition"; case 24..35: return "not in a good condition"; case 36..49: return "almost in normal condition"; case 50..61: return "in normal condition"; case 62..73: return "in good condition"; case 74..84: return "in very good condition"; case 85..92: return "in superb condition"; case 93..97: return "in almost excellent condition"; default : return "in excellent condition"; }}//------------------------------------------------------------------//// Name: light_of //// Func: get amount of light being emitted by object //// Args: object o //// Rtrn: int amount of light (candlepower/1000?) ////------------------------------------------------------------------//int light_of(object o){#if 1 if(environment(o)){ return query_inner_light_sources(environment(o))[o]; }else{ // a room? return query_own_light(o); }#else return( o->query_arm_light() || o->query_light() || fold_left( (#'+), m_values( filter( query_light_sources(o), (: member($3, $1) :), mkmapping(deep_inventory(o)) ) ) ) );#endif}//------------------------------------------------------------------//// Name: receive_event //// Func: handle occurring events //// Args: mapping e, string type, int prio //// Rtrn: nothing ////------------------------------------------------------------------//void receive_event( mapping e, string type, int prio ){ int i, j; mixed h, agent; string description; object fading_blindness; if( e[E_HANDLED] ){ return; } e[E_HANDLED] = 1; // we will handle it now agent = e[E_AGENT]; switch( type ){ default: raise_error( "Internal error '" + type + "'\n" ); case "look": switch( e[E_TYPE] ){ default: raise_error( "Internal error '" + e[E_TYPE] + "'\n" ); case "look_into": // this is a look_into event to neighbour rooms, if( !e[E_ID] ){ break; // skip it. } // next part by Coogan, 15-Apr-2003 send_message( ({ M_PL_THE, M_PL_VERB, "look", " into ", M_THE, M_ARG, E_TARGET, "." }), e ); if( ( i = sizeof( ( h = all_inventory( e[E_TARGET] ) ) ) ) ){ send_message( ({ M_WRITE, "This ", M_NONE, M_ARG, E_TARGET, M_VERB, "seem", M_ARG, E_TARGET, " to contain ", M_SIMPLE_DESCRIBE, h, "." }), e ); } else{ send_message( ({ M_WRITE, "This ", M_NONE, M_ARG, E_TARGET, M_VERB, "seem", M_ARG, E_TARGET, " to contain nothing." }), e ); } break; case "look": case "see": case "glimpse": // Coogan, 07-Nov-2002 case "look_view": h = agent->query_property(P_DISPLAY_WIDTH) || 79; tell_object( agent, break_string( look_at_room( e[E_TARGET], ( e[E_TYPE]=="see"? 1 : ( e[E_TYPE]=="glimpse"? 2 : 0 ) ), agent->query_property( P_COMBINED ), agent, 0, e[E_TYPE] == "look_view" ), h ) ); if( !agent->test_sight(0, 1) && // cannot see e[E_TARGET] == environment(agent) ){ // looked at his own room? if( fading_blindness = present_clone( "obj/fading_blindness", agent ) ){ destruct( fading_blindness ); } move_object( fading_blindness = clone_object( "obj/fading_blindness" ), agent ); fading_blindness->set_command( e[E_TYPE] ); } break; case "inventory": case "equipment": // added the next complete if(), Coogan 03-Jul-99 if( e[E_ID] && e[E_TARGET][0]->query_fakeitem_id( e[E_ID] ) ){ description = look_at_thing( agent, e[E_TARGET][0], e[E_ID] ); h = agent->query_property(P_DISPLAY_WIDTH) || 79;#if 0 // Coogan, 10-Feb-02, tell_more() and tell_object() break, too description = break_string( description, h );#endif if( !call_resolved( &h, agent, "tell_more", description ) ){ tell_object( agent, description ); } break; } description = with_player( agent, ( e[E_TYPE] == "equipment" ? ( #'look_at_equipment ) : ( #'look_at_inventory ) ), ({ e[E_TARGET], e[E_ID] }) ); tell_object( agent, description ); break; case "show": map_messages( e[E_MESSAGES], e ); h = e[E_TARGET]->query_property( P_DISPLAY_WIDTH ) || 79;#if 0 // Coogan, 10-Feb-02: use the target's t_c_closure()! tell_object( e[E_TARGET], break_string( with_player( e[E_TARGET], #'look_at_thing, ({ e[E_TARGET], e[E_OBJECT], e[E_ID] }) ) || "", h ) );#else tell_object( e[E_TARGET], terminal_colour( with_player( e[E_TARGET], #'look_at_thing, ({ e[E_TARGET], e[E_OBJECT], e[E_ID] }) ) || "", e[E_TARGET]-> get_terminal_colour_closure(), h ) );#endif break; case "show_all": map_messages( e[E_MESSAGES], e ); i = e[E_TARGET]->query_property( P_DISPLAY_WIDTH ) || 79; h = map( e[E_OBJECT], (: look_at_thing($2, $1, 0, 1) :), e[E_AGENT] ); tell_object( e[E_TARGET], terminal_colour( implode(h,""), e[E_TARGET]-> get_terminal_colour_closure(), e[E_TARGET]->query_property( P_DISPLAY_WIDTH ) || 79 ) ); break; case "examine": if( description = look_at_thing( agent, e[E_TARGET], e[E_ID] ) ){ h = agent->query_property( P_DISPLAY_WIDTH ) || 79;#if 0 // Coogan, 10-Feb-02: keep the %^stuff%^ as long as possible. // and tell_object() replaces that stuff, too. description = break_string( description, h );#endif if( !call_resolved( &h, agent, "tell_more", description ) ){ tell_object( agent, description ); } } break; case "est_weight": case "est_light": case "est_value": case "est_quality": case "est_strength": case "est_condition": case "est_alignment": case "est_age": case "est_load": case "est_weapon": case "est_armour": case "est_health": map_messages( e[E_MESSAGES], e ); { int val, estimated_val, skill_base; // skill_base shall be in the range of one // stat value (about 0..40) but also lesser // and greater values are possible. string skill, desc; mixed computer, *msg; closure describer; switch( e[E_TYPE] ){ default: raise_error( "Internal error: " + e[E_TYPE] + "\n" ); case "est_weight": describer = ( #'describe_weight ); msg = ({ M_WRITE, M_THE, e[E_TARGET], M_VERB, "weigh", e[E_TARGET], M_ARG, 0, "." }); skill_base = e[E_AGENT]->query_dex(); skill = S_ESTIMATE_ITEM; val = get_encumbrance( e[E_TARGET] ); break; case "est_light": describer = ( #'describe_light ); msg = ({ M_WRITE, M_THE, e[E_TARGET], M_VERB, "emit", e[E_TARGET], M_ARG, 0, "." }); // estimating light is easy. skill_base = ( e[E_AGENT]->query_int() + 10 ); skill = S_ESTIMATE_ITEM; val = light_of( e[E_TARGET] ); break; case "est_value": describer = ( #'describe_value ); msg = ({ M_WRITE, M_THE, e[E_TARGET], M_VERB, "could", e[E_TARGET], " be worth about ", M_ARG, 0, "." }); skill_base = e[E_AGENT]->query_int(); // --> VALUE, Coogan, 05-Feb-02 skill = S_ESTIMATE_VALUE; val = e[E_TARGET]->query_value(); break; case "est_quality": if( e[E_TARGET]->id("armour") ){ describer = ( #'describe_armour_quality ); skill = S_ESTIMATE_ARMOUR; } else if( e[E_TARGET]->id("weapon") ){ describer = ( #'describe_weapon_quality ); skill = S_ESTIMATE_WEAPON; } else{ message( "This is neither armour " "nor weapon.\n" ); return; } msg = ({ M_WRITE, M_THE, e[E_TARGET], M_VERB, "seem", e[E_TARGET], " to be", M_ARG, 0, "." }); skill_base = e[E_AGENT]->query_int(); val = e[E_TARGET]->query_class(); break; case "est_strength": describer = ( #'describe_strength ); msg = ({ M_WRITE, M_THE, e[E_TARGET], M_VERB, "look", e[E_TARGET], M_ARG, 0, "." }); // strong people are better in // estimating other people's strength skill_base = ( e[E_AGENT]->query_int() + e[E_AGENT]->query_str() ) / 2; skill = S_ESTIMATE_STATS; val = e[E_TARGET]->query_str(); break; case "est_condition": describer = ( #'describe_condition ); msg = ({ M_WRITE, M_THE, e[E_TARGET], M_VERB, "look", e[E_TARGET], M_ARG, 0, "." }); skill_base = ( e[E_AGENT]->query_int() + e[E_AGENT]->query_con() ) / 2; skill = S_ESTIMATE_STATS; val = e[E_TARGET]->query_max_hp(); break; case "est_alignment": describer = ( #'describe_alignment ); msg = ({ M_WRITE, M_THE, e[E_TARGET], M_VERB, "seem", e[E_TARGET], M_ARG, 0, "." }); // people tend to see another // person as what they are // themselves, but the better a // person is, the less influenced // by this they are. skill_base = e[E_AGENT]->query_int(); skill = S_ESTIMATE_LIVING; val = to_int( e[E_TARGET]->query_alignment() + e[E_AGENT]->query_alignment() * pow( 2.0, ( 200 - e[E_AGENT]-> query_alignment() ) / 20000.0 ) ); break; case "est_age": describer = ( #'describe_age ); msg = ({ M_WRITE, M_THE, e[E_TARGET], M_VERB, "look", e[E_TARGET], M_ARG, 0, "." }); skill_base = e[E_AGENT]->query_int(); skill = S_ESTIMATE_LIVING; val = e[E_TARGET]->query_age(); break; case "est_load": describer = ( #'describe_load ); msg = ({ M_WRITE, M_THE, e[E_TARGET], M_VERB, "seem", e[E_TARGET], " to", M_ARG, 0, "." }); // strong people estimate better skill_base = ( e[E_AGENT]->query_int() + e[E_AGENT]->query_str() ) / 2; skill = S_ESTIMATE_EQUIPMENT; val = ( e[E_TARGET]->query_carry() * 1000 / e[E_TARGET]->query_max_carry() ); break; case "est_weapon": describer = ( #'describe_weapon ); msg = ({ M_WRITE, M_THE, e[E_TARGET], M_VERB, "seem", e[E_TARGET], M_ARG, 0, "." }); // base weapon skill is dex skill_base = ( e[E_AGENT]->query_int() + e[E_AGENT]->query_dex() ) / 2; skill = S_ESTIMATE_WEAPON; val = e[E_TARGET]->query_wc(); break; case "est_armour": describer = ( #'describe_armour ); msg = ({ M_WRITE, M_THE, e[E_TARGET], M_VERB, "seem", e[E_TARGET], M_ARG, 0, "." }); skill_base = e[E_AGENT]->query_int(); skill = S_ESTIMATE_ARMOUR; val = e[E_TARGET]->query_ac(); break; case "est_health": describer = ( #'describe_health ); msg = ({ M_WRITE, M_THE, e[E_TARGET], M_VERB, "seem", e[E_TARGET], " to be", M_ARG, 0, "." }); skill_base = e[E_AGENT]->query_int(); skill = S_ESTIMATE_HEALTH; val = ( e[E_TARGET]->query_hp() * 100 / e[E_TARGET]->query_max_hp() ); break; }//------------------------------------------------------------------//// Note:// use_skill() returns values between -300 and +200.// Values above 0 are meant the be a success.// Values between -200 and 0 are meant to be a failure.// Values below -200 are meant to be a botch or fumble.// We do not honor these semantics but use the value directly in the// formula:// gnuplot: plot [-300:200] 100 * 1.015**(1.018**-x) - 99// This formula gives the factor by which the real value is either// multiplied or divided (which depends on a simple random(2)).// The skill base (derived from the stats) is multiplied by 5 and// added to the result of use_skill() before the formula is applied.//------------------------------------------------------------------// computer = (: float v; v = 100 * pow( 1.015, pow( 1.018, -( $4->use_skill( $3 ) + 5 * $2 ) ) ) - 99; return to_int( random(2)? $1 * v : $1 / v ); :); computer = lambda( 0, ({ ( #'funcall ), computer, val, skill_base, skill, e[E_AGENT] }) ); estimated_val = e[E_AGENT]->get_cache( sprintf( "%s:%O:%d", e[E_TYPE], e[E_TARGET], // ignore val for cache-key if an // age is estimated. e[E_TYPE] != "est_age" && val ), computer ); desc = funcall( describer, estimated_val ); if( is_wizard( e[E_AGENT], IW_TOOLUSER ) ){ desc += sprintf( " [%d%+d]", val, estimated_val - val ); } send_message( msg, ([ 0: " " + desc ]) ); } break; case "cmp_weight": case "cmp_light": case "cmp_value": case "cmp_quality": case "cmp_strength": case "cmp_condition": case "cmp_alignment": case "cmp_age": case "cmp_load": case "cmp_weapon": case "cmp_armour": case "cmp_health": map_messages( e[E_MESSAGES], e ); { string *descs; // shall be in range +/-1000, but may exceed int diff, skill_base; switch( e[E_TYPE] ){ default: raise_error( "Internal error\n" ); case "cmp_weight": descs = ({ "lighter than", "as heavy as", "heavier than" }); skill_base = e[E_AGENT]->query_dex(); diff = to_int( ( log( get_encumbrance( e[E_TARGET][0] ) + 1 ) - log( get_encumbrance( e[E_TARGET][1] ) + 1 ) ) * 85 ); // log(100000(~=max_weight_item))*85 // ~= 1000 break; case "cmp_light": descs = ({ "darker than", "as bright as", "brighter than" }); // estimating light is easy. skill_base = ( e[E_AGENT]->query_int() + 10 ); // added the "|| 1" for log() // Coogan, 13-Nov-01 diff = to_int( ( log( light_of( e[E_TARGET][0] ) || 1 ) - log( light_of( e[E_TARGET][1] ) || 1 ) ) * 7 ); // log(1000000(~=max_light_value))*7 // ~= 1000 break; case "cmp_value": descs = ({ "not as expensive as", "as valuable as", "more expensive than" }); skill_base = e[E_AGENT]->query_int(); diff = (e[E_TARGET][0]->query_value() - e[E_TARGET][1]->query_value() ); break; case "cmp_quality": descs = ({ "to be of a lesser quality " "than", "as good as", "to be of a higher quality " "than" }); skill_base = e[E_AGENT]->query_int(); diff = ( e[E_TARGET][0]->query_class() - e[E_TARGET][1]->query_class() ) * 40; break; case "cmp_strength": descs = ({ "to be weaker than", "to be as strong as", "to be stronger than" }); // strong people are better in // estimating other people's strength skill_base = ( e[E_AGENT]->query_int() + e[E_AGENT]->query_str() ) / 2; diff = ( e[E_TARGET][0]->query_str() - e[E_TARGET][1]->query_str() ) * 25; break; case "cmp_condition": descs = ({ "less fit than", "as fit as", "fitter than" }); skill_base = ( e[E_AGENT]->query_int() + e[E_AGENT]->query_con() ) / 2; diff = ( e[E_TARGET][0]->query_max_hp() - e[E_TARGET][1]->query_max_hp() ) * 3; break; case "cmp_alignment": descs = ({ "to be more evil than", "to be as good to others as", "to be better than" }); skill_base = e[E_AGENT]->query_int(); diff = ( e[E_TARGET][0]-> query_alignment() - e[E_TARGET][1]-> query_alignment() ); break; case "cmp_age": descs = ({ "younger than", "of the same age as", "older than" }); skill_base = e[E_AGENT]->query_int(); diff = to_int( ( log( e[E_TARGET][0]-> query_age() ) - log( e[E_TARGET][1]-> query_age() ) ) * 50 ); // log(alfe's_age)*50 ~= 1000 break; case "cmp_load": descs = ({ "to carry less than", "to carry as much as", "to carry more than" }); // strong people estimate better skill_base = ( e[E_AGENT]->query_int() + e[E_AGENT]->query_str() ) / 2; diff = ( e[E_TARGET][0]->query_carry() * 1000 / e[E_TARGET][0]->query_max_carry() - e[E_TARGET][1]->query_carry() * 1000 / e[E_TARGET][1]->query_max_carry() ); break; case "cmp_weapon": descs = ({ "to be worse equipped than", "to be as good equipped as", "to be better equipped than" }); // base weapon skill is dex skill_base = ( e[E_AGENT]->query_int() + e[E_AGENT]->query_dex() ) / 2; diff = ( e[E_TARGET][0]->query_wc() - e[E_TARGET][1]->query_wc() ) * 50; break; case "cmp_armour": descs = ({ "to be worse armoured than", "to be as good armoured as", "to be better armoured than" }); skill_base = e[E_AGENT]->query_int(); diff = ( e[E_TARGET][0]->query_ac() - e[E_TARGET][1]->query_ac() ) * 100; break; case "cmp_health": descs = ({ "to be more hurt than", "to be as healthy as", "to be healthier than" }); skill_base = e[E_AGENT]->query_int(); diff = ( e[E_TARGET][0]->query_hp() * 1000 / e[E_TARGET][0]->query_max_hp() - e[E_TARGET][1]->query_hp() * 1000 / e[E_TARGET][1]->query_max_hp() ); break; } diff = e[E_AGENT]->get_cache( sprintf( "%s:%O:%d", e[E_TYPE], e[E_TARGET] & e[E_TARGET],//------------------------------------------------------------------//// Note:// that x & x on arrays produces an array with fixed ordering of the// elements; this is necessary in order to produce equal results on// comparing two things in various order; same is valid for the// abs()-value used in the line below.//------------------------------------------------------------------// diff<0? -diff : diff ), to_int( diff + ( 1000 * gauss_random() / skill_base ) ) / 50 ); send_message( ({ M_WRITE, M_THE, e[E_TARGET][0], M_VERB, "seem", e[E_TARGET][0], " " + descs[(diff>=0) + (diff>0)] + " ", M_THE, e[E_TARGET][1], "." }) ); } break; } }}/********************************************************************/