mirror of
https://github.com/tbamud/tbamud.git
synced 2026-04-04 11:27:18 +02:00
Scan/hide update
This commit is contained in:
parent
cba4a5b0aa
commit
219d59787f
10 changed files with 315 additions and 175 deletions
|
|
@ -235,10 +235,13 @@ ACMD(do_report);
|
|||
ACMD(do_save);
|
||||
ACMD(do_skills);
|
||||
ACMD(do_sneak);
|
||||
ACMD(do_perception);
|
||||
ACMD(do_split);
|
||||
ACMD(do_steal);
|
||||
ACMD(do_visible);
|
||||
bool perform_scan_sweep(struct char_data *ch);
|
||||
void clear_scan_results(struct char_data *ch);
|
||||
bool scan_can_target(struct char_data *ch, struct char_data *tch);
|
||||
bool scan_confirm_target(struct char_data *ch, struct char_data *tch);
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
|
|
|
|||
|
|
@ -625,6 +625,7 @@ void look_at_room(struct char_data *ch, int ignore_brief)
|
|||
/* now list characters & objects */
|
||||
list_obj_to_char(world[IN_ROOM(ch)].contents, ch, SHOW_OBJ_LONG, FALSE);
|
||||
list_char_to_char(world[IN_ROOM(ch)].people, ch);
|
||||
perform_scan_sweep(ch);
|
||||
}
|
||||
|
||||
static void look_in_direction(struct char_data *ch, int dir)
|
||||
|
|
@ -2658,101 +2659,3 @@ ACMD(do_areas)
|
|||
else
|
||||
page_string(ch->desc, buf, TRUE);
|
||||
}
|
||||
|
||||
static void list_scanned_chars(struct char_data * list, struct char_data * ch, int
|
||||
distance, int door)
|
||||
{
|
||||
char buf[MAX_STRING_LENGTH], buf2[MAX_STRING_LENGTH - 1];
|
||||
|
||||
const char *how_far[] = {
|
||||
"close by",
|
||||
"a ways off",
|
||||
"far off to the"
|
||||
};
|
||||
|
||||
struct char_data *i;
|
||||
int count = 0;
|
||||
*buf = '\0';
|
||||
|
||||
/* this loop is a quick, easy way to help make a grammatical sentence
|
||||
(i.e., "You see x, x, y, and z." with commas, "and", etc.) */
|
||||
|
||||
for (i = list; i; i = i->next_in_room)
|
||||
|
||||
/* put any other conditions for scanning someone in this if statement -
|
||||
i.e., if (CAN_SEE(ch, i) && condition2 && condition3) or whatever */
|
||||
|
||||
if (CAN_SEE(ch, i))
|
||||
count++;
|
||||
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
for (i = list; i; i = i->next_in_room) {
|
||||
|
||||
/* make sure to add changes to the if statement above to this one also, using
|
||||
or's to join them.. i.e.,
|
||||
if (!CAN_SEE(ch, i) || !condition2 || !condition3) */
|
||||
|
||||
if (!CAN_SEE(ch, i))
|
||||
continue;
|
||||
if (!*buf)
|
||||
snprintf(buf, sizeof(buf), "You see %s", GET_NAME(i));
|
||||
else
|
||||
strncat(buf, GET_NAME(i), sizeof(buf) - strlen(buf) - 1);
|
||||
if (--count > 1)
|
||||
strncat(buf, ", ", sizeof(buf) - strlen(buf) - 1);
|
||||
else if (count == 1)
|
||||
strncat(buf, " and ", sizeof(buf) - strlen(buf) - 1);
|
||||
else {
|
||||
snprintf(buf2, sizeof(buf2), " %s %s.\r\n", how_far[distance], dirs[door]);
|
||||
strncat(buf, buf2, sizeof(buf) - strlen(buf) - 1);
|
||||
}
|
||||
|
||||
}
|
||||
send_to_char(ch, "%s", buf);
|
||||
}
|
||||
|
||||
ACMD(do_scan)
|
||||
{
|
||||
int door;
|
||||
bool found=FALSE;
|
||||
|
||||
int range;
|
||||
int maxrange = 3;
|
||||
|
||||
room_rnum scanned_room = IN_ROOM(ch);
|
||||
|
||||
if (IS_AFFECTED(ch, AFF_BLIND)) {
|
||||
send_to_char(ch, "You can't see a damned thing, you're blind!\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (door = 0; door < DIR_COUNT; door++) {
|
||||
for (range = 1; range<= maxrange; range++) {
|
||||
if (world[scanned_room].dir_option[door] && world[scanned_room].dir_option[door]->to_room != NOWHERE &&
|
||||
!IS_SET(world[scanned_room].dir_option[door]->exit_info, EX_CLOSED) &&
|
||||
!IS_SET(world[scanned_room].dir_option[door]->exit_info, EX_HIDDEN)) {
|
||||
scanned_room = world[scanned_room].dir_option[door]->to_room;
|
||||
if (IS_DARK(scanned_room) && !CAN_SEE_IN_DARK(ch)) {
|
||||
if (world[scanned_room].people)
|
||||
send_to_char(ch, "%s: It's too dark to see, but you can hear shuffling.\r\n", dirs[door]);
|
||||
else
|
||||
send_to_char(ch, "%s: It is too dark to see anything.\r\n", dirs[door]);
|
||||
found=TRUE;
|
||||
} else {
|
||||
if (world[scanned_room].people) {
|
||||
list_scanned_chars(world[scanned_room].people, ch, range - 1, door);
|
||||
found=TRUE;
|
||||
}
|
||||
}
|
||||
} // end of if
|
||||
else
|
||||
break;
|
||||
} // end of range
|
||||
scanned_room = IN_ROOM(ch);
|
||||
} // end of directions
|
||||
if (!found) {
|
||||
send_to_char(ch, "You don't see anything nearby!\r\n");
|
||||
}
|
||||
} // end of do_scan
|
||||
|
|
|
|||
289
src/act.other.c
289
src/act.other.c
|
|
@ -315,84 +315,241 @@ ACMD(do_hide)
|
|||
GET_MOVE(ch) -= 10;
|
||||
}
|
||||
|
||||
/* Perception: scan the room for hidden creatures and objects */
|
||||
ACMD(do_perception)
|
||||
static void remember_scan_target(struct char_data *ch, struct char_data *tch)
|
||||
{
|
||||
struct scan_result_data *node;
|
||||
long uid;
|
||||
|
||||
if (!ch || !tch)
|
||||
return;
|
||||
if (IS_NPC(ch))
|
||||
return;
|
||||
if (!ch->player_specials || ch->player_specials == &dummy_mob)
|
||||
return;
|
||||
|
||||
uid = char_script_id(tch);
|
||||
for (node = GET_SCAN_RESULTS(ch); node; node = node->next) {
|
||||
if (node->target_uid == uid) {
|
||||
node->room = IN_ROOM(ch);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CREATE(node, struct scan_result_data, 1);
|
||||
node->target_uid = uid;
|
||||
node->room = IN_ROOM(ch);
|
||||
node->next = GET_SCAN_RESULTS(ch);
|
||||
GET_SCAN_RESULTS(ch) = node;
|
||||
}
|
||||
|
||||
static void forget_scan_target(struct char_data *ch, struct char_data *tch)
|
||||
{
|
||||
struct scan_result_data **node;
|
||||
long uid;
|
||||
|
||||
if (!ch || !tch)
|
||||
return;
|
||||
if (IS_NPC(ch))
|
||||
return;
|
||||
if (!ch->player_specials || ch->player_specials == &dummy_mob)
|
||||
return;
|
||||
|
||||
uid = char_script_id(tch);
|
||||
for (node = &GET_SCAN_RESULTS(ch); *node; node = &((*node)->next)) {
|
||||
if ((*node)->target_uid == uid) {
|
||||
struct scan_result_data *old = *node;
|
||||
*node = old->next;
|
||||
free(old);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clear_scan_results(struct char_data *ch)
|
||||
{
|
||||
struct scan_result_data *node, *next;
|
||||
|
||||
if (!ch || IS_NPC(ch))
|
||||
return;
|
||||
if (!ch->player_specials || ch->player_specials == &dummy_mob)
|
||||
return;
|
||||
|
||||
for (node = GET_SCAN_RESULTS(ch); node; node = next) {
|
||||
next = node->next;
|
||||
free(node);
|
||||
}
|
||||
|
||||
GET_SCAN_RESULTS(ch) = NULL;
|
||||
}
|
||||
|
||||
bool scan_can_target(struct char_data *ch, struct char_data *tch)
|
||||
{
|
||||
struct scan_result_data *node;
|
||||
long uid;
|
||||
|
||||
if (!ch || !tch)
|
||||
return FALSE;
|
||||
if (IS_NPC(ch))
|
||||
return FALSE;
|
||||
if (!ch->player_specials || ch->player_specials == &dummy_mob)
|
||||
return FALSE;
|
||||
if (!AFF_FLAGGED(ch, AFF_SCAN))
|
||||
return FALSE;
|
||||
|
||||
uid = char_script_id(tch);
|
||||
|
||||
for (node = GET_SCAN_RESULTS(ch); node; node = node->next)
|
||||
if (node->target_uid == uid && node->room == IN_ROOM(ch))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int scan_target_dc(struct char_data *tch)
|
||||
{
|
||||
if (GET_STEALTH_CHECK(tch) <= 0)
|
||||
SET_STEALTH_CHECK(tch, 5);
|
||||
|
||||
/* Give hiders a modest buffer so high skill matters but success remains possible. */
|
||||
return GET_STEALTH_CHECK(tch) + 2;
|
||||
}
|
||||
|
||||
bool scan_confirm_target(struct char_data *ch, struct char_data *tch)
|
||||
{
|
||||
int roll, bonus, total;
|
||||
|
||||
if (!ch || !tch)
|
||||
return FALSE;
|
||||
if (!AFF_FLAGGED(ch, AFF_SCAN))
|
||||
return FALSE;
|
||||
if (!GET_SKILL(ch, SKILL_PERCEPTION))
|
||||
return FALSE;
|
||||
|
||||
bonus = GET_ABILITY_MOD(GET_WIS(ch)) +
|
||||
GET_PROFICIENCY(GET_SKILL(ch, SKILL_PERCEPTION));
|
||||
roll = rand_number(1, 20);
|
||||
total = roll + bonus;
|
||||
|
||||
if (FIGHTING(ch))
|
||||
total -= 4;
|
||||
|
||||
if (total >= scan_target_dc(tch)) {
|
||||
remember_scan_target(ch, tch);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int scan_effect_duration(struct char_data *ch)
|
||||
{
|
||||
int skill = GET_SKILL(ch, SKILL_PERCEPTION);
|
||||
int minutes;
|
||||
|
||||
if (skill < 20)
|
||||
minutes = 15;
|
||||
else if (skill < 40)
|
||||
minutes = 20;
|
||||
else if (skill < 60)
|
||||
minutes = 25;
|
||||
else if (skill < 80)
|
||||
minutes = 30;
|
||||
else
|
||||
minutes = 45;
|
||||
|
||||
/* Affect durations tick once per mud hour (75 seconds). */
|
||||
return MAX(1, (minutes * SECS_PER_REAL_MIN) / SECS_PER_MUD_HOUR);
|
||||
}
|
||||
|
||||
bool perform_scan_sweep(struct char_data *ch)
|
||||
{
|
||||
struct char_data *tch;
|
||||
struct obj_data *obj, *next_obj;
|
||||
int roll, bonus, total;
|
||||
int found_chars = 0, found_objs = 0;
|
||||
bool had_targets = FALSE;
|
||||
bool found_any = FALSE;
|
||||
|
||||
if (ch == NULL || IN_ROOM(ch) == NOWHERE)
|
||||
return FALSE;
|
||||
if (!AFF_FLAGGED(ch, AFF_SCAN))
|
||||
return FALSE;
|
||||
if (!GET_SKILL(ch, SKILL_PERCEPTION))
|
||||
return FALSE;
|
||||
if (AFF_FLAGGED(ch, AFF_BLIND))
|
||||
return FALSE;
|
||||
if (IS_DARK(IN_ROOM(ch)) && !CAN_SEE_IN_DARK(ch))
|
||||
return FALSE;
|
||||
|
||||
for (tch = world[IN_ROOM(ch)].people; tch; tch = tch->next_in_room) {
|
||||
if (tch == ch)
|
||||
continue;
|
||||
if (!AFF_FLAGGED(tch, AFF_HIDE))
|
||||
continue;
|
||||
if (IS_NPC(tch))
|
||||
continue;
|
||||
had_targets = TRUE;
|
||||
}
|
||||
|
||||
if (!had_targets)
|
||||
return FALSE;
|
||||
|
||||
bonus = GET_ABILITY_MOD(GET_WIS(ch)) +
|
||||
GET_PROFICIENCY(GET_SKILL(ch, SKILL_PERCEPTION));
|
||||
roll = rand_number(1, 20);
|
||||
total = roll + bonus;
|
||||
|
||||
if (FIGHTING(ch))
|
||||
total -= 4;
|
||||
|
||||
for (tch = world[IN_ROOM(ch)].people; tch; tch = tch->next_in_room) {
|
||||
if (tch == ch)
|
||||
continue;
|
||||
if (!AFF_FLAGGED(tch, AFF_HIDE))
|
||||
continue;
|
||||
if (IS_NPC(tch))
|
||||
continue;
|
||||
|
||||
if (total >= scan_target_dc(tch)) {
|
||||
send_to_char(ch, "A shadowy figure.\r\n");
|
||||
remember_scan_target(ch, tch);
|
||||
found_any = TRUE;
|
||||
} else {
|
||||
forget_scan_target(ch, tch);
|
||||
}
|
||||
}
|
||||
|
||||
gain_skill(ch, "perception", found_any ? TRUE : FALSE);
|
||||
return found_any;
|
||||
}
|
||||
|
||||
/* Scan: apply a perception-based buff that auto-checks rooms while it lasts */
|
||||
ACMD(do_scan)
|
||||
{
|
||||
struct affected_type af;
|
||||
|
||||
if (!GET_SKILL(ch, SKILL_PERCEPTION)) {
|
||||
send_to_char(ch, "You have no idea how to do that.\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Roll once for this scan (active check) */
|
||||
bonus = GET_ABILITY_MOD(GET_WIS(ch)) +
|
||||
GET_PROFICIENCY(GET_SKILL(ch, SKILL_PERCEPTION));
|
||||
|
||||
roll = rand_number(1, 20);
|
||||
total = roll + bonus;
|
||||
|
||||
/* Optional: it’s harder to actively scan while in melee */
|
||||
if (FIGHTING(ch))
|
||||
total -= 4;
|
||||
|
||||
/* --- Scan characters in the room (PCs & NPCs) --- */
|
||||
for (tch = world[IN_ROOM(ch)].people; tch; tch = tch->next_in_room) {
|
||||
if (tch == ch)
|
||||
continue;
|
||||
if (!AFF_FLAGGED(tch, AFF_HIDE))
|
||||
continue;
|
||||
|
||||
/* Safety default if some legacy code set AFF_HIDE without a stored check */
|
||||
if (GET_STEALTH_CHECK(tch) <= 0)
|
||||
SET_STEALTH_CHECK(tch, 5);
|
||||
|
||||
if (total >= GET_STEALTH_CHECK(tch)) {
|
||||
/* Spotted! Reveal them. */
|
||||
REMOVE_BIT_AR(AFF_FLAGS(tch), AFF_HIDE);
|
||||
SET_STEALTH_CHECK(tch, 0);
|
||||
++found_chars;
|
||||
|
||||
act("You spot $N hiding!", FALSE, ch, 0, tch, TO_CHAR);
|
||||
act("$n seems to look right at you — you've been spotted!", FALSE, ch, 0, tch, TO_VICT);
|
||||
act("$n spots $N hiding nearby!", FALSE, ch, 0, tch, TO_NOTVICT);
|
||||
}
|
||||
if (AFF_FLAGGED(ch, AFF_SCAN)) {
|
||||
affect_from_char(ch, SKILL_PERCEPTION);
|
||||
send_to_char(ch, "You lower your guard and stop scanning the area.\r\n");
|
||||
act("$n relaxes, no longer scanning so intently.", TRUE, ch, 0, 0, TO_ROOM);
|
||||
return;
|
||||
}
|
||||
|
||||
/* --- Scan objects in the room (requires an ITEM_HIDDEN extra flag) --- */
|
||||
for (obj = world[IN_ROOM(ch)].contents; obj; obj = next_obj) {
|
||||
next_obj = obj->next_content;
|
||||
new_affect(&af);
|
||||
af.spell = SKILL_PERCEPTION;
|
||||
af.location = APPLY_NONE;
|
||||
af.modifier = 0;
|
||||
af.duration = scan_effect_duration(ch);
|
||||
memset(af.bitvector, 0, sizeof(af.bitvector));
|
||||
SET_BIT_AR(af.bitvector, AFF_SCAN);
|
||||
affect_to_char(ch, &af);
|
||||
|
||||
/* If you don't have ITEM_HIDDEN yet, add it to your extra flags table and OBJ flag names. */
|
||||
#ifdef ITEM_HIDDEN
|
||||
if (OBJ_FLAGGED(obj, ITEM_HIDDEN)) {
|
||||
/* Simple baseline DC for hidden objects; tune as desired or add per-object difficulty. */
|
||||
int obj_dc = 12;
|
||||
if (FIGHTING(ch)) obj_dc += 2;
|
||||
send_to_char(ch, "You sharpen your senses and begin scanning for hidden threats.\r\n");
|
||||
act("$n studies $s surroundings with a wary gaze.", TRUE, ch, 0, 0, TO_ROOM);
|
||||
|
||||
if (total >= obj_dc) {
|
||||
/* Reveal the object. */
|
||||
REMOVE_BIT_AR(GET_OBJ_EXTRA(obj), ITEM_HIDDEN);
|
||||
++found_objs;
|
||||
|
||||
act("You spot $p tucked out of sight.", FALSE, ch, obj, 0, TO_CHAR);
|
||||
act("$n notices $p tucked out of sight.", FALSE, ch, obj, 0, TO_ROOM);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!found_chars && !found_objs) {
|
||||
send_to_char(ch, "You search carefully but don’t uncover anything hidden.\r\n");
|
||||
gain_skill(ch, "perception", FALSE);
|
||||
} else {
|
||||
gain_skill(ch, "perception", TRUE);
|
||||
}
|
||||
|
||||
/* Small action taxes do disincline players from spamming perception */
|
||||
WAIT_STATE(ch, PULSE_VIOLENCE / 2);
|
||||
GET_MOVE(ch) -= 10;
|
||||
}
|
||||
|
|
@ -1058,4 +1215,4 @@ ACMD(do_gen_tog)
|
|||
send_to_char(ch, "%s", tog_messages[subcmd][TOG_OFF]);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -408,9 +408,20 @@ static void stat_format_char_effects(struct char_data *k, char *buf, size_t buf_
|
|||
if (len)
|
||||
stat_appendf(buf, buf_size, &len, "\n");
|
||||
|
||||
stat_appendf(buf, buf_size, &len, "%s (%dhr)",
|
||||
const char *dur_unit = "hr";
|
||||
int display_dur = aff->duration + 1;
|
||||
|
||||
if (aff->spell == SKILL_PERCEPTION) {
|
||||
/* convert mud-hours -> real minutes (round up) */
|
||||
int total_seconds = display_dur * SECS_PER_MUD_HOUR;
|
||||
display_dur = (total_seconds + SECS_PER_REAL_MIN - 1) / SECS_PER_REAL_MIN;
|
||||
dur_unit = "min";
|
||||
}
|
||||
|
||||
stat_appendf(buf, buf_size, &len, "%s (%d%s)",
|
||||
skill_name(aff->spell),
|
||||
aff->duration + 1);
|
||||
display_dur,
|
||||
dur_unit);
|
||||
|
||||
if (aff->modifier)
|
||||
stat_appendf(buf, buf_size, &len, " %+d %s",
|
||||
|
|
|
|||
|
|
@ -308,8 +308,9 @@ const char *affected_bits[] =
|
|||
"SCUBA",
|
||||
"SNEAK",
|
||||
"HIDE",
|
||||
"UNUSED",
|
||||
"SCAN",
|
||||
"CHARM",
|
||||
"BANDAGED",
|
||||
"\n"
|
||||
};
|
||||
|
||||
|
|
@ -855,4 +856,4 @@ const char *armor_flag_bits[] = {
|
|||
/** Number of defined extra bit descriptions. */
|
||||
extra_bits_count = sizeof(extra_bits) / sizeof(extra_bits[0]) - 1,
|
||||
/** Number of defined wear bit descriptions. */
|
||||
wear_bits_count = sizeof(wear_bits) / sizeof(wear_bits[0]) - 1;
|
||||
wear_bits_count = sizeof(wear_bits) / sizeof(wear_bits[0]) - 1;
|
||||
|
|
|
|||
3
src/db.c
3
src/db.c
|
|
@ -3402,6 +3402,9 @@ void free_char(struct char_data *ch)
|
|||
int i;
|
||||
struct alias_data *a;
|
||||
|
||||
if (!IS_NPC(ch) && ch->player_specials && ch->player_specials != &dummy_mob)
|
||||
clear_scan_results(ch);
|
||||
|
||||
if (ch->player_specials != NULL && ch->player_specials != &dummy_mob) {
|
||||
while ((a = GET_ALIASES(ch)) != NULL) {
|
||||
GET_ALIASES(ch) = (GET_ALIASES(ch))->next;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ static int extractions_pending = 0;
|
|||
static int apply_ac(struct char_data *ch, int eq_pos);
|
||||
static void update_object(struct obj_data *obj, int use);
|
||||
static void affect_modify_ar(struct char_data * ch, byte loc, sbyte mod, int bitv[], bool add);
|
||||
static bool is_shadow_keyword(const char *name);
|
||||
|
||||
char *fname(const char *namelist)
|
||||
{
|
||||
|
|
@ -110,6 +111,13 @@ int isname(const char *str, const char *namelist)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool is_shadow_keyword(const char *name)
|
||||
{
|
||||
if (!name || !*name)
|
||||
return FALSE;
|
||||
return isname(name, "shadow shadowy figure");
|
||||
}
|
||||
|
||||
static void aff_apply_modify(struct char_data *ch, byte loc, sbyte mod, char *msg)
|
||||
{
|
||||
switch (loc) {
|
||||
|
|
@ -264,6 +272,8 @@ void affect_remove(struct char_data *ch, struct affected_type *af)
|
|||
|
||||
affect_modify_ar(ch, af->location, af->modifier, af->bitvector, FALSE);
|
||||
REMOVE_FROM_LIST(af, ch->affected, next);
|
||||
if (af->spell == SKILL_PERCEPTION)
|
||||
clear_scan_results(ch);
|
||||
free(af);
|
||||
affect_total(ch);
|
||||
}
|
||||
|
|
@ -1132,9 +1142,39 @@ struct char_data *get_char_room_vis(struct char_data *ch, char *name, int *numbe
|
|||
}
|
||||
}
|
||||
|
||||
if (match && CAN_SEE(ch, i))
|
||||
if (--(*number) == 0)
|
||||
if (match) {
|
||||
bool can_target = CAN_SEE(ch, i);
|
||||
|
||||
if (!can_target && GET_LEVEL(ch) >= LVL_IMMORT)
|
||||
can_target = TRUE;
|
||||
|
||||
if (!can_target &&
|
||||
AFF_FLAGGED(ch, AFF_SCAN) &&
|
||||
AFF_FLAGGED(i, AFF_HIDE) &&
|
||||
scan_can_target(ch, i)) {
|
||||
can_target = scan_confirm_target(ch, i);
|
||||
}
|
||||
|
||||
if (can_target && --(*number) == 0)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
if ((AFF_FLAGGED(ch, AFF_SCAN) || GET_LEVEL(ch) >= LVL_IMMORT) && is_shadow_keyword(name)) {
|
||||
for (i = world[IN_ROOM(ch)].people; i && *number; i = i->next_in_room) {
|
||||
if (i == ch)
|
||||
continue;
|
||||
if (!AFF_FLAGGED(i, AFF_HIDE))
|
||||
continue;
|
||||
if (GET_LEVEL(ch) < LVL_IMMORT && !scan_can_target(ch, i))
|
||||
continue;
|
||||
|
||||
if (--(*number) == 0) {
|
||||
if (GET_LEVEL(ch) >= LVL_IMMORT || scan_confirm_target(ch, i))
|
||||
return i;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
|
@ -1177,8 +1217,22 @@ struct char_data *get_char_world_vis(struct char_data *ch, char *name, int *numb
|
|||
|
||||
if (!match)
|
||||
continue;
|
||||
if (!CAN_SEE(ch, i))
|
||||
|
||||
bool can_target = CAN_SEE(ch, i);
|
||||
|
||||
if (!can_target && GET_LEVEL(ch) >= LVL_IMMORT)
|
||||
can_target = TRUE;
|
||||
|
||||
if (!can_target &&
|
||||
AFF_FLAGGED(ch, AFF_SCAN) &&
|
||||
AFF_FLAGGED(i, AFF_HIDE) &&
|
||||
scan_can_target(ch, i)) {
|
||||
can_target = scan_confirm_target(ch, i);
|
||||
}
|
||||
|
||||
if (!can_target)
|
||||
continue;
|
||||
|
||||
if (--(*number) != 0)
|
||||
continue;
|
||||
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ cpp_extern const struct command_info cmd_info[] = {
|
|||
{ "pick" , "pi" , POS_STANDING, do_gen_door , 1, SCMD_PICK },
|
||||
{ "page" , "pag" , POS_DEAD , do_page , 1, 0 },
|
||||
{ "pardon" , "pardon" , POS_DEAD , do_wizutil , LVL_GOD, SCMD_PARDON },
|
||||
{ "perception","per" , POS_RESTING , do_perception, 0, 0 },
|
||||
{ "perception","per" , POS_RESTING , do_scan , 0, 0 },
|
||||
{ "plist" , "plist" , POS_DEAD , do_plist , LVL_GOD, 0 },
|
||||
{ "policy" , "pol" , POS_DEAD , do_gen_ps , 0, SCMD_POLICIES },
|
||||
{ "pour" , "pour" , POS_STANDING, do_pour , 0, SCMD_POUR },
|
||||
|
|
@ -263,7 +263,7 @@ cpp_extern const struct command_info cmd_info[] = {
|
|||
|
||||
{ "say" , "s" , POS_RESTING , do_say , 0, 0 },
|
||||
{ "score" , "sc" , POS_DEAD , do_score , 0, 0 },
|
||||
{ "scan" , "sca" , POS_RESTING , do_scan , 0, 0 },
|
||||
{ "scan" , "sca" , POS_RESTING , do_scan , 0, 0 },
|
||||
{ "scopy" , "scopy" , POS_DEAD , do_oasis_copy, LVL_GOD, CON_SEDIT },
|
||||
{ "sit" , "si" , POS_RESTING , do_sit , 0, 0 },
|
||||
{ "'" , "'" , POS_RESTING , do_say , 0, 0 },
|
||||
|
|
|
|||
|
|
@ -298,7 +298,7 @@
|
|||
#define AFF_SCUBA 18 /**< Room for future expansion */
|
||||
#define AFF_SNEAK 19 /**< Char can move quietly */
|
||||
#define AFF_HIDE 20 /**< Char is hidden */
|
||||
#define AFF_FREE 21 /**< Room for future expansion */
|
||||
#define AFF_SCAN 21 /**< Actively scanning for hidden threats */
|
||||
#define AFF_CHARM 22 /**< Char is charmed */
|
||||
#define AFF_BANDAGED 23 /**< Character was bandaged recently */
|
||||
/** Total number of affect flags */
|
||||
|
|
@ -1008,6 +1008,7 @@ struct player_special_data
|
|||
int last_olc_mode; /**< ? Currently Unused ? */
|
||||
char *host; /**< Resolved hostname, or ip, for player. */
|
||||
int buildwalk_sector; /**< Default sector type for buildwalk */
|
||||
struct scan_result_data *scan_results; /**< Hidden figures this player has spotted */
|
||||
};
|
||||
|
||||
/** Special data used by NPCs, not PCs */
|
||||
|
|
@ -1047,6 +1048,12 @@ struct mob_loadout {
|
|||
struct mob_loadout *next;
|
||||
};
|
||||
|
||||
struct scan_result_data {
|
||||
long target_uid; /* char_script_id() value when spotted */
|
||||
room_rnum room; /* room where the target was seen */
|
||||
struct scan_result_data *next;
|
||||
};
|
||||
|
||||
/** Master structure for PCs and NPCs. */
|
||||
struct char_data
|
||||
{
|
||||
|
|
|
|||
|
|
@ -659,6 +659,7 @@ do \
|
|||
#define GET_PREF(ch) ((ch)->pref)
|
||||
/** Get host name or ip of ch. */
|
||||
#define GET_HOST(ch) CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->host))
|
||||
#define GET_SCAN_RESULTS(ch) CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->scan_results))
|
||||
#define GET_LAST_MOTD(ch) CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->saved.lastmotd))
|
||||
#define GET_LAST_NEWS(ch) CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->saved.lastnews))
|
||||
/** Get channel history i for ch. */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue