#include "kernel.h" #include "sflags.h" #include "sendsys.h" /* Actions, by Alf. * * an extern message is either a char string * or it is a list of structs, defined as follows. */ struct _ext_msg { char code; /* Codes EXT_TNAM..EXT_ONAM uses this form */ char *next; /* Pointer to next part of string. */ }; struct _ext_msg1 { struct _ext_msg e; char *str; /* Code EXT_STRING uses this form */ }; struct _ext_msg2 { struct _ext_msg e; /* Codes EXT_TARGET and EXT_ACTOR uses this form */ char *male_txt; char *female_txt; }; /* code is one of the following: */ #define EXT_STRING 1 /* insert string here */ #define EXT_TARGET 2 /* Select string on psex(target) */ #define EXT_ACTOR 3 /* Select string on psex(actor) */ #define EXT_TNAM 4 /* insert pname(target) here */ #define EXT_ANAM 5 /* insert pname(actor) here */ #define EXT_THIM 6 /* Insert psex(target) ? "her" : "him" here */ #define EXT_AHIM 7 /* Insert psex(actor) ? "her" : "him" here */ #define EXT_THIS 8 /* Insert psex(target) ? "her" : "his" here */ #define EXT_AHIS 9 /* Insert psex(actor) ? "her" : "his" here */ #define EXT_ONAM 10 /* Insert oname(ob2) here if EXTF_OBJ */ #define EXT_MTXT 11 /* Insert user text via %s here */ #define EXT_ERROR ((char *)(-2)) /* Error return from various functions. */ /* struct for the external commands */ typedef struct _ext { struct _ext *next; int flags; char *verb; char *msg_to_all; char *msg_to_me; } EXTERN_CMD_REC; /* These are in addition if the command accept a target */ struct _ext2 { EXTERN_CMD_REC e; char *msg_to_target; char *msg_to_sender; char *msg_to_others; }; #define EXTF_ALL 0x01 #define EXTF_SINGLE 0x02 #define EXTF_HOSTILE 0x04 #define EXTF_ALOOF 0x08 #define EXTF_OBJ 0x10 /* Command takes an object as arg */ #define EXTF_TEXT 0x20 /* Command accepts a string at the end */ #define EXTF_FAR 0x40 /* Target may be in other room */ static void ext_free_msg(char *s); static int ext_get_tok(void); static char *ext_get_itm(void); static char *ext_get_string(void); static char *ext_get_simple(int code); static char *ext_get_mf(int code,int middle,int end, int fla_m,int fla_c); static struct _ext_msg *ext_mk_struct(char *s); static char *ext_get_anything(void); static char *ext_get_msg(int *w,FILE *f,int bsiz,int l, int h, int *mem_used); static char *build_action(char *a); #define EXT_MSG_ALL 0 #define EXT_MSG_ME 1 #define EXT_MSG_TARGET 2 #define EXT_MSG_SENDER 3 #define EXT_MSG_OTHERS 4 #define EXT_ANGLE_OPEN 0x100 /* %< ok? */ #define EXT_ANGLE_MIDDLE 0x200 /* %: ok? */ #define EXT_ANGLE_CLOSE 0x400 /* %> ok? */ #define EXT_SQ_MIDDLE 0x800 /* %/ ok? */ #define EXT_SQ_CLOSE 0x1000 /* %] ok? */ #define EXT_HAT 0x2000 /* %^ or %~ ok? */ #define EXT_T 0x2000 /* %t ok? */ #define EXT_O 0x4000 /* %o ok? */ #define EXT_M 0x8000 /* %m ok? */ static char *ext_msg_names[] = { "all", "me", "target", "sender", "others", TABLE_END }; EXTERN_CMD_REC *externs; static char *buffer; static char *bufp; static int cur_tok; static int ext_who; static int mused; static int ext_lino; static int ext_flags; static char *s_ext[] = { "Flowers", "Pet", "Pray", "Tickle", "Wave", TABLE_END}; /* * Function to free a msg. */ static void ext_free_msg(char *s) { if (s == NULL || s == EXT_ERROR) return; if (*s < ' ' || *s > '~') { switch (((struct _ext_msg *)s)->code) { case EXT_STRING: ext_free_msg(((struct _ext_msg1 *)s)->str); break; case EXT_TARGET: case EXT_ACTOR: ext_free_msg(((struct _ext_msg2 *)s)->male_txt); ext_free_msg(((struct _ext_msg2 *)s)->female_txt); break; case EXT_TNAM: case EXT_ANAM: case EXT_THIM: case EXT_AHIM: case EXT_THIS: case EXT_AHIS: case EXT_ONAM: break; default: mudlog( "Illegal extern code %d\n", ((struct _ext_msg *)s)->code); return; /* Don't free anything */ } ext_free_msg(((struct _ext_msg *)s)->next); /* Free the next part */ } free(s); } static int ext_get_tok(void) { int c; int k; if ((c = *bufp++) == '%') { switch (c = *bufp++) { case 'A': c = 'a'; case 'a': case '[': return cur_tok = 0400 + c; case '%': return cur_tok = c; case '<': k = EXT_ANGLE_OPEN; break; case ':': k = EXT_ANGLE_MIDDLE; break; case '>': k = EXT_ANGLE_CLOSE; break; case '~': case '^': k = EXT_HAT; break; case 'T': c = 't'; case 't': k = EXT_T; break; case '/': k = EXT_SQ_MIDDLE; break; case ']': k = EXT_SQ_CLOSE; break; case 'O': c = 'o'; case 'o': k = EXT_O; break; case 'M': c = 'm'; case 'm': k = EXT_M; break; default: k = 0; } if (k != 0 && (ext_flags & k) != 0) return cur_tok = c + 0400; c = '%'; --bufp; } if (c < ' ' || c > '~') c = 0; return cur_tok = c; } static char *ext_get_itm(void) { char *s; switch (cur_tok) { case 0400 + '<': return ext_get_mf(EXT_TARGET,':', '>',EXT_ANGLE_MIDDLE,EXT_ANGLE_CLOSE); case 0400 + '[': return ext_get_mf(EXT_ACTOR, '/', ']',EXT_SQ_MIDDLE,EXT_SQ_CLOSE); case 0400 + '/': case 0400 + ':': case 0400 + '>': case 0400 + ']': case 0: return NULL; case 0400 + '^': return ext_get_simple(ext_who == EXT_MSG_SENDER? EXT_THIS:EXT_AHIS); case 0400 + '~': return ext_get_simple(ext_who == EXT_MSG_SENDER? EXT_THIM:EXT_AHIM); case 0400 + 'a': return ext_get_simple(EXT_ANAM); case 0400 + 't': return ext_get_simple(EXT_TNAM); case 0400 + 'o': return ext_get_simple(EXT_ONAM); case 0400 + 'm': ext_flags &= ~EXT_M; return ext_get_simple(EXT_MTXT); } return ext_get_string(); } static char *ext_get_string(void) { char b[256]; int c = cur_tok; int ct = 0; while (c >= ' ' && c <= '~') { b[ct++] = c; c = ext_get_tok(); } if (ct == 0) return NULL; mused += ct + 1; b[ct] = '\0'; return COPY(b); } static char *ext_get_simple(int code) { struct _ext_msg *m; (void)ext_get_tok(); m = NEW(struct _ext_msg,1); m->code = code; m->next = NULL; mused += sizeof(struct _ext_msg); return (char *)m; } static char *ext_get_mf(int code,int middle,int end,int fla_m,int fla_c) { struct _ext_msg2 *s; char *m, *f; int flags = ext_flags; (void)ext_get_tok(); ext_flags |= fla_m|fla_c; if ((m = ext_get_anything()) == EXT_ERROR) { ext_flags = flags; return EXT_ERROR; } f = NULL; ext_flags = flags; if (cur_tok == 0400 + middle) { ext_flags |= fla_c; (void)ext_get_tok(); if ((f = ext_get_anything()) == EXT_ERROR) { ext_free_msg(m); ext_flags = flags; return EXT_ERROR; } ext_flags = flags; } if (cur_tok == 0400 + end) (void)ext_get_tok(); s = NEW(struct _ext_msg2,1); ((struct _ext_msg *)s)->next = NULL; ((struct _ext_msg *)s)->code = code; s->male_txt = m; s->female_txt = f; mused += sizeof(struct _ext_msg2); return (char *)s; } static struct _ext_msg *ext_mk_struct(char *s) { struct _ext_msg1 *m; int c; if (s == NULL || s == EXT_ERROR) return (struct _ext_msg *)s; if (*s >= ' ' && *s <= '~') { m = NEW(struct _ext_msg1,1); m->str = s; ((struct _ext_msg *)m)->code = EXT_STRING; ((struct _ext_msg *)m)->next = NULL; mused += sizeof(struct _ext_msg1); return (struct _ext_msg *)m; } c = ((struct _ext_msg *)s)->code; if (c >= EXT_STRING && c <= EXT_ONAM) return (struct _ext_msg *)s; mudlog( "ext_mk_struct: Illegal ext code %d", c); return (struct _ext_msg *)EXT_ERROR; } static char *ext_get_anything(void) { struct _ext_msg *first, *second_last; char *s, *t; if ((s = ext_get_itm()) == NULL || s == EXT_ERROR) return s; if ((t = ext_get_itm()) == EXT_ERROR) { ext_free_msg(s); return EXT_ERROR; } if (t == NULL) return s; /* build a list with s as first and t as last */ second_last = first = ext_mk_struct(s); /* make sure s is a struct */ first->next = t; while ((s = ext_get_itm()) != NULL && s != EXT_ERROR) { /* Make sure last is a struct */ second_last->next = (char *)ext_mk_struct(second_last->next); /* move second_last to point to last */ second_last = (struct _ext_msg *)second_last->next; second_last->next = s; /* append s to the list */ } if (s == EXT_ERROR) { /* Clear the list */ ext_free_msg((char *)first); return EXT_ERROR; } return (char *)first; } static char *ext_get_msg(int *w,FILE *f,int bsiz,int l,int h,int *mem_used) { char *s; int x = *w; int fl = ext_flags; if (bufp == EXT_ERROR) return EXT_ERROR; if (feof(f) || fgets(buffer,bsiz,f) == NULL) return NULL; ++ext_lino; bufp = buffer; if ((s = strchr(bufp,':')) != NULL && s > bufp) { *s = 0; if ((x = tlookup(bufp,ext_msg_names)) < l || x > h) { x = *w; } else { *w = x; bufp = s + 1; } *s = ':'; } if ((ext_who = x) >= EXT_MSG_TARGET) { ext_flags |= EXT_T|EXT_ANGLE_OPEN; } if (x < EXT_MSG_OTHERS) { ext_flags |= EXT_HAT; } mused = 0; (void)ext_get_tok(); if ((s = ext_get_anything()) == EXT_ERROR) { ext_flags = fl; return bufp = EXT_ERROR; } if (cur_tok != 0) { ext_free_msg(s); printf( "Illegal syntax in actions file\n" ); ext_flags = fl; return bufp = EXT_ERROR; } *mem_used += mused; ext_flags = fl; if (s != NULL) ext_flags |= (1 << x); return s; } static void dump_action(EXTERN_CMD_REC *v) { if (v == NULL) return; bprintf( "Data about %s:\n", v->verb); bprintf( "Next verb: %s\n", (v->next == NULL) ? "<none>" : v->next->verb); bprintf( "Flags: " ); if ((v->flags & EXTF_ALL) != 0) bprintf( "a" ); if ((v->flags & EXTF_SINGLE) != 0) bprintf( "s" ); if ((v->flags & EXTF_HOSTILE) != 0) bprintf( "h" ); if ((v->flags & EXTF_ALOOF) != 0) bprintf( "i" ); if ((v->flags & EXTF_FAR) != 0) bprintf( "f" ); if ((v->flags & EXTF_OBJ) != 0) bprintf( "o" ); if ((v->flags & EXTF_TEXT) != 0) bprintf( "t" ); bprintf( "\n" ); if ((v->flags & EXTF_ALL) != 0) { bprintf( "Msg to all: %s\n", build_action(v->msg_to_all)); bprintf( "Msg to me: %s\n", build_action(v->msg_to_me)); } if ((v->flags & EXTF_SINGLE) != 0) { bprintf( "Msg to target: %s\n", build_action(((struct _ext2 *)v)->msg_to_target)); bprintf( "Msg to sender: %s\n", build_action(((struct _ext2 *)v)->msg_to_sender)); if (((struct _ext2 *)v)->msg_to_others != NULL) { bprintf( "Msg to others: %s\n", build_action(((struct _ext2 *)v)->msg_to_others)); } } bprintf( "\n" ); } static void dump_act_vb(char *s) { EXTERN_CMD_REC *v; int i; for (v = externs; v != NULL && !EQ(v->verb,wordbuf); v = v->next); if (v == NULL) { if ((i = tlookup(wordbuf,s_ext)) < 0) { bprintf( "I don't know about any %s action.\n", wordbuf); } else { bprintf( "%s is a special action.\n", s_ext[i]); } } else { dump_action(v); } } int boot_extern(FILE *f, char *fname) { char buff[256]; char *verb; EXTERN_CMD_REC *first = NULL, *last, *this; int flags; int i, j, k, low, high; char *s, *t; int mem_used = 0; int m_used = 0; int lino = 0; char *msgs[5]; buffer = buff; externs = NULL; while (!feof(f) && fgets(buff,sizeof buff,f) != NULL) { ++ext_lino; if (*buff != ':') continue; s = buff; while (*++s == ' ' || *s == '\t'); t = s; while (isalpha(*t)) ++t; *t = 0; if (t == s) { /* No verb given */ printf( "Error in actions file line %d, no verb given.", lino ); continue; } verb = COPY(s); lowercase(verb); m_used = strlen(s) + 1; flags = 0; do { ++t; } while (*t != '\0' && !isalpha(*t)); while (isalpha(*t)) { switch (*t++) { case 'h': case 'H': flags |= EXTF_HOSTILE; break; case 'i': case 'I': flags |= EXTF_ALOOF; break; case 'a': case 'A': flags |= EXTF_ALL; break; case 's': case 'S': flags |= EXTF_SINGLE; break; case 'o': case 'O': flags |= EXTF_OBJ; break; case 't': case 'T': flags |= EXTF_TEXT; break; case 'f': case 'F': flags |= EXTF_FAR; break; } } if ((flags & EXTF_SINGLE) == 0) flags |= EXTF_ALL; low = ((flags & EXTF_ALL) != 0) ? EXT_MSG_ALL : EXT_MSG_TARGET; high = ((flags & EXTF_SINGLE) != 0) ? EXT_MSG_OTHERS : EXT_MSG_ME; ext_flags = 0; if ((flags & EXTF_OBJ) != 0) ext_flags |= EXT_O; for (i = EXT_MSG_ALL; i <= EXT_MSG_OTHERS;) msgs[i++] = NULL; for (i = low; i <= high; i++) { j = i; if ((flags & EXTF_TEXT) != 0) ext_flags |= EXT_M; s = ext_get_msg(&j,f,sizeof buff,low,high,&m_used); if (s == EXT_ERROR) break; if ((t = msgs[j]) != NULL) { printf( "Double definition for msg for verb %s.\n", verb); ext_free_msg(t); } msgs[j] = s; } if (s == EXT_ERROR) { printf( "Error in actions file for verb %s, error in messages.\n", verb); } else { s = NULL; if (low == EXT_MSG_ALL && (ext_flags & 0x03) != 0x03) { printf( "Error in actions file for verb %s, missing ALL messages.\n", verb); s = EXT_ERROR; } else if (high == EXT_MSG_OTHERS && (ext_flags & 0x0c) != 0x0c) { printf("Error in actions file for verb %s, missing TARGET messages.\n", verb); s = EXT_ERROR; } } if (s == EXT_ERROR) { for (i = EXT_MSG_ALL; i <= EXT_MSG_OTHERS; i++) { if ((s = msgs[i]) != NULL) ext_free_msg(s); } free(verb); continue; } if ((ext_flags & 0x0c) == 0x0c) { this = (EXTERN_CMD_REC *)NEW(struct _ext2,1); m_used += sizeof(struct _ext2); ((struct _ext2 *)this)->msg_to_target = msgs[EXT_MSG_TARGET]; ((struct _ext2 *)this)->msg_to_sender = msgs[EXT_MSG_SENDER]; ((struct _ext2 *)this)->msg_to_others = msgs[EXT_MSG_OTHERS]; } else { this = NEW(EXTERN_CMD_REC,1); m_used += sizeof(EXTERN_CMD_REC); } this->next = NULL; this->flags = flags; this->verb = verb; this->msg_to_all = msgs[EXT_MSG_ALL]; this->msg_to_me = msgs[EXT_MSG_ME]; /* dump_action(this); */ if (first == NULL) { first = last = this; } else { last->next = this; last = this; } mem_used += m_used; } externs = first; return mem_used; } static char *ext_copy(char *b,char *m) { struct _ext_msg *mm; static char *n = "<null>"; char *p, *q; char v[50]; if (m == NULL || m == EXT_ERROR) { *b = 0; return b; } if (*m >= ' ' && *m <= '~') return x_strcpy(b,m); p = v; switch (((struct _ext_msg *)m)->code) { case EXT_STRING: p = ((struct _ext_msg1 *)m)->str; break; case EXT_TARGET: p = psex(pl1) ? ((struct _ext_msg2 *)m)->female_txt : ((struct _ext_msg2 *)m)->male_txt; break; case EXT_ACTOR: p = (psex(mynum) ? ((struct _ext_msg2 *)m)->female_txt : ((struct _ext_msg2 *)m)->male_txt); break; case EXT_TNAM: sprintf(p,"\001p%s\003",pname(pl1)); break; case EXT_ANAM: sprintf(p,"\001p%s\003",pname(mynum)); break; case EXT_THIM: p = psex(pl1) ? "her" : "him"; break; case EXT_AHIM: p = psex(mynum) ? "her" : "him"; break; case EXT_THIS: p = psex(pl1) ? "her" : "his"; break; case EXT_AHIS: p = psex(mynum) ? "her" : "his"; break; case EXT_ONAM: p = oname(ob2); break; case EXT_MTXT: p = "%s"; default: return b; } b = x_strcpy(b,p); return ext_copy(b,((struct _ext_msg *)m)->next); } static char *build_act_msg(char *b,char *m) { if (m == NULL || m == EXT_ERROR) { *b = 0; return b; } if (*m >= ' ' && *m <= '~') return x_strcpy(b,m); switch (((struct _ext_msg *)m)->code) { case EXT_STRING: b = x_strcpy(b,((struct _ext_msg1 *)m)->str); break; case EXT_TARGET: *b++ = '%'; *b++ = '<'; b = build_act_msg(b, ((struct _ext_msg2 *)m)->male_txt); *b++ = '%'; *b++ = ':'; b = build_act_msg(b, ((struct _ext_msg2 *)m)->female_txt); *b++ = '%'; *b++ = '>'; break; case EXT_ACTOR: *b++ = '%'; *b++ = '['; b = build_act_msg(b, ((struct _ext_msg2 *)m)->male_txt); *b++ = '%'; *b++ = '/'; b = build_act_msg(b, ((struct _ext_msg2 *)m)->female_txt); *b++ = '%'; *b++ = ']'; break; case EXT_TNAM: *b++ = '%'; *b++ = 't'; break; case EXT_ANAM: *b++ = '%'; *b++ = 'a'; break; case EXT_THIM: case EXT_AHIM: *b++ = '%'; *b++ = '~'; break; case EXT_THIS: case EXT_AHIS: *b++ = '%'; *b++ = '^'; break; case EXT_ONAM: *b++ = '%'; *b++ = 'o'; break; case EXT_MTXT: *b++ = '%'; *b++ = 'm'; break; default: return b; } *b = 0; return build_act_msg(b,((struct _ext_msg *)m)->next); } static char *build_action(char *a) { static char b[256]; char *t; t = build_act_msg(b,a); *t = 0; return b; } /* ** (C) Brian Preble (rassilon@eddie.mit.edu) ** Handles external commands such as Kiss, Hug, Tickle, etc. ** ** Enhancements of Alf. */ int fextern(char *verb) { struct _ext *v; struct _ext *v2 = NULL; char *m; int p; int o; char *t; int a; char b[MAX_COM_LEN]; char b2[MAX_COM_LEN]; char b3[MAX_COM_LEN]; v = externs; verb = strcpy(b,verb); /* Stupid, parse_2, doesn't use vb, but we must give one */ if (!parse_2(1)) return -1; #if 0 bprintf( "fextern(%s) is called, pl1 = %d, ob1 = %d, ob2 = %d.\n", verb, pl1, ob1, ob2); #endif for (; v != NULL; v = v->next) { if (!EQ(verb,v->verb)) continue; #if 0 bprintf( "Found verb.\n" ); dump_action(v); #endif stp = 0; (void)brkword(); if ((v->flags & EXTF_ALL) == 0) { if (pl1 < 0) continue; p = pl1; brkword(); /* skip player */ if ((v->flags & EXTF_OBJ) != 0) { if (ob2 < 0) continue; o = ob2; brkword(); } } else if ((v->flags & EXTF_SINGLE) == 0) { p = -1; if ((v->flags & EXTF_OBJ) != 0) { if (ob1 < 0) continue; o = ob1; brkword(); /* Skip object */ } } else if ((p = pl1) < 0) { if ((v->flags & EXTF_OBJ) != 0) { if (ob1 < 0) continue; o = ob1; brkword(); } } else { brkword(); if ((v->flags & EXTF_OBJ) != 0) { if (ob2 < 0) continue; o = ob2; brkword(); } } if ((v->flags & EXTF_TEXT) != 0) { getreinput(b3); if (EMPTY(b3)) continue; } else { *b3 = '\0'; } ob2 = o; /* Now pl1 >= 0 if target, ob2 >= 0 if object and b3 is !EMPTY if txt */ /* Verb found */ #if 0 bprintf( "Verb satisfy the requirements.\n" ); #endif if (pfighting(mynum) >= 0) { bprintf("Not in a fight!\n"); return 0; } if ((v->flags & EXTF_HOSTILE) != 0 && pl1 >= 0) { if (testpeace(mynum)) { bprintf("Nah, that's violent.\n"); return 0; } } #if 0 /* Why is this here????? -Alf */ if (do_tables(VERB_GO) == 2) return 0; #endif if (p < 0) { (void)ext_copy(b,v->msg_to_all); sprintf(b2,b,b3); sprintf(b, "\001s%%s\003%s\n\003", b2); sillycom(b); (void)ext_copy(b,v->msg_to_me); sprintf(b2,b,b3); bprintf("%s\n", b2); return 0; } if ((v->flags & EXTF_FAR) == 0 && ploc(p) != ploc(mynum)) { bprintf( "%s is not here.\n", psex(pl1) ? "She" : "He"); return 0; } if (p == mynum) { bprintf("Good trick, that.\n"); return 0; } if ((v->flags & EXTF_ALOOF) != 0 && ststflg(p, SFL_ALOOF) && plev(mynum) < LVL_WIZARD) { bprintf("%s thinks %s's too good for mere mortals.\n", pname(p), (psex(p) ? "she" : "he")); return 0; } ext_copy(b2,((struct _ext2 *)v)->msg_to_target); sprintf(b,b2,b3); m = b + strlen(b); strcpy(m,"\n"); send_msg(p,0,LVL_MIN,LVL_MAX,NOBODY,NOBODY,b); if ((m = ((struct _ext2 *)v)->msg_to_others) != NULL) { ext_copy(b2,m); sprintf(b,b2,b3); send_msg(ploc(mynum), 0, pvis(mynum), LVL_MAX, mynum, p, "%s\n", b); } ext_copy(b2,((struct _ext2 *)v)->msg_to_sender); sprintf(b,b2,b3); bprintf("%s\n", b); /* Hostile action? */ if ((v->flags & EXTF_HOSTILE) != 0 && p >= max_players) { hit_player(p, mynum, pwpn(p)); } return 0; } return -1; /* Command not found in extern list */ } /* ** Displays list of external commands such as Kiss, Hug, Tickle, etc. */ int lisextern(void) { char line[80]; int i = -1; char **t; EXTERN_CMD_REC *v; if (brkword() != -1) { dump_act_vb(wordbuf); } else { bprintf("The following actions are defined:\n"); for (v = externs; v != NULL; v = v->next) { ++i; if (i % 9 == 0) bprintf("\n"); strcpy(line,v->verb); *line = toupper(*line); bprintf("%s\t", line); } for (t = s_ext; *t != TABLE_END; ++t) { ++i; if (i % 9 == 0) bprintf("\n"); bprintf("%s%c", *t, t[1] == TABLE_END ? '\n' : '\t'); } bprintf( "\n" ); } }