Change ldesc update

This commit is contained in:
kinther 2025-12-29 10:55:09 -08:00
parent 497218958e
commit be79603e8f
9 changed files with 220 additions and 6 deletions

View file

@ -45,6 +45,7 @@ Features in Miranthas MUD Alpha release:
* Account system for tracking players/characters over long periods of time
* Race/species selection and stat ranges (elves have higher dex, dwarves have higher str, etc)
* Prioritized stats during character generation
* Ability to change ldesc of PC/NPC's in some situations
Features to be implemented in the next few releases:

View file

@ -257,6 +257,7 @@ ACMD(do_group);
ACMD(do_hide);
ACMD(do_listen);
ACMD(do_not_here);
ACMD(do_change);
ACMD(do_report);
ACMD(do_save);
ACMD(do_skills);

View file

@ -569,8 +569,30 @@ static void list_one_char(struct char_data *i, struct char_data *ch)
CCNRM(ch, C_NRM));
}
/* NPCs with a full long description at default position: print that and bail. */
if (IS_NPC(i) && i->player.long_descr && GET_POS(i) == GET_DEFAULT_POS(i)) {
/* Custom ldesc overrides position-based output. */
if (i->char_specials.custom_ldesc && i->player.long_descr) {
if (AFF_FLAGGED(i, AFF_INVISIBLE))
send_to_char(ch, "*");
if (AFF_FLAGGED(ch, AFF_DETECT_ALIGN)) {
if (IS_EVIL(i))
send_to_char(ch, "(Red Aura) ");
else if (IS_GOOD(i))
send_to_char(ch, "(Blue Aura) ");
}
send_to_char(ch, "%s", i->player.long_descr);
if (AFF_FLAGGED(i, AFF_SANCTUARY))
act("...$e glows with a bright light!", FALSE, i, 0, ch, TO_VICT);
if (AFF_FLAGGED(i, AFF_BLIND) && GET_LEVEL(i) < LVL_IMMORT)
act("...$e is groping around blindly!", FALSE, i, 0, ch, TO_VICT);
return;
}
/* Characters with a full long description at default position: print that and bail. */
if (i->player.long_descr && GET_POS(i) == GET_DEFAULT_POS(i)) {
if (AFF_FLAGGED(i, AFF_INVISIBLE))
send_to_char(ch, "*");
@ -892,7 +914,11 @@ static bool look_list_direction_chars(struct char_data *ch, room_rnum room)
if (AFF_FLAGGED(tch, AFF_HIDE)) {
if (CAN_SEE(ch, tch) || look_can_spot_hidden(ch, tch, room)) {
send_to_char(ch, "a shadowy figure\r\n");
char hidden_ldesc[MAX_STRING_LENGTH];
if (build_hidden_ldesc(tch, hidden_ldesc, sizeof(hidden_ldesc)))
send_to_char(ch, "%s", hidden_ldesc);
else
send_to_char(ch, "a shadowy figure\r\n");
found = TRUE;
}
continue;

View file

@ -492,6 +492,7 @@ int do_simple_move(struct char_data *ch, int dir, int need_specials_check)
/* Only here is the move successful *and* complete. Return success for
* calling functions to handle post move operations. */
clear_custom_ldesc(ch);
return (1);
}
@ -1000,6 +1001,7 @@ ACMD(do_stand)
act(self_msg, TRUE, ch, furniture, 0, TO_CHAR);
act(room_msg, TRUE, ch, furniture, 0, TO_ROOM);
GET_POS(ch) = FIGHTING(ch) ? POS_FIGHTING : POS_STANDING;
clear_custom_ldesc(ch);
return;
}
@ -1020,6 +1022,7 @@ ACMD(do_stand)
char_from_furniture(ch);
/* Will be standing after a successful bash and may still be fighting. */
GET_POS(ch) = FIGHTING(ch) ? POS_FIGHTING : POS_STANDING;
clear_custom_ldesc(ch);
break;
case POS_RESTING:
@ -1033,6 +1036,7 @@ ACMD(do_stand)
GET_POS(ch) = POS_STANDING;
/* Were they sitting in something. */
char_from_furniture(ch);
clear_custom_ldesc(ch);
break;
case POS_SLEEPING:
@ -1050,6 +1054,7 @@ ACMD(do_stand)
else
act("$n stops floating around, and puts $s feet on the ground.", TRUE, ch, 0, 0, TO_ROOM);
GET_POS(ch) = POS_STANDING;
clear_custom_ldesc(ch);
break;
}
}
@ -1122,6 +1127,7 @@ ACMD(do_sit)
act(self_msg, TRUE, ch, furniture, 0, TO_CHAR);
act(room_msg, TRUE, ch, furniture, 0, TO_ROOM);
GET_POS(ch) = POS_SITTING;
clear_custom_ldesc(ch);
return;
}
@ -1130,6 +1136,7 @@ ACMD(do_sit)
send_to_char(ch, "You sit down.\r\n");
act("$n sits down.", FALSE, ch, 0, 0, TO_ROOM);
GET_POS(ch) = POS_SITTING;
clear_custom_ldesc(ch);
break;
case POS_SITTING:
send_to_char(ch, "You're sitting already.\r\n");
@ -1141,6 +1148,7 @@ ACMD(do_sit)
else
act("$n stops resting and sits up.", TRUE, ch, 0, 0, TO_ROOM);
GET_POS(ch) = POS_SITTING;
clear_custom_ldesc(ch);
break;
case POS_SLEEPING:
send_to_char(ch, "You have to wake up first.\r\n");
@ -1155,6 +1163,7 @@ ACMD(do_sit)
else
act("$n stops floating around, and sits down.", TRUE, ch, 0, 0, TO_ROOM);
GET_POS(ch) = POS_SITTING;
clear_custom_ldesc(ch);
break;
}
}
@ -1227,6 +1236,7 @@ ACMD(do_rest)
act(self_msg, TRUE, ch, furniture, 0, TO_CHAR);
act(room_msg, TRUE, ch, furniture, 0, TO_ROOM);
GET_POS(ch) = POS_RESTING;
clear_custom_ldesc(ch);
return;
}
@ -1240,6 +1250,7 @@ ACMD(do_rest)
act("$n sits down and rests.", TRUE, ch, 0, 0, TO_ROOM);
}
GET_POS(ch) = POS_RESTING;
clear_custom_ldesc(ch);
break;
case POS_SITTING:
@ -1258,6 +1269,7 @@ ACMD(do_rest)
act("$n rests.", TRUE, ch, 0, 0, TO_ROOM);
}
GET_POS(ch) = POS_RESTING;
clear_custom_ldesc(ch);
break;
case POS_RESTING:
@ -1279,6 +1291,7 @@ ACMD(do_rest)
else
act("$n stops floating around, and rests.", FALSE, ch, 0, 0, TO_ROOM);
GET_POS(ch) = POS_RESTING;
clear_custom_ldesc(ch);
break;
}
}
@ -1332,6 +1345,7 @@ ACMD(do_sleep)
act("You go to sleep on $p.", TRUE, ch, furniture, 0, TO_CHAR);
act("$n lies down and falls asleep on $p.", TRUE, ch, furniture, 0, TO_ROOM);
GET_POS(ch) = POS_SLEEPING;
clear_custom_ldesc(ch);
return;
}
@ -1354,6 +1368,7 @@ ACMD(do_sleep)
act("$n lies down and falls asleep.", TRUE, ch, 0, 0, TO_ROOM);
}
GET_POS(ch) = POS_SLEEPING;
clear_custom_ldesc(ch);
break;
case POS_SLEEPING:
@ -1371,6 +1386,7 @@ ACMD(do_sleep)
else
act("$n stops floating around, and lies down to sleep.", TRUE, ch, 0, 0, TO_ROOM);
GET_POS(ch) = POS_SLEEPING;
clear_custom_ldesc(ch);
break;
}
}

View file

@ -36,6 +36,36 @@
static void print_group(struct char_data *ch);
static void display_group_list(struct char_data * ch);
static bool change_has_emote_tokens(const char *text)
{
for (; text && *text; text++) {
switch (*text) {
case '~': case '!': case '%': case '^':
case '#': case '&': case '=': case '+':
case '@':
return TRUE;
}
}
return FALSE;
}
static bool change_ends_with_punct(const char *text)
{
size_t len = text ? strlen(text) : 0;
if (len == 0)
return FALSE;
return (text[len - 1] == '.' || text[len - 1] == '!' || text[len - 1] == '?');
}
static void change_trim_trailing_spaces(char *text)
{
size_t len = text ? strlen(text) : 0;
while (len > 0 && isspace((unsigned char)text[len - 1])) {
text[len - 1] = '\0';
len--;
}
}
ACMD(do_quit)
{
char first[MAX_INPUT_LENGTH];
@ -182,6 +212,69 @@ ACMD(do_save)
Crash_crashsave(ch);
}
ACMD(do_change)
{
char option[MAX_INPUT_LENGTH];
char suffix[MAX_INPUT_LENGTH];
char base_buf[MAX_INPUT_LENGTH];
char ldesc[MAX_STRING_LENGTH];
char *rest = argument;
const char *base;
rest = one_argument(rest, option);
if (!*option) {
send_to_char(ch, "Usage: change ldesc <string>\r\n");
return;
}
if (!is_abbrev(option, "ldesc")) {
send_to_char(ch, "Unknown change option. Available: ldesc\r\n");
return;
}
skip_spaces(&rest);
if (!*rest) {
send_to_char(ch, "Usage: change ldesc <string>\r\n");
return;
}
if (change_has_emote_tokens(rest)) {
send_to_char(ch, "You can't use emote tokens in your ldesc.\r\n");
return;
}
strlcpy(suffix, rest, sizeof(suffix));
change_trim_trailing_spaces(suffix);
if (!*suffix) {
send_to_char(ch, "Usage: change ldesc <string>\r\n");
return;
}
if (!change_ends_with_punct(suffix))
strlcat(suffix, ".", sizeof(suffix));
base = (GET_SHORT_DESC(ch) && *GET_SHORT_DESC(ch)) ? GET_SHORT_DESC(ch) : GET_NAME(ch);
if (!base || !*base)
base = "someone";
strlcpy(base_buf, base, sizeof(base_buf));
if (*base_buf)
base_buf[0] = UPPER(*base_buf);
snprintf(ldesc, sizeof(ldesc), "%s %s\r\n", base_buf, suffix);
if (ch->player.long_descr) {
if (!IS_NPC(ch) || GET_MOB_RNUM(ch) == NOBODY ||
ch->player.long_descr != mob_proto[GET_MOB_RNUM(ch)].player.long_descr) {
free(ch->player.long_descr);
}
}
ch->player.long_descr = strdup(ldesc);
ch->char_specials.custom_ldesc = TRUE;
send_to_char(ch, "Long description updated.\r\n");
}
/* Generic function for commands which are normally overridden by special
* procedures - i.e., shop commands, mail commands, etc. */
ACMD(do_not_here)
@ -886,7 +979,11 @@ bool perform_scan_sweep(struct char_data *ch)
continue;
if (total >= scan_target_dc(tch)) {
send_to_char(ch, "A shadowy figure.\r\n");
char hidden_ldesc[MAX_STRING_LENGTH];
if (build_hidden_ldesc(tch, hidden_ldesc, sizeof(hidden_ldesc)))
send_to_char(ch, "%s", hidden_ldesc);
else
send_to_char(ch, "A shadowy figure.\r\n");
remember_scan_target(ch, tch);
found_any = TRUE;
} else {

View file

@ -118,6 +118,7 @@ cpp_extern const struct command_info cmd_info[] = {
{ "cast" , "c" , POS_SITTING , do_cast , 1, 0 },
{ "cedit" , "cedit" , POS_DEAD , do_oasis_cedit, LVL_IMPL, 0 },
{ "change" , "chang" , POS_RESTING , do_change , 0, 0 },
{ "changelog", "cha" , POS_DEAD , do_changelog, LVL_IMPL, 0 },
{ "check" , "ch" , POS_STANDING, do_not_here , 1, 0 },
{ "checkload", "checkl" , POS_DEAD , do_checkloadstatus, LVL_GOD, 0 },
@ -483,8 +484,6 @@ void command_interpreter(struct char_data *ch, char *argument)
char *line;
char arg[MAX_INPUT_LENGTH];
REMOVE_BIT_AR(AFF_FLAGS(ch), AFF_HIDE);
/* just drop to next line for hitting CR */
skip_spaces(&argument);
if (!*argument)
@ -500,6 +499,9 @@ void command_interpreter(struct char_data *ch, char *argument)
} else
line = any_one_arg(argument, arg);
if (!is_abbrev(arg, "change"))
REMOVE_BIT_AR(AFF_FLAGS(ch), AFF_HIDE);
/* Since all command triggers check for valid_dg_target before acting, the levelcheck
* here has been removed. Otherwise, find the command. */
{

View file

@ -1021,6 +1021,7 @@ struct char_special_data
byte carry_items; /**< Number of items carried */
int timer; /**< Timer for update */
int stealth_check; /* last rolled Stealth value for Hide; 0 = not hiding/opposed */
bool custom_ldesc; /* temporary ldesc override from change command */
struct char_special_data_saved saved; /**< Constants saved for PCs. */
};

View file

@ -1700,6 +1700,74 @@ const char *get_char_sdesc(const struct char_data *ch)
return "someone";
}
void clear_custom_ldesc(struct char_data *ch)
{
char base_buf[MAX_INPUT_LENGTH];
char ldesc[MAX_STRING_LENGTH];
const char *base;
if (!ch || !ch->char_specials.custom_ldesc)
return;
ch->char_specials.custom_ldesc = FALSE;
if (ch->player.long_descr) {
if (!IS_NPC(ch) || GET_MOB_RNUM(ch) == NOBODY ||
ch->player.long_descr != mob_proto[GET_MOB_RNUM(ch)].player.long_descr) {
free(ch->player.long_descr);
}
ch->player.long_descr = NULL;
}
base = (GET_SHORT_DESC(ch) && *GET_SHORT_DESC(ch)) ? GET_SHORT_DESC(ch) : GET_NAME(ch);
if (!base || !*base)
base = "someone";
strlcpy(base_buf, base, sizeof(base_buf));
if (*base_buf)
base_buf[0] = UPPER(*base_buf);
snprintf(ldesc, sizeof(ldesc), "%s is standing here.\r\n", base_buf);
ch->player.long_descr = strdup(ldesc);
}
bool build_hidden_ldesc(const struct char_data *ch, char *out, size_t outsz)
{
char base_buf[MAX_INPUT_LENGTH];
const char *base;
size_t base_len;
const char *suffix;
if (!out || outsz == 0) return FALSE;
*out = '\0';
if (!ch || !ch->char_specials.custom_ldesc || !ch->player.long_descr)
return FALSE;
if (GET_POS(ch) != GET_DEFAULT_POS(ch))
return FALSE;
base = (GET_SHORT_DESC(ch) && *GET_SHORT_DESC(ch)) ? GET_SHORT_DESC(ch) : GET_NAME(ch);
if (!base || !*base)
base = "someone";
strlcpy(base_buf, base, sizeof(base_buf));
if (*base_buf)
base_buf[0] = UPPER(*base_buf);
base_len = strlen(base_buf);
if (strncmp(ch->player.long_descr, base_buf, base_len) != 0)
return FALSE;
suffix = ch->player.long_descr + base_len;
if (*suffix == ' ')
suffix++;
else
return FALSE;
snprintf(out, outsz, "A shadowy figure %s", suffix);
return TRUE;
}
/* 5e system helpers */
extern const struct armor_slot armor_slots[]; /* in constants.c */

View file

@ -80,6 +80,8 @@ char *right_trim_whitespace(const char *string);
void remove_from_string(char *string, const char *to_remove);
const char *const *obj_value_labels(int item_type);
const char *get_char_sdesc(const struct char_data *ch);
void clear_custom_ldesc(struct char_data *ch);
bool build_hidden_ldesc(const struct char_data *ch, char *out, size_t outsz);
int obj_is_storage(const struct obj_data *obj);
int obj_storage_is_closed(const struct obj_data *obj);
int roll_skill_check(struct char_data *ch, int skillnum, int mode, int *out_d20);