From dd280c1b582b0144ce887a740cedae1a325ce3e2 Mon Sep 17 00:00:00 2001 From: Vatiken Date: Sun, 12 Feb 2012 22:07:50 +0000 Subject: [PATCH] Added protocols,lists and events, and fixed some bugs... refer to changelog. --- changelog | 19 ++++++ src/act.informative.c | 13 ++++- src/act.item.c | 25 ++++---- src/act.offensive.c | 14 +++-- src/act.wizard.c | 32 ++++++++-- src/comm.c | 133 +++++++++++++++++++++++++++++++++++++----- src/constants.c | 1 + src/db.c | 10 ++++ src/dg_event.c | 21 ++++++- src/dg_event.h | 2 + src/ibt.c | 27 +++++++-- src/ibt.h | 1 + src/interpreter.c | 44 ++++++++++++++ src/limits.c | 29 +++++++++ src/modify.c | 18 ++++++ src/modify.h | 2 + src/qedit.c | 46 +++++++-------- src/sedit.c | 4 +- src/shop.c | 28 +++++---- src/spec_procs.c | 2 +- src/structs.h | 9 +++ src/utils.c | 28 ++++++--- 22 files changed, 419 insertions(+), 89 deletions(-) diff --git a/changelog b/changelog index 21eb733..abaa6e5 100644 --- a/changelog +++ b/changelog @@ -35,6 +35,25 @@ export (QQ's a zone into a tarball) Xlist (mlist, olist, rlist, zlist, slist, tlist, qlist) (lots of major bugfixes too) @ +[Feb 12 2012] - Vatiken + bug: do_score, changed level 30 to LVL_IMMORT + idea: Mortals can't see immortals levels + bug: the NOHASSLE flag allows imms to carry unlimited weight + idea: dexterity now affects whether a character gets the first hit + idea: advance to immortal now sets hunger/thirst to -1 + feature: color is now an option on do_show, which shows all 256 color options + feature: active lists has now been added to do_show, under 'stats' + feature: added KaVir's protocol snippet + bug: protocol snippet should now properly detect xterm color + bug: protocol settings should now be preserved after copyover + idea: ibt now time stamps when something is submitted + feature: added a new MUD event system (mud_event.c) + feature: added a display_usage() event, which is basically an event/list tester. + feature: added two new parsing commands to modify.c for converting tabs to @ and back + feature: added a new MUD list system (lists.c) + improve: qedit now uses '\t' instead of '@' to show color + improve: sedit now uses '\t' instead of '@' to show color + issues: may be bugs with strfrmt() while converting '@' to '\t' [Feb 04 2012] - Vatiken Feature: Added 'Experience' and 'Thaco' to the do_show() command. Bug Fix: Nipped a bug where shopkeepers weren't sending tells. diff --git a/src/act.informative.c b/src/act.informative.c index b59c566..9b7de6c 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -20,6 +20,7 @@ #include "screen.h" #include "constants.h" #include "dg_scripts.h" +#include "mud_event.h" #include "mail.h" /**< For the has_mail function */ #include "act.h" #include "class.h" @@ -808,7 +809,7 @@ ACMD(do_score) send_to_char(ch, "You have %d exp, %d gold coins, and %d questpoints.\r\n", GET_EXP(ch), GET_GOLD(ch), GET_QUESTPOINTS(ch)); - if (GET_LEVEL(ch) < 30) + if (GET_LEVEL(ch) < LVL_IMMORT) send_to_char(ch, "You need %d exp to reach your next level.\r\n", level_exp(GET_CLASS(ch), GET_LEVEL(ch) + 1) - GET_EXP(ch)); @@ -1262,11 +1263,19 @@ ACMD(do_who) CCNRM(ch, C_SPR), ((!(++num_can_see % 4)) ? "\r\n" : "")); } else { num_can_see++; - send_to_char(ch, "%s[%2d %s] %s%s%s%s", + if (GET_LEVEL(tch) >= LVL_GOD) { + send_to_char(ch, "%s%s%s%s%s", + (GET_LEVEL(tch) >= LVL_IMMORT ? CCYEL(ch, C_SPR) : ""), + GET_NAME(tch), (*GET_TITLE(tch) ? " " : ""), GET_TITLE(tch), + CCNRM(ch, C_SPR)); + } else { + send_to_char(ch, "%s[%2d %s] %s%s%s%s", (GET_LEVEL(tch) >= LVL_IMMORT ? CCYEL(ch, C_SPR) : ""), GET_LEVEL(tch), CLASS_ABBR(tch), GET_NAME(tch), (*GET_TITLE(tch) ? " " : ""), GET_TITLE(tch), CCNRM(ch, C_SPR)); + } + if (GET_INVIS_LEV(tch)) send_to_char(ch, " (i%d)", GET_INVIS_LEV(tch)); diff --git a/src/act.item.c b/src/act.item.c index 41b2c78..6d183e6 100644 --- a/src/act.item.c +++ b/src/act.item.c @@ -161,19 +161,24 @@ ACMD(do_put) static int can_take_obj(struct char_data *ch, struct obj_data *obj) { - if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch)) { - act("$p: you can't carry that many items.", FALSE, ch, obj, 0, TO_CHAR); - return (0); - } else if ((IS_CARRYING_W(ch) + GET_OBJ_WEIGHT(obj)) > CAN_CARRY_W(ch)) { - act("$p: you can't carry that much weight.", FALSE, ch, obj, 0, TO_CHAR); - return (0); - } else if (!(CAN_WEAR(obj, ITEM_WEAR_TAKE))) { - act("$p: you can't take that!", FALSE, ch, obj, 0, TO_CHAR); - return (0); - } else if (OBJ_SAT_IN_BY(obj)){ + if (!PRF_FLAGGED(ch, PRF_NOHASSLE)) { + if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch)) { + act("$p: you can't carry that many items.", FALSE, ch, obj, 0, TO_CHAR); + return (0); + } else if ((IS_CARRYING_W(ch) + GET_OBJ_WEIGHT(obj)) > CAN_CARRY_W(ch)) { + act("$p: you can't carry that much weight.", FALSE, ch, obj, 0, TO_CHAR); + return (0); + } else if (!(CAN_WEAR(obj, ITEM_WEAR_TAKE))) { + act("$p: you can't take that!", FALSE, ch, obj, 0, TO_CHAR); + return (0); + } + } + + if (OBJ_SAT_IN_BY(obj)){ act("It appears someone is sitting on $p..", FALSE, ch, obj, 0, TO_CHAR); return (0); } + return (1); } diff --git a/src/act.offensive.c b/src/act.offensive.c index 4c3dbe7..e47ba69 100644 --- a/src/act.offensive.c +++ b/src/act.offensive.c @@ -84,12 +84,14 @@ ACMD(do_hit) if (!CONFIG_PK_ALLOWED && !IS_NPC(vict) && !IS_NPC(ch)) check_killer(ch, vict); - if ((GET_POS(ch) == POS_STANDING) && (vict != FIGHTING(ch))) { - hit(ch, vict, TYPE_UNDEFINED); - WAIT_STATE(ch, PULSE_VIOLENCE + 2); - } else - send_to_char(ch, "You do the best you can!\r\n"); - } + if ((GET_POS(ch) == POS_STANDING) && (vict != FIGHTING(ch))) { + if (GET_DEX(ch) > GET_DEX(vict) || (GET_DEX(ch) == GET_DEX(vict) && rand_number(1, 2) == 1)) /* if faster */ + hit(ch, vict, TYPE_UNDEFINED); /* first */ + else hit(vict, ch, TYPE_UNDEFINED); /* or the victim is first */ + WAIT_STATE(ch, PULSE_VIOLENCE + 2); + } else + send_to_char(ch, "You're fighting the best you can!\r\n"); + } } ACMD(do_kill) diff --git a/src/act.wizard.c b/src/act.wizard.c index 474f1bf..5f045eb 100644 --- a/src/act.wizard.c +++ b/src/act.wizard.c @@ -1546,6 +1546,9 @@ ACMD(do_advance) for (i = 1; i <= MAX_SKILLS; i++) SET_SKILL(victim, i, 100); GET_OLC_ZONE(victim) = NOWHERE; + GET_COND(victim, HUNGER) = -1; + GET_COND(victim, THIRST) = -1; + GET_COND(victim, DRUNK) = -1; } gain_exp_regardless(victim, level_exp(GET_CLASS(victim), newlevel) - GET_EXP(victim)); @@ -2459,7 +2462,9 @@ ACMD(do_show) struct obj_data *obj; struct descriptor_data *d; char field[MAX_INPUT_LENGTH], value[MAX_INPUT_LENGTH], - arg[MAX_INPUT_LENGTH], buf[MAX_STRING_LENGTH]; + arg[MAX_INPUT_LENGTH], buf[MAX_STRING_LENGTH], temp[MAX_STRING_LENGTH]; + int r, g, b; + char colour[16]; struct show_struct { const char *cmd; @@ -2477,7 +2482,8 @@ ACMD(do_show) { "houses", LVL_IMMORT }, { "snoop", LVL_IMMORT }, /* 10 */ { "thaco", LVL_IMMORT }, - { "experience", LVL_IMMORT }, + { "exp", LVL_IMMORT }, + { "colour", LVL_IMMORT }, { "\n", 0 } }; @@ -2617,7 +2623,8 @@ ACMD(do_show) " %5d rooms %5d zones\r\n" " %5d triggers %5d shops\r\n" " %5d large bufs %5d autoquests\r\n" - " %5d buf switches %5d overflows\r\n", + " %5d buf switches %5d overflows\r\n" + " %5d lists\r\n", i, con, top_of_p_table + 1, j, top_of_mobt + 1, @@ -2625,7 +2632,7 @@ ACMD(do_show) top_of_world + 1, top_of_zone_table + 1, top_of_trigt + 1, top_shop + 1, buf_largecount, total_quests, - buf_switches, buf_overflows + buf_switches, buf_overflows, global_lists->iSize ); break; @@ -2742,6 +2749,21 @@ ACMD(do_show) page_string(ch->desc, buf, TRUE); break; + case 13: + len = strlcpy(buf, "Colours\r\n--------------------------\r\n", sizeof(buf)); + k = 0; + for (r = 0; r < 6; r++) + for (g = 0; g < 6; g++) + for (b = 0; b < 6; b++) { + sprintf(colour, "F%d%d%d", r, g, b); + nlen = snprintf(buf + len, sizeof(buf) - len, "%s%s%s", ColourRGB(ch->desc, colour), colour, ++k % 6 == 0 ? "\tn\r\n" : " "); + if (len + nlen >= sizeof(buf)) + break; + len += nlen; + } + page_string(ch->desc, buf, TRUE); + break; + /* show what? */ default: send_to_char(ch, "Sorry, I don't understand that.\r\n"); @@ -4135,7 +4157,7 @@ ACMD(do_copyover) write_to_descriptor (d->descriptor, "\n\rSorry, we are rebooting. Come back in a few minutes.\n\r"); close_socket (d); /* throw'em out */ } else { - fprintf (fp, "%d %ld %s %s\n", d->descriptor, GET_PREF(och), GET_NAME(och), d->host); + fprintf (fp, "%d %ld %s %s %s\n", d->descriptor, GET_PREF(och), GET_NAME(och), d->host, CopyoverGet(d)); /* save och */ GET_LOADROOM(och) = GET_ROOM_VNUM(IN_ROOM(och)); Crash_rentsave(och,0); diff --git a/src/comm.c b/src/comm.c index c8a372b..efa2b1e 100644 --- a/src/comm.c +++ b/src/comm.c @@ -81,6 +81,7 @@ #include "modify.h" #include "quest.h" #include "ibt.h" /* for free_ibt_lists */ +#include "mud_event.h" #ifndef INVALID_SOCKET #define INVALID_SOCKET (-1) @@ -164,6 +165,8 @@ static RETSIGTYPE websterlink(int sig); static size_t proc_colors(char *txt, size_t maxlen, int parse); static void handle_webster_file(); +static void msdp_update(void); /* KaVir plugin*/ + /* externally defined functions, used locally */ #ifdef __CXREF__ #undef FD_ZERO @@ -390,7 +393,7 @@ void copyover_recover() { struct descriptor_data *d; FILE *fp; - char host[1024]; + char host[1024], guiopt[1024]; int desc, i, player_i; bool fOld; char name[MAX_INPUT_LENGTH]; @@ -414,7 +417,7 @@ void copyover_recover() for (;;) { fOld = TRUE; - i = fscanf (fp, "%d %ld %s %s\n", &desc, &pref, name, host); + i = fscanf (fp, "%d %ld %s %s %s\n", &desc, &pref, name, host, guiopt); if (desc == -1) break; @@ -435,6 +438,8 @@ void copyover_recover() d->connected = CON_CLOSE; + CopyoverSet(d,guiopt); + /* Now, find the pfile */ CREATE(d->character, struct char_data, 1); clear_char(d->character); @@ -815,8 +820,12 @@ void game_loop(socket_t local_mother_desc) for (d = descriptor_list; d; d = next_d) { next_d = d->next; if (FD_ISSET(d->descriptor, &input_set)) + { + if ( d->pProtocol != NULL ) /* KaVir's plugin */ + d->pProtocol->WriteOOB = 0; /* KaVir's plugin */ if (process_input(d) < 0) close_socket(d); + } } /* Process commands we just read from process_input */ @@ -950,6 +959,7 @@ void heartbeat(int heart_pulse) script_trigger_check(); if (!(heart_pulse % PASSES_PER_SEC)) { /* EVERY second */ + msdp_update(); next_tick--; } @@ -1337,6 +1347,12 @@ size_t vwrite_to_output(struct descriptor_data *t, const char *format, va_list a wantsize = size = vsnprintf(txt, sizeof(txt), format, args); if (t->character) wantsize = size = proc_colors(txt, sizeof(txt), COLOR_ON(t->character)); + + strcpy(txt, ProtocolOutput( t, txt, (int*)&wantsize )); /* <--- Add this line */ + size = wantsize; /* <--- Add this line */ + if ( t->pProtocol->WriteOOB > 0 ) /* <--- Add this line */ + --t->pProtocol->WriteOOB; /* <--- Add this line */ + /* If exceeding the size of the buffer, truncate it for the overflow message */ if (size < 0 || wantsize >= sizeof(txt)) { size = sizeof(txt) - 1; @@ -1494,11 +1510,14 @@ static void init_descriptor (struct descriptor_data *newd, int desc) *newd->output = '\0'; newd->bufptr = 0; newd->has_prompt = 1; /* prompt is part of greetings */ - STATE(newd) = CON_GET_NAME; + STATE(newd) = CON_GET_PROTOCOL; CREATE(newd->history, char *, HISTORY_SIZE); if (++last_desc == 1000) last_desc = 1; newd->desc_num = last_desc; + newd->pProtocol = ProtocolCreate(); /* KaVir's plugin*/ + newd->events = create_list(); + } static int new_descriptor(socket_t s) @@ -1509,8 +1528,7 @@ static int new_descriptor(socket_t s) struct descriptor_data *newd; struct sockaddr_in peer; struct hostent *from; - char greet_copy[MAX_STRING_LENGTH]; - + /* accept the new connection */ i = sizeof(peer); if ((desc = accept(s, (struct sockaddr *) &peer, &i)) == INVALID_SOCKET) { @@ -1564,18 +1582,18 @@ static int new_descriptor(socket_t s) } /* initialize descriptor data */ - init_descriptor(newd, desc); + init_descriptor(newd, desc); /* prepend to list */ newd->next = descriptor_list; descriptor_list = newd; - /* This is where the greetings are actually sent to the new player */ - /* Adjusted by Jamdog to show color codes on the greetings page */ - *greet_copy = '\0'; - sprintf(greet_copy, "%s", GREETINGS); - proc_colors(greet_copy, MAX_STRING_LENGTH, TRUE); - write_to_output(newd, "%s", greet_copy); + /* Attach Event */ + attach_mud_event(get_protocols, new_mud_event(EVENT_DESC, newd, NULL), 1.5 * PASSES_PER_SEC); + + /* KaVir's plugin*/ + write_to_output(newd, "Attempting to Detect Client, Please Wait...\r\n"); + ProtocolNegotiate(newd); return (0); } @@ -1605,8 +1623,11 @@ static int process_output(struct descriptor_data *t) if (STATE(t) == CON_PLAYING && t->character && !IS_NPC(t->character) && !PRF_FLAGGED(t->character, PRF_COMPACT)) strcat(osb, "\r\n"); /* strcpy: OK (osb:MAX_SOCK_BUF-2 reserves space) */ + if (!t->pProtocol->WriteOOB) + { /* add a prompt */ strcat(i, make_prompt(t)); /* strcpy: OK (i:MAX_SOCK_BUF reserves space) */ + } /* now, send the output. If this is an 'interruption', use the prepended * CRLF, otherwise send the straight output sans CRLF. */ @@ -1861,6 +1882,9 @@ static int process_input(struct descriptor_data *t) char *ptr, *read_point, *write_point, *nl_pos = NULL; char tmp[MAX_INPUT_LENGTH]; + static char read_buf[MAX_PROTOCOL_BUFFER]; /* KaVir's plugin */ + read_buf[0] = '\0'; /* KaVir's plugin */ + /* first, find the point where we left off reading data */ buf_length = strlen(t->inbuf); read_point = t->inbuf + buf_length; @@ -1872,7 +1896,14 @@ static int process_input(struct descriptor_data *t) return (-1); } - bytes_read = perform_socket_read(t->descriptor, read_point, space_left); + bytes_read = perform_socket_read(t->descriptor, read_buf, MAX_PROTOCOL_BUFFER); + + if ( bytes_read >= 0 ) + { + read_buf[bytes_read] = '\0'; + ProtocolInput( t, read_buf, bytes_read, t->inbuf ); + bytes_read = strlen(t->inbuf); + } if (bytes_read < 0) /* Error, disconnect them. */ return (-1); @@ -2122,6 +2153,19 @@ void close_socket(struct descriptor_data *d) free(d->showstr_head); if (d->showstr_count) free(d->showstr_vector); + + /* KaVir's plugin*/ + ProtocolDestroy( d->pProtocol ); + + /* Mud Events */ + if (d->events->iSize > 0) { + struct event * pEvent; + + while ((pEvent = simple_list(d->events)) != NULL) + event_cancel(pEvent); + } + + free_list(d->events); /*. Kill any OLC stuff .*/ switch (d->connected) { @@ -2794,3 +2838,66 @@ static void handle_webster_file(void) { send_to_char(ch, "You get this feedback from Merriam-Webster:\r\n"); page_string(ch->desc, retval, 1); } + + +/* KaVir's plugin*/ +static void msdp_update( void ) +{ + struct descriptor_data *d; + int PlayerCount = 0; + char buf[MAX_STRING_LENGTH]; + extern const char *pc_class_types[]; + + for (d = descriptor_list; d; d = d->next) + { + struct char_data *ch = d->character; + if ( ch && !IS_NPC(ch) && d->connected == CON_PLAYING ) + { + struct char_data *pOpponent = FIGHTING(ch); + ++PlayerCount; + + MSDPSetString( d, eMSDP_CHARACTER_NAME, GET_NAME(ch) ); + MSDPSetNumber( d, eMSDP_ALIGNMENT, GET_ALIGNMENT(ch) ); + MSDPSetNumber( d, eMSDP_EXPERIENCE, GET_EXP(ch) ); + + MSDPSetNumber( d, eMSDP_HEALTH, GET_HIT(ch) ); + MSDPSetNumber( d, eMSDP_HEALTH_MAX, GET_MAX_HIT(ch) ); + MSDPSetNumber( d, eMSDP_LEVEL, GET_LEVEL(ch) ); + + sprinttype( ch->player.chclass, pc_class_types, buf, sizeof(buf) ); + MSDPSetString( d, eMSDP_CLASS, buf ); + + MSDPSetNumber( d, eMSDP_MANA, GET_MANA(ch) ); + MSDPSetNumber( d, eMSDP_MANA_MAX, GET_MAX_MANA(ch) ); + MSDPSetNumber( d, eMSDP_WIMPY, GET_WIMP_LEV(ch) ); + MSDPSetNumber( d, eMSDP_MONEY, GET_GOLD(ch) ); + MSDPSetNumber( d, eMSDP_MOVEMENT, GET_MOVE(ch) ); + MSDPSetNumber( d, eMSDP_MOVEMENT_MAX, GET_MAX_MOVE(ch) ); + MSDPSetNumber( d, eMSDP_AC, compute_armor_class(ch) ); + + /* This would be better moved elsewhere */ + if ( pOpponent != NULL ) + { + int hit_points = (GET_HIT(pOpponent) * 100) / GET_MAX_HIT(pOpponent); + MSDPSetNumber( d, eMSDP_OPPONENT_HEALTH, hit_points ); + MSDPSetNumber( d, eMSDP_OPPONENT_HEALTH_MAX, 100 ); + MSDPSetNumber( d, eMSDP_OPPONENT_LEVEL, GET_LEVEL(pOpponent) ); + MSDPSetString( d, eMSDP_OPPONENT_NAME, PERS(pOpponent, ch) ); + } + else /* Clear the values */ + { + MSDPSetNumber( d, eMSDP_OPPONENT_HEALTH, 0 ); + MSDPSetNumber( d, eMSDP_OPPONENT_LEVEL, 0 ); + MSDPSetString( d, eMSDP_OPPONENT_NAME, "" ); + } + + MSDPUpdate( d ); + } + + /* Ideally this should be called once at startup, and again whenever + * someone leaves or joins the mud. But this works, and it keeps the + * snippet simple. Optimise as you see fit. + */ + MSSPSetPlayers( PlayerCount ); + } +} diff --git a/src/constants.c b/src/constants.c index 6223784..125792c 100644 --- a/src/constants.c +++ b/src/constants.c @@ -320,6 +320,7 @@ const char *connected_types[] = { "Quest edit", "Preference edit", "IBT edit", + "Protocol Detection", "\n" }; diff --git a/src/db.c b/src/db.c index 25804f9..6b077f8 100644 --- a/src/db.c +++ b/src/db.c @@ -37,6 +37,7 @@ #include "shop.h" #include "quest.h" #include "ibt.h" +#include "mud_event.h" #include /* declarations of most of the 'global' variables */ @@ -628,6 +629,9 @@ void destroy_db(void) /* Events */ event_free_all(); + /* Lists */ + free_list(world_events); + } /* body of the booting system */ @@ -639,6 +643,12 @@ void boot_db(void) log("Resetting the game time:"); reset_time(); + + log("Initialize Global Lists"); + global_lists = create_list(); + + log("Initializing Events"); + init_events(); log("Reading news, credits, help, ihelp, bground, info & motds."); file_to_string_alloc(NEWS_FILE, &news); diff --git a/src/dg_event.c b/src/dg_event.c index 99e9014..3245ce3 100644 --- a/src/dg_event.c +++ b/src/dg_event.c @@ -24,7 +24,7 @@ #include "dg_event.h" #include "constants.h" #include "comm.h" /* For access to the game pulse */ - +#include "mud_event.h" /*************************************************************************** * Begin mud specific event queue functions @@ -65,6 +65,7 @@ struct event *event_create(EVENTFUNC(*func), void *event_obj, long when) new_event->func = func; new_event->event_obj = event_obj; new_event->q_el = queue_enq(event_q, new_event, when + pulse); + new_event->isMudEvent = FALSE; return new_event; } @@ -85,10 +86,23 @@ void event_cancel(struct event *event) queue_deq(event_q, event->q_el); if (event->event_obj) - free(event->event_obj); + cleanup_event_obj(event); + free(event); } +/* The memory freeing routine tied into the mud event system */ +void cleanup_event_obj(struct event *event) +{ + struct mud_event_data * mud_event; + + if (event->isMudEvent) { + mud_event = (struct mud_event_data *) event->event_obj; + free_mud_event(mud_event); + } else + free(event->event_obj); +} + /** Process any events whose time has come. Should be called from, and at, every * pulse of heartbeat. Re-enqueues multi-use events. */ @@ -314,7 +328,8 @@ void queue_free(struct dg_queue *q) if ((event = (struct event *) qe->data) != NULL) { if (event->event_obj) - free(event->event_obj); + cleanup_event_obj(event); + free(event); } free(qe); diff --git a/src/dg_event.h b/src/dg_event.h index 8f82a44..ee36e47 100644 --- a/src/dg_event.h +++ b/src/dg_event.h @@ -33,6 +33,7 @@ struct event { EVENTFUNC(*func); /**< The function called when this event comes up. */ void *event_obj; /**< event_obj is passed to func when func is called */ struct q_element *q_el; /**< Where this event is located in the queue */ + bool isMudEvent; /**< used by the memory routines */ }; /************************************************************************** * End event structures and defines. @@ -67,6 +68,7 @@ void event_cancel(struct event *event); void event_process(void); long event_time(struct event *event); void event_free_all(void); +void cleanup_event_obj(struct event *event); /* - queues - function protos need by other modules */ struct dg_queue *queue_init(void); diff --git a/src/ibt.c b/src/ibt.c index cd2cb4c..10a81b5 100755 --- a/src/ibt.c +++ b/src/ibt.c @@ -79,6 +79,7 @@ static IBT_DATA *new_ibt(void) ibtData->level = 0; ibtData->id_num = NOBODY; ibtData->room = NOWHERE; + ibtData->dated = 0; for (i=0; iflags[i] = 0; @@ -117,7 +118,7 @@ static void free_ibt_list(IBT_DATA *first_ibt, IBT_DATA *last_ibt) static IBT_DATA *read_ibt( char *filename, FILE *fp ) { IBT_DATA *ibtData; - char *word, *id_num=NULL; + char *word, *id_num=NULL, *dated=NULL; char buf[MAX_STRING_LENGTH]; bool fMatch, flgCheck; char letter; @@ -150,13 +151,20 @@ static IBT_DATA *read_ibt( char *filename, FILE *fp ) if (!str_cmp(word, "Body")) STRFREE(ibtData->body); KEY("Body", ibtData->body, fread_clean_string( fp, buf )); break; - + case 'D': + TXT_KEY("Dated", dated, fread_line(fp)); + break; case 'E': if (!str_cmp(word, "End")) { - if ( id_num ) + if ( id_num ) { ibtData->id_num = atol(id_num); - + STRFREE( id_num ); + } + if ( dated ) { + ibtData->dated = atol(dated); + STRFREE( dated ); + } if ( !ibtData->name ) ibtData->name = STRALLOC(""); if ( !ibtData->text ) @@ -219,7 +227,11 @@ static IBT_DATA *read_ibt( char *filename, FILE *fp ) STRFREE( ibtData->text); if ( ibtData->body) STRFREE( ibtData->body); - + if ( id_num ) + STRFREE( id_num ); + if ( dated ) + STRFREE( dated ); + DISPOSE( ibtData); return NULL; } @@ -316,6 +328,8 @@ void save_ibt_file(int mode) fprintf(fp,"Notes %s~\n",ibtData->notes); if (ibtData->id_num != NOBODY) fprintf(fp,"IdNum %ld\n",ibtData->id_num); + if (ibtData->dated != 0) + fprintf(fp,"Dated %ld\n",ibtData->dated); fprintf(fp,"Level %d\n",ibtData->level); fprintf(fp,"Room %d\n",ibtData->room); fprintf(fp,"Flags %d %d %d %d\n",ibtData->flags[0],ibtData->flags[1], @@ -504,6 +518,7 @@ ACMD(do_ibt) } else { send_to_char(ch, "%s%s by %s%s\r\n",QCYN, ibt_types[subcmd], QYEL, ibtData->name); + send_to_char(ch, "%sSubmitted: %s%s", QCYN, QYEL, ibtData->dated ? ctime(&ibtData->dated) : "Unknown\r\n"); if (GET_LEVEL(ch) >= LVL_IMMORT) { send_to_char(ch, "%sLevel: %s%d\r\n",QCYN, QYEL, ibtData->level); send_to_char(ch, "%sRoom : %s%d\r\n",QCYN, QYEL, ibtData->room); @@ -640,6 +655,8 @@ ACMD(do_ibt) ibtData->text = STRALLOC(arg_text); ibtData->name = STRALLOC(GET_NAME(ch)); ibtData->id_num = GET_IDNUM(ch); + ibtData->dated = time(0); + switch(subcmd) { case SCMD_BUG : LINK( ibtData, first_bug, last_bug, next, prev ); break; diff --git a/src/ibt.h b/src/ibt.h index d2e7668..04cf9d2 100755 --- a/src/ibt.h +++ b/src/ibt.h @@ -81,6 +81,7 @@ struct ibt_data room_vnum room; /**< Room in which this IBT was reported */ long id_num; /**< The ID number of the player who logged it */ int flags[IBT_ARRAY_MAX]; /**< IBT flags */ + long dated; /**< When the IBT what reported */ }; extern IBT_DATA *first_bug; diff --git a/src/interpreter.c b/src/interpreter.c index 915f120..1e2187c 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -38,6 +38,7 @@ #include "asciimap.h" #include "prefedit.h" #include "ibt.h" +#include "mud_event.h" /* local (file scope) functions */ static int perform_dupe_check(struct descriptor_data *d); @@ -1138,6 +1139,7 @@ static int perform_dupe_check(struct descriptor_data *d) REMOVE_BIT_AR(PLR_FLAGS(d->character), PLR_WRITING); REMOVE_BIT_AR(AFF_FLAGS(d->character), AFF_GROUP); STATE(d) = CON_PLAYING; + MXPSendTag( d, "" ); switch (mode) { case RECON: @@ -1267,6 +1269,43 @@ int enter_player_game (struct descriptor_data *d) return load_result; } +EVENTFUNC(get_protocols) +{ + struct descriptor_data *d; + struct mud_event_data *pMudEvent; + char buf[MAX_STRING_LENGTH]; + int len; + + if (event_obj == NULL) + return 0; + + pMudEvent = (struct mud_event_data *) event_obj; + d = (struct descriptor_data *) pMudEvent->pStruct; + + /* Clear extra white space from the "protocol scroll" */ + write_to_output(d, ""); + + len = snprintf(buf, MAX_STRING_LENGTH, "\tO[\toClient\tO] \tw%s\tn | ", d->pProtocol->pVariables[eMSDP_CLIENT_ID]->pValueString); + + if (d->pProtocol->pVariables[eMSDP_XTERM_256_COLORS]->ValueInt) + len += snprintf(buf + len, MAX_STRING_LENGTH - len, "\tO[\toColors\tO] \tw256\tn | "); + else if (d->pProtocol->pVariables[eMSDP_ANSI_COLORS]->ValueInt) + len += snprintf(buf + len, MAX_STRING_LENGTH - len, "\tO[\toColors\tO] \twAnsi\tn | "); + else + len += snprintf(buf + len, MAX_STRING_LENGTH - len, "[Colors] No Color | "); + + len += snprintf(buf + len, MAX_STRING_LENGTH - len, "\tO[\toMXP\tO] \tw%s\tn | ", d->pProtocol->bMXP ? "Yes" : "No"); + len += snprintf(buf + len, MAX_STRING_LENGTH - len, "\tO[\toMSDP\tO] \tw%s\tn | ", d->pProtocol->bMSDP ? "Yes" : "No"); + len += snprintf(buf + len, MAX_STRING_LENGTH - len, "\tO[\toATCP\tO] \tw%s\tn\r\n\r\n", d->pProtocol->bATCP ? "Yes" : "No"); + + write_to_output(d, buf, 0); + + write_to_output(d, GREETINGS, 0); + STATE(d) = CON_GET_NAME; + free_mud_event(pMudEvent); + return 0; +} + /* deal with newcomers and other non-playing sockets */ void nanny(struct descriptor_data *d, char *arg) { @@ -1304,6 +1343,10 @@ void nanny(struct descriptor_data *d, char *arg) /* Not in OLC. */ switch (STATE(d)) { + case CON_GET_PROTOCOL: + write_to_output(d, "Collecting Protocol Information... Please Wait.\r\n"); + return; + break; case CON_GET_NAME: /* wait for input of name */ if (d->character == NULL) { CREATE(d->character, struct char_data, 1); @@ -1619,6 +1662,7 @@ void nanny(struct descriptor_data *d, char *arg) act("$n has entered the game.", TRUE, d->character, 0, 0, TO_ROOM); STATE(d) = CON_PLAYING; + MXPSendTag( d, "" ); if (GET_LEVEL(d->character) == 0) { do_start(d->character); send_to_char(d->character, "%s", CONFIG_START_MESSG); diff --git a/src/limits.c b/src/limits.c index 43b9481..a16bf2f 100644 --- a/src/limits.c +++ b/src/limits.c @@ -21,6 +21,7 @@ #include "class.h" #include "fight.h" #include "screen.h" +#include "mud_event.h" /* local file scope function prototypes */ static int graf(int grafage, int p0, int p1, int p2, int p3, int p4, int p5, int p6); @@ -527,3 +528,31 @@ int decrease_bank(struct char_data *ch, int deduction) increase_bank(ch, amt); return (GET_BANK_GOLD(ch)); } + +EVENTFUNC(display_usage) +{ + struct descriptor_data * d; + struct char_data * tch; + struct list_data * player_list; + + player_list = create_list(); + + for (d = descriptor_list; d; d = d->next) + if (d->character && STATE(d) == CON_PLAYING) + add_to_list(d->character, player_list); + + game_info("News:"); + game_info("Currently %d Players Online", player_list->iSize); + + if (player_list->iSize) { + tch = (struct char_data *) random_from_list(player_list); + if (player_list->iSize == 1) + game_info("%s is apparently very lonely.", GET_NAME(tch)); + else + game_info("%s last seen at %s", GET_NAME(tch), world[IN_ROOM(tch)].name); + } + + free_list(player_list); + + return (10 * 60 * PASSES_PER_SEC); +} diff --git a/src/modify.c b/src/modify.c index f035cad..7c72457 100644 --- a/src/modify.c +++ b/src/modify.c @@ -75,6 +75,24 @@ void smash_tilde(char *str) *p=' '; } +/* Parse out the @ character and replace it with the '\t' to work with + * KaVir's protocol snippet */ +void parse_at(char *str) +{ + char *p = str; + for (; *p; p++) + if (*p == '@') + *p = '\t'; +} + +void parse_tab(char *str) +{ + char *p = str; + for (; *p; p++) + if (*p == '\t') + *p = '@'; +} + /* Basic API function to start writing somewhere. 'data' isn't used, but you * can use it to pass whatever else you may want through it. The improved * editor patch when updated could use it to pass the old text buffer, for diff --git a/src/modify.h b/src/modify.h index c6e535c..0fbdbd8 100644 --- a/src/modify.h +++ b/src/modify.h @@ -22,6 +22,8 @@ /* Public functions */ void show_string(struct descriptor_data *d, char *input); void smash_tilde(char *str); +void parse_at(char *str); +void parse_tab(char *str); void paginate_string(char *str, struct descriptor_data *d); /** @todo should this really be in modify.c? */ ACMD(do_skillset); diff --git a/src/qedit.c b/src/qedit.c index 8436488..cf51a77 100644 --- a/src/qedit.c +++ b/src/qedit.c @@ -293,29 +293,29 @@ static void qedit_disp_menu(struct descriptor_data *d) break; } write_to_output(d, - "-- Quest Number : @n[@c%6d@n]\r\n" - "@g 1@n) Quest Name : @y%s\r\n" - "@g 2@n) Description : @y%s\r\n" - "@g 3@n) Accept Message\r\n@y%s" - "@g 4@n) Completion Message\r\n@y%s" - "@g 5@n) Quit Message\r\n@y%s" - "@g 6@n) Quest Flags : @c%s\r\n" - "@g 7@n) Quest Type : @c%s %s\r\n" - "@g 8@n) Quest Master : [@c%6d@n] @y%s\r\n" - "@g 9@n) Quest Target : [@c%6d@n] @y%s\r\n" - "@g A@n) Quantity : [@c%6d@n]\r\n" - "@n Quest Point Rewards\r\n" - "@g B@n) Completed : [@c%6d@n] @g C@n) Abandoned : [@c%6d@n]\r\n" - "@n Other Rewards Rewards\r\n" - "@g G@n) Gold Coins : [@c%6d@n] @g T@n) Exp Points : [@c%6d@n] @g O@n) Object : [@c%6d@n]\r\n" - "@n Level Limits to Accept Quest\r\n" - "@g D@n) Lower Level : [@c%6d@n] @g E@n) Upper Level : [@c%6d@n]\r\n" - "@g F@n) Prerequisite : [@c%6d@n] @y%s\r\n" - "@g L@n) Time Limit : [@c%6d@n]\r\n" - "@g N@n) Next Quest : [@c%6d@n] @y%s\r\n" - "@g P@n) Previous Quest : [@c%6d@n] @y%s\r\n" - "@g X@n) Delete Quest\r\n" - "@g Q@n) Quit\r\n" + "-- Quest Number : \tn[\tc%6d\tn]\r\n" + "\tg 1\tn) Quest Name : \ty%s\r\n" + "\tg 2\tn) Description : \ty%s\r\n" + "\tg 3\tn) Accept Message\r\n\ty%s" + "\tg 4\tn) Completion Message\r\n\ty%s" + "\tg 5\tn) Quit Message\r\n\ty%s" + "\tg 6\tn) Quest Flags : \tc%s\r\n" + "\tg 7\tn) Quest Type : \tc%s %s\r\n" + "\tg 8\tn) Quest Master : [\tc%6d\tn] \ty%s\r\n" + "\tg 9\tn) Quest Target : [\tc%6d\tn] \ty%s\r\n" + "\tg A\tn) Quantity : [\tc%6d\tn]\r\n" + "\tn Quest Point Rewards\r\n" + "\tg B\tn) Completed : [\tc%6d\tn] \tg C\tn) Abandoned : [\tc%6d\tn]\r\n" + "\tn Other Rewards Rewards\r\n" + "\tg G\tn) Gold Coins : [\tc%6d\tn] \tg T\tn) Exp Points : [\tc%6d\tn] \tg O\tn) Object : [\tc%6d\tn]\r\n" + "\tn Level Limits to Accept Quest\r\n" + "\tg D\tn) Lower Level : [\tc%6d\tn] \tg E\tn) Upper Level : [\tc%6d\tn]\r\n" + "\tg F\tn) Prerequisite : [\tc%6d\tn] \ty%s\r\n" + "\tg L\tn) Time Limit : [\tc%6d\tn]\r\n" + "\tg N\tn) Next Quest : [\tc%6d\tn] \ty%s\r\n" + "\tg P\tn) Previous Quest : [\tc%6d\tn] \ty%s\r\n" + "\tg X\tn) Delete Quest\r\n" + "\tg Q\tn) Quit\r\n" "Enter Choice : ", quest->vnum, quest->name, diff --git a/src/sedit.c b/src/sedit.c index dce5be0..fb797ca 100644 --- a/src/sedit.c +++ b/src/sedit.c @@ -248,9 +248,9 @@ static void sedit_compact_rooms_menu(struct descriptor_data *d) clear_screen(d); for (i = 0; S_ROOM(shop, i) != NOWHERE; i++) { if (real_room(S_ROOM(shop, i)) != NOWHERE) { - write_to_output(d, "%2d - [@c%5d@n] - @y%s@n\r\n", i, S_ROOM(shop, i), world[real_room(S_ROOM(shop, i))].name); + write_to_output(d, "%2d - [@\t%5d\tn] - \ty%s\tn\r\n", i, S_ROOM(shop, i), world[real_room(S_ROOM(shop, i))].name); } else { - write_to_output(d, "%2d - [@R!Removed Room!@n]\r\n", i); + write_to_output(d, "%2d - [\tR!Removed Room!\tn]\r\n", i); } } write_to_output(d, "\r\n" diff --git a/src/shop.c b/src/shop.c index 11885a6..4ac25a2 100644 --- a/src/shop.c +++ b/src/shop.c @@ -85,7 +85,7 @@ static char *times_message(struct obj_data *obj, char *name, int num); static int buy_price(struct obj_data *obj, int shop_nr, struct char_data *keeper, struct char_data *buyer); static int sell_price(struct obj_data *obj, int shop_nr, struct char_data *keeper, struct char_data *seller); static int ok_shop_room(int shop_nr, room_vnum room); -static int add_to_list(struct shop_buy_data *list, int type, int *len, int *val); +static int add_to_shop_list(struct shop_buy_data *list, int type, int *len, int *val); static int end_read_list(struct shop_buy_data *list, int len, int error); static void read_line(FILE *shop_f, const char *string, void *data); @@ -532,14 +532,18 @@ static void shopping_buy(char *arg, struct char_data *ch, struct char_data *keep } } } - if (IS_CARRYING_N(ch) + 1 > CAN_CARRY_N(ch)) { - send_to_char(ch, "%s: You can't carry any more items.\r\n", fname(obj->name)); - return; - } - if (IS_CARRYING_W(ch) + GET_OBJ_WEIGHT(obj) > CAN_CARRY_W(ch)) { - send_to_char(ch, "%s: You can't carry that much weight.\r\n", fname(obj->name)); - return; + + if (IS_NPC(ch) || (!IS_NPC(ch) && !PRF_FLAGGED(ch, PRF_NOHASSLE))) { + if (IS_CARRYING_N(ch) + 1 > CAN_CARRY_N(ch)) { + send_to_char(ch, "%s: You can't carry any more items.\r\n", fname(obj->name)); + return; + } + if (IS_CARRYING_W(ch) + GET_OBJ_WEIGHT(obj) > CAN_CARRY_W(ch)) { + send_to_char(ch, "%s: You can't carry that much weight.\r\n", fname(obj->name)); + return; + } } + if (OBJ_FLAGGED(obj, ITEM_QUEST)) { while (obj && (GET_QUESTPOINTS(ch) >= GET_OBJ_COST(obj) || IS_GOD(ch)) @@ -1019,7 +1023,7 @@ int ok_damage_shopkeeper(struct char_data *ch, struct char_data *victim) } /* val == obj_vnum and obj_rnum (?) */ -static int add_to_list(struct shop_buy_data *list, int type, int *len, int *val) +static int add_to_shop_list(struct shop_buy_data *list, int type, int *len, int *val) { if (*val != NOTHING && *val >= 0) { /* necessary after changing to unsigned v/rnums -- Welcor */ if (*len < MAX_SHOP_OBJ) { @@ -1066,12 +1070,12 @@ static int read_list(FILE *shop_f, struct shop_buy_data *list, int new_format, read_line(shop_f, "%d", &temp); if (temp < 0) /* Always "-1" the string. */ break; - error += add_to_list(list, type, &len, &temp); + error += add_to_shop_list(list, type, &len, &temp); } } else for (count = 0; count < max; count++) { read_line(shop_f, "%d", &temp); - error += add_to_list(list, type, &len, &temp); + error += add_to_shop_list(list, type, &len, &temp); } return (end_read_list(list, len, error)); } @@ -1115,7 +1119,7 @@ static int read_type_list(FILE *shop_f, struct shop_buy_data *list, ptr++; while (isspace(*(END_OF(ptr) - 1))) *(END_OF(ptr) - 1) = '\0'; - error += add_to_list(list, LIST_TRADE, &len, &num); + error += add_to_shop_list(list, LIST_TRADE, &len, &num); if (*ptr) BUY_WORD(list[len - 1]) = strdup(ptr); } while (num >= 0); diff --git a/src/spec_procs.c b/src/spec_procs.c index 80924db..c1b1b24 100644 --- a/src/spec_procs.c +++ b/src/spec_procs.c @@ -452,7 +452,7 @@ SPECIAL(guild_guard) /* Allow the people of the guild through. */ if (!IS_NPC(ch) && GET_CLASS(ch) == guild_info[i].pc_class) continue; - + send_to_char(ch, "%s", buf); act(buf2, FALSE, ch, 0, 0, TO_ROOM); return (TRUE); diff --git a/src/structs.h b/src/structs.h index 30e8851..04cd1f1 100644 --- a/src/structs.h +++ b/src/structs.h @@ -12,6 +12,9 @@ #ifndef _STRUCTS_H_ #define _STRUCTS_H_ +#include "protocol.h" /* Kavir Plugin*/ +#include "lists.h" + /** Intended use of this macro is to allow external packages to work with a * variety of versions without modifications. For instance, an IS_CORPSE() * macro was introduced in pl13. Any future code add-ons could take into @@ -326,6 +329,7 @@ #define CON_QEDIT 28 /**< OLC mode - quest edit */ #define CON_PREFEDIT 29 /**< OLC mode - preference edit */ #define CON_IBTEDIT 30 /**< OLC mode - idea/bug/typo edit */ +#define CON_GET_PROTOCOL 31 /**< Used at log-in while attempting to get protocols > */ /* OLC States range - used by IS_IN_OLC and IS_PLAYING */ #define FIRST_OLC_STATE CON_OEDIT /**< The first CON_ state that is an OLC */ @@ -1031,6 +1035,8 @@ struct char_data struct char_data *master; /**< List of character being followed */ long pref; /**< unique session id */ + + struct list_data * events; }; /** descriptor-related structures */ @@ -1085,6 +1091,9 @@ struct descriptor_data struct descriptor_data *snoop_by; /**< And who is snooping this char */ struct descriptor_data *next; /**< link to next descriptor */ struct oasis_olc_data *olc; /**< OLC info */ + protocol_t *pProtocol; /**< Kavir plugin */ + + struct list_data * events; }; /* other miscellaneous structures */ diff --git a/src/utils.c b/src/utils.c index ea1ec7f..71e05ce 100644 --- a/src/utils.c +++ b/src/utils.c @@ -809,8 +809,9 @@ int count_color_chars(char *string) len = strlen(string); for (i = 0; i < len; i++) { - while (string[i] == '@') { - if (string[i + 1] == '@') + while (string[i] == '\t' || string[i] == '@') { + if ((string[i] == '\t' && string[i + 1] == '\t') || + (string[i] == '@' && string[i + 1] == '@')) num++; else num += 2; @@ -1290,6 +1291,7 @@ IDXTYPE atoidx( const char *str_to_conv ) return (IDXTYPE) result; } +#define isspace_ignoretabs(c) ((c)!='\t' && isspace(c)) /* strfrmt (String Format) function @@ -1316,17 +1318,17 @@ char *strfrmt(char *str, int w, int h, int justify, int hpad, int vpad) /* Split into lines, including convert \\ into \r\n */ while(*sp) { /* eat leading space */ - while(*sp && isspace(*sp)) sp++; + while(*sp && isspace_ignoretabs(*sp)) sp++; /* word begins */ wp = sp; wlen = 0; while(*sp) { /* Find the end of the word */ - if(isspace(*sp)) break; + if(isspace_ignoretabs(*sp)) break; if(*sp=='\\' && sp[1] && sp[1]=='\\') { if(sp!=wp) break; /* Finish dealing with the current word */ sp += 2; /* Eat the marker and any trailing space */ - while(*sp && isspace(*sp)) sp++; + while(*sp && isspace_ignoretabs(*sp)) sp++; wp = sp; /* Start a new line */ if(hpad) @@ -1345,6 +1347,18 @@ char *strfrmt(char *str, int w, int h, int justify, int hpad, int vpad) if (*sp=='@' && (sp[1]!=*sp)) /* Color code, not @@ */ last_color = sp[1]; sp += 2; /* Eat the whole code regardless */ + } else if (*sp=='\t'&&sp[1]) { + char MXPcode = sp[1]=='[' ? ']' : sp[1]=='<' ? '>' : '\0'; + + if (!MXPcode) + last_color = sp[1]; + + sp += 2; /* Eat the code */ + if (MXPcode) + { + while (*sp!='\0'&&*sp!=MXPcode) + ++sp; /* Eat the rest of the code */ + } } else { wlen++; sp++; @@ -1355,7 +1369,7 @@ char *strfrmt(char *str, int w, int h, int justify, int hpad, int vpad) if(hpad) for(; llen < w; llen++) *lp++ = ' '; - *lp++ = '@'; /* 'normal' color */ + *lp++ = '\t'; /* 'normal' color */ *lp++ = 'n'; *lp++ = '\r'; /* New line */ *lp++ = '\n'; @@ -1366,7 +1380,7 @@ char *strfrmt(char *str, int w, int h, int justify, int hpad, int vpad) lcount++; lp = line; if (last_color != 'n') { - *lp++ = '@'; /* restore previous color */ + *lp++ = '\t'; /* restore previous color */ *lp++ = last_color; new_line_started = TRUE; }