mirror of
https://github.com/tbamud/tbamud.git
synced 2026-03-18 18:26:33 +01:00
Say and talk update
This commit is contained in:
parent
b883a72bb9
commit
5dcc018fcd
4 changed files with 522 additions and 48 deletions
380
src/act.comm.c
380
src/act.comm.c
|
|
@ -110,38 +110,374 @@ static void to_second_person_self(const char *in, char *out, size_t outlen) {
|
|||
}
|
||||
}
|
||||
|
||||
static void trim_whitespace(char *s) {
|
||||
char *start = s;
|
||||
while (*start && isspace((unsigned char)*start))
|
||||
start++;
|
||||
|
||||
if (start != s)
|
||||
memmove(s, start, strlen(start) + 1);
|
||||
|
||||
size_t len = strlen(s);
|
||||
while (len > 0 && isspace((unsigned char)s[len - 1]))
|
||||
s[--len] = '\0';
|
||||
}
|
||||
|
||||
ACMD(do_say)
|
||||
{
|
||||
skip_spaces(&argument);
|
||||
char *p = argument;
|
||||
char bracket_raw[MAX_INPUT_LENGTH] = "";
|
||||
char paren_raw[MAX_INPUT_LENGTH] = "";
|
||||
char speech[MAX_INPUT_LENGTH];
|
||||
struct targeted_phrase bracket_phrase;
|
||||
struct targeted_phrase paren_phrase;
|
||||
bool has_bracket = FALSE;
|
||||
bool has_paren = FALSE;
|
||||
|
||||
if (!*argument)
|
||||
skip_spaces(&p);
|
||||
|
||||
if (*p == '[') {
|
||||
const char *close = strchr(p, ']');
|
||||
if (!close) {
|
||||
send_to_char(ch, "You need a closing ']'.\r\n");
|
||||
return;
|
||||
}
|
||||
size_t len = (size_t)(close - p - 1);
|
||||
if (len >= sizeof(bracket_raw))
|
||||
len = sizeof(bracket_raw) - 1;
|
||||
strncpy(bracket_raw, p + 1, len);
|
||||
bracket_raw[len] = '\0';
|
||||
trim_whitespace(bracket_raw);
|
||||
p = (char *)close + 1;
|
||||
}
|
||||
|
||||
skip_spaces(&p);
|
||||
|
||||
if (*p == '(') {
|
||||
const char *close = strchr(p, ')');
|
||||
if (!close) {
|
||||
send_to_char(ch, "You need a closing ')'.\r\n");
|
||||
return;
|
||||
}
|
||||
size_t len = (size_t)(close - p - 1);
|
||||
if (len >= sizeof(paren_raw))
|
||||
len = sizeof(paren_raw) - 1;
|
||||
strncpy(paren_raw, p + 1, len);
|
||||
paren_raw[len] = '\0';
|
||||
trim_whitespace(paren_raw);
|
||||
p = (char *)close + 1;
|
||||
}
|
||||
|
||||
skip_spaces(&p);
|
||||
|
||||
if (!*p) {
|
||||
send_to_char(ch, "Yes, but WHAT do you want to say?\r\n");
|
||||
else {
|
||||
char buf[MAX_INPUT_LENGTH + 14], *msg;
|
||||
struct char_data *vict;
|
||||
|
||||
if (CONFIG_SPECIAL_IN_COMM && legal_communication(argument))
|
||||
parse_at(argument);
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "$n\tn says, '%s'", argument);
|
||||
msg = act(buf, FALSE, ch, 0, 0, TO_ROOM | DG_NO_TRIG);
|
||||
strlcpy(speech, p, sizeof(speech));
|
||||
|
||||
for (vict = world[IN_ROOM(ch)].people; vict; vict = vict->next_in_room)
|
||||
if (vict != ch && GET_POS(vict) > POS_SLEEPING)
|
||||
add_history(vict, msg, HIST_SAY);
|
||||
if (CONFIG_SPECIAL_IN_COMM && legal_communication(speech))
|
||||
parse_at(speech);
|
||||
|
||||
if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_NOREPEAT))
|
||||
send_to_char(ch, "%s", CONFIG_OK);
|
||||
else {
|
||||
sprintf(buf, "You say, '%s'", argument);
|
||||
msg = act(buf, FALSE, ch, 0, 0, TO_CHAR | DG_NO_TRIG);
|
||||
add_history(ch, msg, HIST_SAY);
|
||||
if (*bracket_raw) {
|
||||
if (!build_targeted_phrase(ch, bracket_raw, FALSE, &bracket_phrase))
|
||||
return;
|
||||
has_bracket = TRUE;
|
||||
}
|
||||
if (*paren_raw) {
|
||||
if (!build_targeted_phrase(ch, paren_raw, FALSE, &paren_phrase))
|
||||
return;
|
||||
has_paren = TRUE;
|
||||
}
|
||||
|
||||
bool suppress_self = (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_NOREPEAT));
|
||||
bool use_say = (has_bracket || has_paren);
|
||||
|
||||
for (struct char_data *vict = world[IN_ROOM(ch)].people; vict; vict = vict->next_in_room) {
|
||||
bool self = (vict == ch);
|
||||
|
||||
if (self && suppress_self)
|
||||
continue;
|
||||
if (!self && GET_POS(vict) <= POS_SLEEPING)
|
||||
continue;
|
||||
|
||||
char prefix[MAX_STRING_LENGTH] = "";
|
||||
char suffix[MAX_STRING_LENGTH] = "";
|
||||
char first_line[MAX_STRING_LENGTH];
|
||||
char speaker[MAX_INPUT_LENGTH];
|
||||
|
||||
if (has_bracket)
|
||||
render_targeted_phrase(ch, &bracket_phrase, FALSE, vict, prefix, sizeof(prefix));
|
||||
if (has_paren)
|
||||
render_targeted_phrase(ch, &paren_phrase, FALSE, vict, suffix, sizeof(suffix));
|
||||
|
||||
if (self)
|
||||
strlcpy(speaker, "You", sizeof(speaker));
|
||||
else
|
||||
strlcpy(speaker, PERS(ch, vict), sizeof(speaker));
|
||||
|
||||
first_line[0] = '\0';
|
||||
strlcpy(first_line, "", sizeof(first_line));
|
||||
if (*prefix) {
|
||||
char capped[MAX_STRING_LENGTH];
|
||||
strlcpy(capped, prefix, sizeof(capped));
|
||||
CAP(capped);
|
||||
strlcpy(first_line, capped, sizeof(first_line));
|
||||
strlcat(first_line, ", ", sizeof(first_line));
|
||||
strlcat(first_line, speaker, sizeof(first_line));
|
||||
} else {
|
||||
strlcpy(first_line, speaker, sizeof(first_line));
|
||||
}
|
||||
|
||||
strlcat(first_line, (self && use_say) ? " say" : " says", sizeof(first_line));
|
||||
|
||||
if (*suffix) {
|
||||
strlcat(first_line, ", ", sizeof(first_line));
|
||||
strlcat(first_line, suffix, sizeof(first_line));
|
||||
}
|
||||
|
||||
strlcat(first_line, ":", sizeof(first_line));
|
||||
send_to_char(vict, "%s\r\n \"%s\"\r\n", first_line, speech);
|
||||
|
||||
if (!self || !suppress_self) {
|
||||
char hist_buf[MAX_STRING_LENGTH];
|
||||
snprintf(hist_buf, sizeof(hist_buf), "%s\r\n \"%s\"", first_line, speech);
|
||||
add_history(vict, hist_buf, HIST_SAY);
|
||||
}
|
||||
}
|
||||
|
||||
/* Trigger check. */
|
||||
speech_mtrigger(ch, argument);
|
||||
speech_wtrigger(ch, argument);
|
||||
if (suppress_self)
|
||||
send_to_char(ch, "%s", CONFIG_OK);
|
||||
|
||||
speech_mtrigger(ch, speech);
|
||||
speech_wtrigger(ch, speech);
|
||||
}
|
||||
|
||||
ACMD(do_talk)
|
||||
{
|
||||
struct obj_data *furniture = SITTING(ch);
|
||||
int allowed_positions = 0;
|
||||
char *p = argument;
|
||||
char bracket_raw[MAX_INPUT_LENGTH] = "";
|
||||
char paren_raw[MAX_INPUT_LENGTH] = "";
|
||||
struct targeted_phrase bracket_phrase;
|
||||
struct targeted_phrase paren_phrase;
|
||||
bool has_bracket = FALSE, has_paren = FALSE;
|
||||
|
||||
if (!furniture || GET_OBJ_TYPE(furniture) != ITEM_FURNITURE) {
|
||||
send_to_char(ch, "You need to be seated at a piece of furniture to talk there.\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (GET_POS(ch) != POS_SITTING) {
|
||||
send_to_char(ch, "You need to be sitting first.\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
allowed_positions = GET_OBJ_VAL(furniture, VAL_FURN_POSITIONS);
|
||||
if (allowed_positions > 0 && !(allowed_positions & (1 << 1))) {
|
||||
send_to_char(ch, "That furniture doesn't have any seats.\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
skip_spaces(&p);
|
||||
if (*p == '[') {
|
||||
const char *close = strchr(p, ']');
|
||||
if (!close) {
|
||||
send_to_char(ch, "You need a closing ']'.\r\n");
|
||||
return;
|
||||
}
|
||||
size_t len = (size_t)(close - p - 1);
|
||||
if (len >= sizeof(bracket_raw))
|
||||
len = sizeof(bracket_raw) - 1;
|
||||
strncpy(bracket_raw, p + 1, len);
|
||||
bracket_raw[len] = '\0';
|
||||
trim_whitespace(bracket_raw);
|
||||
p = (char *)close + 1;
|
||||
}
|
||||
|
||||
skip_spaces(&p);
|
||||
|
||||
if (*p == '(') {
|
||||
const char *close = strchr(p, ')');
|
||||
if (!close) {
|
||||
send_to_char(ch, "You need a closing ')'.\r\n");
|
||||
return;
|
||||
}
|
||||
size_t len = (size_t)(close - p - 1);
|
||||
if (len >= sizeof(paren_raw))
|
||||
len = sizeof(paren_raw) - 1;
|
||||
strncpy(paren_raw, p + 1, len);
|
||||
paren_raw[len] = '\0';
|
||||
trim_whitespace(paren_raw);
|
||||
p = (char *)close + 1;
|
||||
}
|
||||
|
||||
skip_spaces(&p);
|
||||
|
||||
if (!*p) {
|
||||
send_to_char(ch, "Talk what?\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char speech[MAX_INPUT_LENGTH];
|
||||
strlcpy(speech, p, sizeof(speech));
|
||||
|
||||
if (CONFIG_SPECIAL_IN_COMM && legal_communication(speech))
|
||||
parse_at(speech);
|
||||
|
||||
if (*bracket_raw) {
|
||||
if (!build_targeted_phrase(ch, bracket_raw, FALSE, &bracket_phrase))
|
||||
return;
|
||||
has_bracket = TRUE;
|
||||
}
|
||||
if (*paren_raw) {
|
||||
if (!build_targeted_phrase(ch, paren_raw, FALSE, &paren_phrase))
|
||||
return;
|
||||
has_paren = TRUE;
|
||||
}
|
||||
|
||||
const char *furn_name = (furniture->short_description && *furniture->short_description)
|
||||
? furniture->short_description : "the furniture";
|
||||
|
||||
bool suppress_self = (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_NOREPEAT));
|
||||
bool delivered = FALSE;
|
||||
|
||||
for (struct char_data *tch = OBJ_SAT_IN_BY(furniture); tch; tch = NEXT_SITTING(tch)) {
|
||||
if (tch == ch)
|
||||
continue;
|
||||
if (SITTING(tch) != furniture)
|
||||
continue;
|
||||
if (GET_POS(tch) != POS_SITTING)
|
||||
continue;
|
||||
if (GET_POS(tch) <= POS_SLEEPING)
|
||||
continue;
|
||||
|
||||
char prefix[MAX_STRING_LENGTH] = "";
|
||||
char suffix[MAX_STRING_LENGTH] = "";
|
||||
char first_line[MAX_STRING_LENGTH];
|
||||
const char *speaker = PERS(ch, tch);
|
||||
|
||||
if (has_bracket)
|
||||
render_targeted_phrase(ch, &bracket_phrase, FALSE, tch, prefix, sizeof(prefix));
|
||||
if (has_paren)
|
||||
render_targeted_phrase(ch, &paren_phrase, FALSE, tch, suffix, sizeof(suffix));
|
||||
|
||||
first_line[0] = '\0';
|
||||
if (*prefix) {
|
||||
char capped[MAX_STRING_LENGTH];
|
||||
strlcpy(capped, prefix, sizeof(capped));
|
||||
CAP(capped);
|
||||
strlcpy(first_line, capped, sizeof(first_line));
|
||||
strlcat(first_line, ", ", sizeof(first_line));
|
||||
strlcat(first_line, speaker, sizeof(first_line));
|
||||
} else {
|
||||
strlcpy(first_line, speaker, sizeof(first_line));
|
||||
}
|
||||
|
||||
strlcat(first_line, " says", sizeof(first_line));
|
||||
strlcat(first_line, ", ", sizeof(first_line));
|
||||
if (*suffix) {
|
||||
strlcat(first_line, suffix, sizeof(first_line));
|
||||
strlcat(first_line, ", ", sizeof(first_line));
|
||||
}
|
||||
char locbuf[MAX_INPUT_LENGTH];
|
||||
snprintf(locbuf, sizeof(locbuf), "at %s,", furn_name);
|
||||
strlcat(first_line, locbuf, sizeof(first_line));
|
||||
|
||||
send_to_char(tch, "%s\r\n \"%s\"\r\n", first_line, speech);
|
||||
|
||||
char hist_buf[MAX_STRING_LENGTH];
|
||||
snprintf(hist_buf, sizeof(hist_buf), "%s\r\n \"%s\"", first_line, speech);
|
||||
add_history(tch, hist_buf, HIST_SAY);
|
||||
delivered = TRUE;
|
||||
}
|
||||
|
||||
if (!delivered)
|
||||
send_to_char(ch, "No one else seated there hears you.\r\n");
|
||||
|
||||
if (suppress_self)
|
||||
send_to_char(ch, "%s", CONFIG_OK);
|
||||
else {
|
||||
char prefix[MAX_STRING_LENGTH] = "";
|
||||
char suffix[MAX_STRING_LENGTH] = "";
|
||||
char first_line[MAX_STRING_LENGTH];
|
||||
|
||||
if (has_bracket)
|
||||
render_targeted_phrase(ch, &bracket_phrase, FALSE, ch, prefix, sizeof(prefix));
|
||||
if (has_paren)
|
||||
render_targeted_phrase(ch, &paren_phrase, FALSE, ch, suffix, sizeof(suffix));
|
||||
|
||||
if (*prefix) {
|
||||
char capped[MAX_STRING_LENGTH];
|
||||
strlcpy(capped, prefix, sizeof(capped));
|
||||
CAP(capped);
|
||||
strlcpy(first_line, capped, sizeof(first_line));
|
||||
strlcat(first_line, ", you", sizeof(first_line));
|
||||
} else
|
||||
strlcpy(first_line, "you", sizeof(first_line));
|
||||
|
||||
strlcat(first_line, " say", sizeof(first_line));
|
||||
strlcat(first_line, ", ", sizeof(first_line));
|
||||
if (*suffix) {
|
||||
strlcat(first_line, suffix, sizeof(first_line));
|
||||
strlcat(first_line, ", ", sizeof(first_line));
|
||||
}
|
||||
char locbuf[MAX_INPUT_LENGTH];
|
||||
snprintf(locbuf, sizeof(locbuf), "at %s,", furn_name);
|
||||
strlcat(first_line, locbuf, sizeof(first_line));
|
||||
|
||||
send_to_char(ch, "%s\r\n \"%s\"\r\n", first_line, speech);
|
||||
char hist_buf[MAX_STRING_LENGTH];
|
||||
snprintf(hist_buf, sizeof(hist_buf), "%s\r\n \"%s\"", first_line, speech);
|
||||
add_history(ch, hist_buf, HIST_SAY);
|
||||
}
|
||||
|
||||
/* Notify others in the room (not seated at this furniture) with an action cue. */
|
||||
for (struct char_data *onlooker = world[IN_ROOM(ch)].people; onlooker; onlooker = onlooker->next_in_room) {
|
||||
if (onlooker == ch)
|
||||
continue;
|
||||
if (GET_POS(onlooker) <= POS_SLEEPING)
|
||||
continue;
|
||||
if (SITTING(onlooker) == furniture && GET_POS(onlooker) == POS_SITTING)
|
||||
continue; /* already heard the speech */
|
||||
|
||||
char prefix[MAX_STRING_LENGTH] = "";
|
||||
char suffix[MAX_STRING_LENGTH] = "";
|
||||
char line[MAX_STRING_LENGTH];
|
||||
const char *speaker = PERS(ch, onlooker);
|
||||
|
||||
if (has_bracket)
|
||||
render_targeted_phrase(ch, &bracket_phrase, FALSE, onlooker, prefix, sizeof(prefix));
|
||||
if (has_paren)
|
||||
render_targeted_phrase(ch, &paren_phrase, FALSE, onlooker, suffix, sizeof(suffix));
|
||||
|
||||
line[0] = '\0';
|
||||
if (*prefix) {
|
||||
char capped[MAX_STRING_LENGTH];
|
||||
strlcpy(capped, prefix, sizeof(capped));
|
||||
CAP(capped);
|
||||
strlcpy(line, capped, sizeof(line));
|
||||
strlcat(line, ", ", sizeof(line));
|
||||
strlcat(line, speaker, sizeof(line));
|
||||
} else
|
||||
strlcpy(line, speaker, sizeof(line));
|
||||
|
||||
strlcat(line, " says something at ", sizeof(line));
|
||||
strlcat(line, furn_name, sizeof(line));
|
||||
|
||||
if (*suffix) {
|
||||
strlcat(line, ", ", sizeof(line));
|
||||
strlcat(line, suffix, sizeof(line));
|
||||
}
|
||||
strlcat(line, ".", sizeof(line));
|
||||
|
||||
send_to_char(onlooker, "%s\r\n", line);
|
||||
}
|
||||
|
||||
speech_mtrigger(ch, speech);
|
||||
speech_wtrigger(ch, speech);
|
||||
}
|
||||
|
||||
ACMD(do_ooc)
|
||||
|
|
|
|||
20
src/act.h
20
src/act.h
|
|
@ -20,6 +20,23 @@
|
|||
|
||||
#include "utils.h" /* for the ACMD macro */
|
||||
|
||||
#ifndef MAX_EMOTE_TOKENS
|
||||
#define MAX_EMOTE_TOKENS 16
|
||||
#endif
|
||||
|
||||
struct emote_token {
|
||||
char op;
|
||||
char name[MAX_NAME_LENGTH];
|
||||
struct char_data *tch;
|
||||
struct obj_data *tobj;
|
||||
};
|
||||
|
||||
struct targeted_phrase {
|
||||
char template[MAX_STRING_LENGTH];
|
||||
int token_count;
|
||||
struct emote_token tokens[MAX_EMOTE_TOKENS];
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
* Begin Functions and defines for act.comm.c
|
||||
****************************************************************************/
|
||||
|
|
@ -44,6 +61,9 @@ ACMD(do_page);
|
|||
ACMD(do_reply);
|
||||
ACMD(do_tell);
|
||||
ACMD(do_write);
|
||||
ACMD(do_talk);
|
||||
bool build_targeted_phrase(struct char_data *ch, const char *input, bool allow_actor_at, struct targeted_phrase *phrase);
|
||||
void render_targeted_phrase(struct char_data *actor, const struct targeted_phrase *phrase, bool actor_possessive_for_at, struct char_data *viewer, char *out, size_t outsz);
|
||||
/*****************************************************************************
|
||||
* Begin Functions and defines for act.informative.c
|
||||
****************************************************************************/
|
||||
|
|
|
|||
169
src/act.wizard.c
169
src/act.wizard.c
|
|
@ -589,7 +589,7 @@ static int purge_room(room_rnum room)
|
|||
/* ===================== Emote engine ===================== */
|
||||
|
||||
/* Operators:
|
||||
*
|
||||
*
|
||||
* ~ (name) / target sees "you"
|
||||
* ! him/her/them / target sees "you"
|
||||
* % (name)'s / target sees "your"
|
||||
|
|
@ -601,10 +601,6 @@ static int purge_room(room_rnum room)
|
|||
* @ moves actor name (or actor's possessive for pemote) to that position
|
||||
*/
|
||||
|
||||
#ifndef MAX_EMOTE_TOKENS
|
||||
#define MAX_EMOTE_TOKENS 16
|
||||
#endif
|
||||
|
||||
/* --- Pronoun & string helpers --- */
|
||||
static const char *pron_obj(struct char_data *tch) { /* him/her/them */
|
||||
switch (GET_SEX(tch)) { case SEX_MALE: return "him"; case SEX_FEMALE: return "her"; default: return "them"; }
|
||||
|
|
@ -676,6 +672,15 @@ static void replace_all_tokens(char *hay, size_t haysz, const char *needle, cons
|
|||
strlcpy(hay, work, haysz);
|
||||
}
|
||||
|
||||
static bool is_token_operator(char c) {
|
||||
switch (c) {
|
||||
case '~': case '!': case '%': case '^': case '#':
|
||||
case '&': case '=': case '+': case '@':
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Capitalize the first alphabetic character of every sentence (start and after .?!).
|
||||
Skips any number of spaces and common closers (quotes/brackets) between sentences. */
|
||||
static void capitalize_sentences(char *s) {
|
||||
|
|
@ -762,16 +767,8 @@ static bool resolve_reference(struct char_data *actor,
|
|||
return false;
|
||||
}
|
||||
|
||||
/* --- Token model --- */
|
||||
struct emote_tok {
|
||||
char op; /* one of ~ ! % ^ # & = + or '@' */
|
||||
char name[MAX_NAME_LENGTH]; /* raw token text (empty for '@') */
|
||||
struct char_data *tch; /* resolved character (if any) */
|
||||
struct obj_data *tobj; /* resolved object (if any) */
|
||||
};
|
||||
|
||||
/* Build replacement text for a token as seen by 'viewer'. */
|
||||
static void build_replacement(const struct emote_tok *tok,
|
||||
static void build_replacement(const struct emote_token *tok,
|
||||
struct char_data *actor,
|
||||
struct char_data *viewer,
|
||||
bool actor_possessive_for_at,
|
||||
|
|
@ -867,6 +864,130 @@ static void build_replacement(const struct emote_tok *tok,
|
|||
strlcpy(out, "something", outsz);
|
||||
}
|
||||
|
||||
bool build_targeted_phrase(struct char_data *ch, const char *input, bool allow_actor_at, struct targeted_phrase *phrase) {
|
||||
struct emote_token tokens[MAX_EMOTE_TOKENS];
|
||||
int tokc = 0;
|
||||
char out[MAX_STRING_LENGTH];
|
||||
char working[MAX_STRING_LENGTH];
|
||||
const char *p;
|
||||
|
||||
if (!phrase)
|
||||
return FALSE;
|
||||
|
||||
phrase->template[0] = '\0';
|
||||
phrase->token_count = 0;
|
||||
|
||||
if (!input || !*input)
|
||||
return TRUE;
|
||||
|
||||
strlcpy(working, input, sizeof(working));
|
||||
out[0] = '\0';
|
||||
p = working;
|
||||
|
||||
while (*p) {
|
||||
if (is_token_operator(*p)) {
|
||||
char op = *p++;
|
||||
char name[MAX_NAME_LENGTH];
|
||||
int ni = 0;
|
||||
|
||||
if (op == '@' && !allow_actor_at) {
|
||||
send_to_char(ch, "You can't use '@' in that phrase.\r\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (op != '@') {
|
||||
const char *q = p;
|
||||
|
||||
while (*q && isdigit((unsigned char)*q) && ni < (int)sizeof(name) - 1)
|
||||
name[ni++] = *q++;
|
||||
|
||||
if (ni > 0 && *q == '.' && ni < (int)sizeof(name) - 1)
|
||||
name[ni++] = *q++;
|
||||
|
||||
while (*q && (isalnum((unsigned char)*q) || *q == '_') && ni < (int)sizeof(name) - 1)
|
||||
name[ni++] = *q++;
|
||||
|
||||
name[ni] = '\0';
|
||||
p = q;
|
||||
} else {
|
||||
name[0] = '\0';
|
||||
}
|
||||
|
||||
if (tokc >= MAX_EMOTE_TOKENS) {
|
||||
send_to_char(ch, "That's too many references for one phrase.\r\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
tokens[tokc].op = op;
|
||||
tokens[tokc].name[0] = '\0';
|
||||
tokens[tokc].tch = NULL;
|
||||
tokens[tokc].tobj = NULL;
|
||||
|
||||
if (op != '@') {
|
||||
if (!*name) {
|
||||
send_to_char(ch, "You need to specify who or what you're referencing.\r\n");
|
||||
return FALSE;
|
||||
}
|
||||
strlcpy(tokens[tokc].name, name, sizeof(tokens[tokc].name));
|
||||
if (!resolve_reference(ch, name, &tokens[tokc].tch, &tokens[tokc].tobj)) {
|
||||
send_to_char(ch, "You can't find one of the references here.\r\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
char ph[16];
|
||||
snprintf(ph, sizeof(ph), "$T%d", tokc + 1);
|
||||
strlcat(out, ph, sizeof(out));
|
||||
tokc++;
|
||||
continue;
|
||||
}
|
||||
|
||||
char buf[2] = { *p++, '\0' };
|
||||
strlcat(out, buf, sizeof(out));
|
||||
}
|
||||
|
||||
strlcpy(phrase->template, out, sizeof(phrase->template));
|
||||
phrase->token_count = tokc;
|
||||
for (int i = 0; i < tokc; i++)
|
||||
phrase->tokens[i] = tokens[i];
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void render_targeted_phrase(struct char_data *actor,
|
||||
const struct targeted_phrase *phrase,
|
||||
bool actor_possessive_for_at,
|
||||
struct char_data *viewer,
|
||||
char *out,
|
||||
size_t outsz)
|
||||
{
|
||||
char msg[MAX_STRING_LENGTH];
|
||||
|
||||
if (!out || !phrase) {
|
||||
if (out && outsz > 0)
|
||||
*out = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
if (!phrase->template[0]) {
|
||||
if (outsz > 0)
|
||||
*out = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
strlcpy(msg, phrase->template, sizeof(msg));
|
||||
|
||||
for (int i = 0; i < phrase->token_count; i++) {
|
||||
char token[16], repl[MAX_INPUT_LENGTH];
|
||||
snprintf(token, sizeof(token), "$T%d", i + 1);
|
||||
build_replacement(&phrase->tokens[i], actor, viewer, actor_possessive_for_at, repl, sizeof(repl));
|
||||
replace_all_tokens(msg, sizeof(msg), token, repl);
|
||||
}
|
||||
|
||||
collapse_spaces(msg);
|
||||
strlcpy(out, msg, outsz);
|
||||
}
|
||||
|
||||
static bool hidden_emote_can_view(struct char_data *actor,
|
||||
struct char_data *viewer,
|
||||
int stealth_total) {
|
||||
|
|
@ -894,7 +1015,7 @@ void perform_emote(struct char_data *ch, char *argument, bool possessive, bool h
|
|||
int at_count = 0;
|
||||
int stealth_total = 0;
|
||||
|
||||
struct emote_tok toks[MAX_EMOTE_TOKENS];
|
||||
struct emote_token toks[MAX_EMOTE_TOKENS];
|
||||
int tokc = 0;
|
||||
|
||||
skip_spaces(&argument);
|
||||
|
|
@ -993,6 +1114,12 @@ void perform_emote(struct char_data *ch, char *argument, bool possessive, bool h
|
|||
collapse_spaces(with_placeholders);
|
||||
}
|
||||
|
||||
struct targeted_phrase phrase;
|
||||
strlcpy(phrase.template, with_placeholders, sizeof(phrase.template));
|
||||
phrase.token_count = tokc;
|
||||
for (int i = 0; i < tokc && i < MAX_EMOTE_TOKENS; i++)
|
||||
phrase.tokens[i] = toks[i];
|
||||
|
||||
/* Deliver personalized message to everyone in the room (including actor) */
|
||||
for (struct descriptor_data *d = descriptor_list; d; d = d->next) {
|
||||
if (STATE(d) != CON_PLAYING || !d->character) continue;
|
||||
|
|
@ -1001,17 +1128,7 @@ void perform_emote(struct char_data *ch, char *argument, bool possessive, bool h
|
|||
continue;
|
||||
|
||||
char msg[MAX_STRING_LENGTH];
|
||||
strlcpy(msg, with_placeholders, sizeof(msg));
|
||||
|
||||
bool actor_poss_for_at = possessive;
|
||||
|
||||
/* Replace each $Tn with viewer-specific text */
|
||||
for (int i = 0; i < tokc; i++) {
|
||||
char token[16], repl[MAX_INPUT_LENGTH];
|
||||
snprintf(token, sizeof(token), "$T%d", i + 1);
|
||||
build_replacement(&toks[i], ch, d->character, actor_poss_for_at, repl, sizeof(repl));
|
||||
replace_all_tokens(msg, sizeof(msg), token, repl);
|
||||
}
|
||||
render_targeted_phrase(ch, &phrase, possessive, d->character, msg, sizeof(msg));
|
||||
|
||||
/* Final per-viewer cleanup: spaces + multi-sentence capitalization */
|
||||
collapse_spaces(msg);
|
||||
|
|
|
|||
|
|
@ -293,6 +293,7 @@ cpp_extern const struct command_info cmd_info[] = {
|
|||
{ "switch" , "switch" , POS_DEAD , do_switch , LVL_GOD, 0 },
|
||||
|
||||
{ "tell" , "t" , POS_DEAD , do_tell , LVL_IMMORT, 0 },
|
||||
{ "talk" , "talk" , POS_SITTING , do_talk , 0, 0 },
|
||||
{ "take" , "ta" , POS_RESTING , do_get , 0, 0 },
|
||||
{ "taste" , "tas" , POS_RESTING , do_eat , 0, SCMD_TASTE },
|
||||
{ "teleport" , "tele" , POS_DEAD , do_teleport , LVL_BUILDER, 0 },
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue