/* File: /cmds/std/_look.c
Creator: Matt. D. Robinson (Yakker/Regret@TMI) 1991
Updated: Help added by Brian (1/28/92)
Rewritten by Adam Beeman (Buddha@TMI) 6/25/92
Light handling by Steven Schmidt (Mobydick@TMI) 11/9/92
Contents processing routines, light handling updated,
and infravision by Glenn Ferguson (Watcher@TMI) 1/29/93
Got querying item_desc to work properly if the
description was a function by Grendel @ TMI-2,
10 August 1993
Rewritten and door/exit suppression added by Austin H.
Ziegler (Fantome@TMI) 11 August 1993
This code allows a user to "look" in a room, or at a specific
object in the user's inventory or environment.
*/
#include <config.h>
#include <mudlib.h>
#include <daemons.h>
inherit DAEMON;
/* Contents display format flag:
0 == standard look
1 == line by line processed
2 == processed linked together
*/
#define FLAG 1
// prototypes...
string look_in_room (object room, int flag);
varargs string look_at_item (string item, object user, string In);
string look_in_item (string item, object user);
string convert_number (int num);
string process_contents (mixed *inv, int flag);
string content_match (object what);
mixed *number;
object viewingOb, env, it;
#ifndef BLOCK_ATTACK
int Attacking;
#endif
/* cmd_look (string)
this function 'look's in a room and handles the case of
whether it's just the room or a separate object */
int cmd_look (string str) {
int oldStatus;
string tmp, tmp2;
mapping exits, doors;
mixed *hidden_exits, *hidden_doors;
it = 0;
viewingOb = this_player();
env = environment (viewingOb);
/* standard TMI-2 look blocks for 2 seconds, but I don't like that,
so we've got another option available on compile-time */
#ifndef BLOCK_ATTACK
Attacking = ((viewingOb->query_attackers()) ? 1 : 0);
#endif
/* Check to see if we have an argument list. If we do, see if
we're trying to look at a particular object. If so, get the
object's description. Otherwise, ask the room for its description.
*/
// are we looking at our immediate environment?
if (!str || !stringp (str)) {
// do we have an environment? If not, write the default message
if (!env) {
write ("There is nothing to see here.\n");
#ifdef BLOCK_ATTACK
viewingOb->block_attack (2);
#endif
return 1;
}
/*
This garbles the room description. It's useful for simulating acid
flashbacks among your players. We recommend you not do that too often. :)
write (LANGUAGE_D->garble_string(look_in_room (env, (int)viewingOb->query_temp ("force_to_look")),"orcish")+"\n") ;
*/
write (look_in_room (env, (int)viewingOb->query_temp ("force_to_look")));
#ifdef BLOCK_ATTACK
viewingOb->block_attack (2);
#endif
return 1;
}
// are we looking at something in a container?
if (sscanf(str, "at %s in %s", tmp, tmp2) == 2) {
// we're looking inside a container
// blocking a look in a locked/opaque container doesn't work yet. -- Fantome
// hopefully will work soon
#ifndef BLOCK_ATTACK
if (Attacking) {
write ("You are too busy to get a detailed look at that!\n");
return 1;
}
#endif
write (sprintf ("%-=75s", look_at_item (tmp, viewingOb, tmp2)));
return 1;
}
// are we looking at an object?
if (sscanf(str, "at %s", tmp)) {
write (sprintf ("%-=75s", look_at_item (tmp, viewingOb)));
return 1;
}
// are we looking in an object?
if (sscanf(str, "in %s", tmp)) {
#ifndef BLOCK_ATTACK
if (Attacking) {
write ("You are too busy to get a detailed look at that!\n");
return 1;
}
#endif
write (sprintf ("%-=75s", look_in_item (tmp, viewingOb)));
return 1;
}
// are we looking in the room?
if (env) {
exits = env->query ("exits");
doors = env->query ("doors");
hidden_exits = env->query ("exit_suppress");
hidden_doors = env->query ("door_suppress");
if (mapp (exits) && member_array (str, keys (exits)) != -1) {
if (doors && doors[str]) {
if (((!pointerp (hidden_doors) || (int)hidden_doors[0] != 1 ||
member_array (str, hidden_doors) == -1))
&& doors[str]["status"] != "open") {
write ("The door is closed.\n");
#ifdef BLOCK_ATTACK
viewingOb->block_attack(2);
#endif
return 1;
}
}
if ((!pointerp (hidden_exits) ||
member_array (str, hidden_exits) == -1) ||
(!intp (hidden_exits) || (int)hidden_exits[0] != 1)) {
env = find_object_or_load (exits[str]);
write (look_in_room (env, (int)this_player()->query_temp("force_to_look")));
#ifdef BLOCK_ATTACK
viewingOb->block_attack(2);
#endif
return 1;
}
}
}
cmd_look (sprintf ("at %s", str));
return 1;
}
int can_see (object who, object what) {
int invis;
if (!(what->query ("short")))
return 0;
invis = what->query ("invisible");
if (!invis)
return 1;
if (invis == 1 && wizardp (who))
return 1;
if (invis == 2 && adminp(who->query ("name")))
return 1;
return 0;
}
int can_see2 (object what, object who) {
return can_see (who, what);
}
string living_description (object ob) {
object *inv;
int i;
string a1, a2, tmp, reg, race, raceat, short, gender, genat;
reg = (string)ob->query ("long");
if (!reg)
reg = "";
race = (string)ob->query ("race");
raceat = article (race) + " " + race;
gender = (string)ob->query ("gender");
genat = ((viewingOb == ob) ? "You are"
: capitalize (subjective (gender)) + " is");
i = sizeof (inv = all_inventory(ob));
while (i--)
if (tmp = inv[i]->query ("extra_look")) {
while (sscanf(tmp, "%s$N%s", a1, a2) > 1)
tmp = sprintf ("%s%s%s", a1, ob->query ("cap_name"), a2);
reg += tmp;
}
if (stringp (race) && race != "")
reg = sprintf ("%s%s %s.\n", reg, genat, raceat);
#ifndef BLOCK_ATTACK
if (!Attacking) {
#endif
inv = filter_array (inv, "can_see2", this_object(), viewingOb);
i = sizeof (inv);
if (i) {
reg = sprintf ("%s %s carrying:\n", reg, genat);
while (i--) {
short = (string)inv[i]->query ("short");
if (short)
reg = sprintf ("%s %s%s%s.\n", reg, short,
(inv[i]->query ("equipped") ? " (equipped)" : ""),
(inv[i]->query ("wielded") ? " (wielded)" : ""));
}
} else
reg = sprintf ("%s%s empty handed.\n", reg, genat);
#ifndef BLOCK_ATTACK
}
#endif
return reg;
}
varargs
string item_description (string str, object user, int infra, string In) {
object inob;
mapping items, doors;
string tmp, ret, dir, foo;
if (str == "me")
str = (string)viewingOb->query ("name");
if (str == "door" || (str && sscanf(str, "%s door", dir))) {
#ifndef BLOCK_ATTACK
if (Attacking)
return "You are too busy to get a detailed look at that!\n";
#endif
if (user && environment (user))
doors = environment (user)->query ("doors");
if(!doors || !sizeof(doors))
return "You don't see any doors here.\n";
if (!dir) {
if (sizeof (doors) > 1)
return "Which door do you wish to look at?\n";
dir = keys (doors)[0];
}
if (infra)
return "That door gives off no heat pattern.\n";
if (!doors[dir])
return sprintf ("There is no door in the %s direction.\n", dir);
if (!doors[dir]["desc"])
tmp = "";
else
tmp = sprintf ("%s.\n", capitalize(doors[dir]["desc"]));
if (doors[dir]["status"])
tmp = sprintf ("%sThe %s door is %s.\n", tmp, dir, doors[dir]["status"]);
#ifdef BLOCK_ATTACK
viewingOb->block_attack (2);
#endif
if (!tmp || tmp == "")
return sprintf ("There is nothing special about the %s door.\n", dir);
else
return tmp;
}
#ifndef BLOCK_ATTACK
if (!Attacking) {
#endif
if (In) {
inob = present (In, user);
if (!inob && env)
inob = present (In, env);
if (inob) {
it = present (str, inob);
if ((int)inob->query_is_closed() && (int)inob->query ("opaque"))
return "Just how do you propose looking in a closed container?\n";
}
}
#ifndef BLOCK_ATTACK
}
#endif
if (!it)
it = present (str, user);
#ifndef BLOCK_ATTACK
if (!Attacking) {
#endif
if (!it && env)
it = present(str, env);
#ifndef BLOCK_ATTACK
}
#endif
if (it && !can_see (viewingOb, it))
return "I don't see that here.\n";
if (infra && it && objectp(it))
if (living (it) || it->query ("hot"))
return "Your infravision shows a bright heat pattern.\n";
else
return "Your infravision shows no heat pattern.\n";
if (it) {
if (living (it))
ret = living_description (it);
else
ret = (string)it->query ("long");
} else {
#ifndef BLOCK_ATTACK
if (Attacking)
return "You are too busy to get a detailed look at that!\n";
#endif
if (env) {
/* okay, this is the way to get things built into the room.
assuming that we _can_ look at objects, check for room-defined
dummy items. Fix to item_desc of @@fun by Grendel.*/
tmp = env->query ("item_desc/" + str);
if (tmp)
ret = tmp;
if (!ret) {
tmp = env->query ("item_func/" + str);
if (tmp) {
(string)call_other (env, tmp);
#ifdef BLOCK_ATTACK
viewingOb->block_attack (2);
#endif
return "";
}
}
} else
return "There is nothing to see here.\n";
}
if (!ret || ret == "")
return "I don't see that here.\n";
if (it) {
if (it != viewingOb) {
if (living (it))
message ("tell_object",
sprintf ("%s looks at you.\n", user->query ("cap_name")),
it);
foo = it->query("cap_name");
if (!foo)
foo = it->query("short") ;
if (!foo)
foo = "something";
} else
foo = sprintf ("%sself", objective ((string)viewingOb->query ("gender")));
message ("say", sprintf ("%s looks at %s.\n", user->query ("cap_name"),
(living (it) ? foo : lower_case (foo))), environment (user),
({ user, it }));
} else
message ("say", sprintf ("%s looks at %s.\n", user->query ("cap_name"),
str), environment (user), user);
#ifdef BLOCK_ATTACK
viewingOb->block_attack (2);
#endif
return ret;
}
varargs string look_at_item (string str, object user, string In) {
//Check if the user is blind.
if ((int)user->query ("blind"))
return "You are blind and cannot see.\n";
//Check to see if the user can see.
if ((int)user->query ("vision"))
if (!undefinedp (In))
return item_description (str, user, 0, In);
else
return item_description (str, user, 0);
//Check to see if user has infravision capabilities
if ((int)user->query("infravision"))
if (!undefinedp (In))
return item_description (str, user, 1, In);
else
return item_description (str, user, 1);
//Guess there is no light here, then.
return "It is dark and you can't see a thing.\n";
}
string lit_room_description(object room, int infra, int flag);
varargs string look_in_room (object room, int flag) {
//Check to see if the user is blind
if (viewingOb->query("blind"))
return "You are blind and cannot see.\n";
//Check to see if the room can be seen.
if (room->query("no_vision"))
return (string)room->query("no_vision") ;
//Check to see if the user can see within the room.
if (viewingOb->query ("vision"))
return lit_room_description (room, 0, flag);
//Check to see if the user has infravision
if (viewingOb->query("infravision"))
return lit_room_description (room, 1, flag);
//Looks like there isn't any light here.
return "It is dark and you can't see a thing.\n";
}
int suppress_filt (string exit, string *suppress) {
if (member_array (exit, suppress) == -1)
return 1;
return 0;
}
string lit_room_description (object room, int infra, int flag) {
string long, str, tmp, *dirs;
object *contents, *live;
int i;
mixed *suppress;
mapping exits, doors ;
/* Check the player's "brief" property and get either the long or short
description as is appropriate. If infravision is being used, minimal
details of the surroundings are given. */
if (infra)
long = "";
else
if (flag && viewingOb->query ("brief")) {
long = sprintf ("%s\n", room->query ("short"));
} else {
#ifdef LONG_WITH_SHORT
long = sprintf ("%s\n%s", room->query ("short"), room->query ("long"));
#else
long = room->query ("long");
#endif
if (!flag && room->query ("outside"))
long += WEATHER_D->query_weather_msg();
}
if (!long)
long = "";
/* Query a room's "door_suppress" property to see what, if any, doors
and their statuses will be displayed in the room. */
suppress = room->query ("door_suppress");
if (!suppress || pointerp (suppress)) {
doors = room->query ("doors");
if (doors && !infra) {
dirs = keys (doors);
if (pointerp (suppress))
dirs = filter_array (dirs, "suppress_filt", this_object(), suppress);
i = sizeof (dirs);
while (i--)
long = sprintf ("%s The %s door is %s.\n", long, dirs[i],
doors[dirs[i]]["status"]);
}
}
/* Query a room's "exit_suppress" property to see what, if any, obvious
exits will be displayed or not. */
suppress = room->query ("exit_suppress");
if (!suppress || pointerp (suppress)) {
exits = room->query ("exits");
if (exits)
dirs = keys (exits);
if (pointerp (suppress))
dirs = filter_array (dirs, "suppress_filt", this_object(), suppress);
i = sizeof (dirs);
switch (i) {
case 0: {
long += ((infra) ? "\tYou cannot detect any obvious exits.\n"
: "\tThere are no obvious exits.\n");
break;
}
case 1: {
long = sprintf ("%s\tThe only obvious exit%s is %s.\n", long,
((infra) ? " you can detect" : ""), dirs[0]);
break;
}
case 2: {
long = sprintf ("%s\t%sbvious exits %sare %s and %s.\n", long,
((infra) ? "The only o" : "O"),
((infra) ? "you can detect " : ""), dirs[0], dirs[1]);
break;
}
default: {
long = sprintf ("%s\t%sbvious exits %sare %s, and %s.\n", long,
((infra) ? "The only o" : "O"),
((infra) ? "you can detect " : ""),
implode (dirs[0..(i-2)], ", "), dirs[i-1]);
}
}
}
// Process inventory of the room/object being examined
contents = all_inventory (room);
// Check for infravision flag and living heat patterns
if (infra) {
i = sizeof (live = filter_array (contents, "filter_living", this_object()));
switch (i) {
case 0: {
long += "Your infravision shows no other heat patterns.\n";
break;
}
case 1: {
long += "Your infravision shows only one heat pattern.\n";
break;
}
default: {
long = sprintf ("%sYour infravision shows %s heat patterns.\n",
long, convert_number (i));
break;
}
}
return long;
}
if (!FLAG) {
i = sizeof (contents);
while (i--) {
tmp = (string)contents[i]->query ("short");
if (contents[i] != viewingOb && tmp && tmp != "")
if (can_see(viewingOb,contents[i]))
long = sprintf ("%s %s\n", long, capitalize (tmp));
}
} else
long += process_contents (contents, FLAG);
return long;
}
// Filter out all objects without a possible heat pattern
int filter_living (object what) {
if (what == viewingOb || (userp (what) && !interactive (what)))
return 0;
return (living (what) && !what->query ("cold") || what->query ("hot"));
}
string look_in_item (string tmp, object user) {
string tmp2;
object *contents;
it = present (tmp, user);
if (!it && env)
it = present (tmp, env);
// THIS CLEARS UP THE look in foo PROBLEM -- Moby
if (!it) {
return "I don't see that here.\n" ;
}
// THAT'S ALL
if (living (it))
return "You must be kidding me! Look INSIDE a living being?\n";
if ((int)it->query_is_closed() && (int)it->query ("opaque"))
return "Just how do you propose looking in a closed container?\n";
if (it) {
// in our hands or in our environment.
contents = all_inventory (it);
if (!contents) {
return "You don't see anything inside.\n";
} else {
tmp2 = process_contents (contents, FLAG);
if (tmp2 == "")
return "You don't see anything inside.\n";
return sprintf ("%s contains:\n%s\n", capitalize (tmp), tmp2);
}
}
// this is where we could look for things in the room's properties.
return "Look in what?\n";
}
string process_contents (mixed *contents, int flag) {
mapping match;
mixed *inv, *ninv;
string tmp, ret;
int loop, i;
ret = "";
inv = contents;
// Remove all objects with no short desc or command initiator
inv = filter_array (inv, "clean_objects", this_object());
// Compile list of objects with matching short descriptions
match = unique_mapping (inv, "query", "short");
ninv = keys (match);
//Loop through object contents and place them into a display string
loop = sizeof (ninv);
while (loop--) {
/* older code handled living cases separately. taken out by Mobydick @ TMI-2
on 10 April 1993, kept out by Fantome 24 July 1993 */
i = sizeof (match[ninv[loop]]);
if (i > 1)
tmp = sprintf ("%s %s", convert_number (i), pluralize (ninv[loop]));
else tmp = ninv[loop];
if (flag == 1)
if(stringp(tmp)) ret = sprintf("%s %s\n", ret,capitalize(tmp));
else ret = sprintf("%s A person with a number for a short\n",ret);
else
ret = sprintf ("%s%s%s", ret, tmp,
((loop > 1) ? ", " : ((!loop) ? "." : ", and ")));
}
if (flag == 2 && ret != "")
ret = wrap (sprintf ("You see %s", ret));
return ret;
}
// Remove all invisible objects from the room's content's list
int clean_objects (object what) {
if (!can_see (viewingOb, what))
return 0;
return (((string)what->query ("short") && what != viewingOb) ? 1 : 0);
}
// Compare each object's short desc with processing short desc
string content_match (object what) {
return (string)what->query("short");
}
// Convert numeric value to word format if below 21
string convert_number(int num) {
if (!number)
number = ({
"one", "two", "three", "four", "five", "six", "seven", "eight",
"nine", "ten", "eleven", "twelve", "thirteen", "fourteen",
"fifteen", "sixteen", "seventeen", "eighteen", "nineteen",
"twenty" });
return ((num > 20) ? "many" : number[num - 1]);
}
string help() {
return (@Help
Syntax: look [at object]
If no object is specified this command makes you look
around the room. If an object is specified it lets you
examine the object more closely.
See also: brief, glance
Help
);
}