From 88fb85b12656b31bd0316b2968712f7f4e076cbe Mon Sep 17 00:00:00 2001 From: JamDog Date: Sat, 6 Nov 2010 18:14:07 +0000 Subject: [PATCH] Added happyhour feature and game_info function --- changelog | 2 + src/act.h | 1 + src/act.informative.c | 4 + src/act.other.c | 113 +++++++++++++++++++++++++++ src/comm.c | 172 ++++++++++++++++++++++++------------------ src/comm.h | 22 +++--- src/db.c | 1 + src/db.h | 3 + src/fight.c | 23 +++++- src/interpreter.c | 8 +- src/limits.c | 23 +++++- src/quest.c | 45 ++++++++--- src/structs.h | 8 ++ src/utils.h | 13 ++++ 14 files changed, 340 insertions(+), 98 deletions(-) diff --git a/changelog b/changelog index 2cc5612..274e5f9 100644 --- a/changelog +++ b/changelog @@ -36,6 +36,8 @@ Xlist (mlist, olist, rlist, zlist, slist, tlist, qlist) (lots of major bugfixes too) @ [Nov 06 2010] - Jamdog + Added HappyHour feature + Added game_info function for sending global messages to all players Added ability to change player/mob level or class in scripts The medit mob flags menu now only shows valid flags (thanks Kyle) Skillset now warns imms when the player shouldn't have a skill (thanks Rumble) diff --git a/src/act.h b/src/act.h index 7d7387e..33cd5d9 100644 --- a/src/act.h +++ b/src/act.h @@ -237,6 +237,7 @@ ACMD(do_use); /* Functions without subcommands */ ACMD(do_display); ACMD(do_group); +ACMD(do_happyhour); ACMD(do_hide); ACMD(do_not_here); ACMD(do_practice); diff --git a/src/act.informative.c b/src/act.informative.c index 7b5ac3c..e2a9bf0 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -1331,6 +1331,10 @@ ACMD(do_who) send_to_char(ch, "One lonely character displayed.\r\n"); else send_to_char(ch, "%d characters displayed.\r\n", num_can_see); + + if (IS_HAPPYHOUR > 0){ + send_to_char(ch, "It's a Happy Hour! Type @Rhappyhour@W to see the current bonuses.\r\n"); + } } #define USERS_FORMAT \ diff --git a/src/act.other.c b/src/act.other.c index a3dadfd..1b4c69b 100644 --- a/src/act.other.c +++ b/src/act.other.c @@ -859,3 +859,116 @@ ACMD(do_gen_tog) return; } + +void show_happyhour(struct char_data *ch) +{ + char happyexp[80], happygold[80], happyqp[80]; + int secs_left; + + if ((IS_HAPPYHOUR) || (GET_LEVEL(ch) >= LVL_GRGOD)) + { + if (HAPPY_TIME) + secs_left = ((HAPPY_TIME - 1) * SECS_PER_MUD_HOUR) + next_tick; + else + secs_left = 0; + + sprintf(happyqp, "%s+%d%%%s to Questpoints per quest\r\n", CCYEL(ch, C_NRM), HAPPY_QP, CCNRM(ch, C_NRM)); + sprintf(happygold, "%s+%d%%%s to Gold gained per kill\r\n", CCYEL(ch, C_NRM), HAPPY_GOLD, CCNRM(ch, C_NRM)); + sprintf(happyexp, "%s+%d%%%s to Experience per kill\r\n", CCYEL(ch, C_NRM), HAPPY_EXP, CCNRM(ch, C_NRM)); + + send_to_char(ch, "tbaMUD Happy Hour!\r\n" + "------------------\r\n" + "%s%s%sTime Remaining: %s%d%s hours %s%d%s mins %s%d%s secs\r\n", + (IS_HAPPYEXP || (GET_LEVEL(ch) >= LVL_GOD)) ? happyexp : "", + (IS_HAPPYGOLD || (GET_LEVEL(ch) >= LVL_GOD)) ? happygold : "", + (IS_HAPPYQP || (GET_LEVEL(ch) >= LVL_GOD)) ? happyqp : "", + CCYEL(ch, C_NRM), (secs_left / 3600), CCNRM(ch, C_NRM), + CCYEL(ch, C_NRM), (secs_left % 3600) / 60, CCNRM(ch, C_NRM), + CCYEL(ch, C_NRM), (secs_left % 60), CCNRM(ch, C_NRM) ); + } + else + { + send_to_char(ch, "Sorry, there is currently no happy hour!\r\n"); + } +} + +ACMD(do_happyhour) +{ + char arg[MAX_INPUT_LENGTH], val[MAX_INPUT_LENGTH]; + int num; + + if (GET_LEVEL(ch) < LVL_GOD) + { + show_happyhour(ch); + return; + } + + /* Only Imms get here, so check args */ + two_arguments(argument, arg, val); + + if (is_abbrev(arg, "experience")) + { + num = MIN(MAX((atoi(val)), 0), 1000); + HAPPY_EXP = num; + send_to_char(ch, "Happy Hour Exp rate set to +%d%%\r\n", HAPPY_EXP); + } + else if ((is_abbrev(arg, "gold")) || (is_abbrev(arg, "coins"))) + { + num = MIN(MAX((atoi(val)), 0), 1000); + HAPPY_GOLD = num; + send_to_char(ch, "Happy Hour Gold rate set to +%d%%\r\n", HAPPY_GOLD); + } + else if ((is_abbrev(arg, "time")) || (is_abbrev(arg, "ticks"))) + { + num = MIN(MAX((atoi(val)), 0), 1000); + if (HAPPY_TIME && !num) + game_info("Happyhour has been stopped!"); + else if (!HAPPY_TIME && num) + game_info("A Happyhour has started!"); + + HAPPY_TIME = num; + send_to_char(ch, "Happy Hour Time set to %d ticks (%d hours %d mins and %d secs)\r\n", + HAPPY_TIME, + (HAPPY_TIME*SECS_PER_MUD_HOUR)/3600, + ((HAPPY_TIME*SECS_PER_MUD_HOUR)%3600) / 60, + (HAPPY_TIME*SECS_PER_MUD_HOUR)%60 ); + } + else if ((is_abbrev(arg, "qp")) || (is_abbrev(arg, "questpoints"))) + { + num = MIN(MAX((atoi(val)), 0), 1000); + HAPPY_QP = num; + send_to_char(ch, "Happy Hour Questpoints rate set to +%d%%\r\n", HAPPY_QP); + } + else if (is_abbrev(arg, "show")) + { + show_happyhour(ch); + } + else if (is_abbrev(arg, "default")) + { + HAPPY_EXP = 100; + HAPPY_GOLD = 50; + HAPPY_QP = 50; + HAPPY_TIME = 48; + game_info("A Happyhour has started!"); + } + else + { + send_to_char(ch, "Usage: %shappyhour %s- show usage (this info)\r\n" + " %shappyhour show %s- display current settings (what mortals see)\r\n" + " %shappyhour time %s- set happyhour time and start timer\r\n" + " %shappyhour qp %s- set qp percentage gain\r\n" + " %shappyhour exp %s- set exp percentage gain\r\n" + " %shappyhour gold %s- set gold percentage gain\r\n" + " @yhappyhour default @w- sets a default setting for happyhour\r\n\r\n" + "Configure the happyhour settings and start a happyhour.\r\n" + "Currently 1 hour IRL = %d ticks\r\n" + "If no number is specified, 0 (off) is assumed.\r\nThe command @yhappyhour time@n will therefore stop the happyhour timer.\r\n", + CCYEL(ch, C_NRM), CCNRM(ch, C_NRM), + CCYEL(ch, C_NRM), CCNRM(ch, C_NRM), + CCYEL(ch, C_NRM), CCNRM(ch, C_NRM), + CCYEL(ch, C_NRM), CCNRM(ch, C_NRM), + CCYEL(ch, C_NRM), CCNRM(ch, C_NRM), + CCYEL(ch, C_NRM), CCNRM(ch, C_NRM), + (3600 / SECS_PER_MUD_HOUR) ); + } +} diff --git a/src/comm.c b/src/comm.c index fe7adc4..50a907c 100644 --- a/src/comm.c +++ b/src/comm.c @@ -86,7 +86,7 @@ #define INVALID_SOCKET (-1) #endif -extern time_t motdmod; +extern time_t motdmod; extern time_t newsmod; /* locally defined globals, used externally */ @@ -102,6 +102,7 @@ FILE *logfile = NULL; /* Where to send the log messages. */ unsigned long pulse = 0; /* number of pulses since game start */ ush_int port; socket_t mother_desc; +int next_tick = SECS_PER_MUD_HOUR; /* Tick countdown */ /* used with do_tell and handle_webster_file utility */ long last_webster_teller = -1L; @@ -114,7 +115,7 @@ static byte reread_wizlist; /* signal: SIGUSR1 */ /* normally signal SIGUSR2, currently orphaned in favor of Webster dictionary * lookup static byte emergency_unban; -*/ +*/ static int dg_act_check; /* toggle for act_trigger */ static bool fCopyOver; /* Are we booting in copyover mode? */ static char *last_act_message = NULL; @@ -178,7 +179,7 @@ static void handle_webster_file(); /* main game loop and related stuff */ #if defined(CIRCLE_WINDOWS) || defined(CIRCLE_MACINTOSH) -/* Windows and Mac do not have gettimeofday, so we'll simulate it. Borland C++ +/* Windows and Mac do not have gettimeofday, so we'll simulate it. Borland C++ * warns: "Undefined structure 'timezone'" */ void gettimeofday(struct timeval *t, struct timezone *dummy) { @@ -200,8 +201,8 @@ int main(int argc, char **argv) int pos = 1; const char *dir; -#ifdef MEMORY_DEBUG - zmalloc_init(); +#ifdef MEMORY_DEBUG + zmalloc_init(); #endif #if CIRCLE_GNU_LIBC_MEMORY_TRACK @@ -216,8 +217,8 @@ int main(int argc, char **argv) GUSIDefaultSetup(); #endif - /* Load the game configuration. We must load BEFORE we use any of the - * constants stored in constants.c. Otherwise, there will be no variables + /* Load the game configuration. We must load BEFORE we use any of the + * constants stored in constants.c. Otherwise, there will be no variables * set to set the rest of the vars to, which will mean trouble --> Mythran */ CONFIG_CONFFILE = NULL; while ((pos < argc) && (*(argv[pos]) == '-')) { @@ -295,7 +296,7 @@ int main(int argc, char **argv) puts("Suppressing assignment of special routines."); break; case 'h': - /* From: Anil Mahajan. Do NOT use -C, this is the copyover mode and + /* From: Anil Mahajan. Do NOT use -C, this is the copyover mode and * without the proper copyover.dat file, the game will go nuts! */ printf("Usage: %s [-c] [-m] [-q] [-r] [-s] [-d pathname] [port #]\n" " -c Enable syntax check mode.\n" @@ -369,7 +370,7 @@ int main(int argc, char **argv) free_ibt_lists(); /* ibt.c */ } - if (last_act_message) + if (last_act_message) free(last_act_message); /* probably should free the entire config here.. */ @@ -546,8 +547,8 @@ static socket_t init_socket(ush_int local_port) exit(1); } - /* 4 = stdin, stdout, stderr, mother_desc. Windows might keep sockets and - * files separate, in which case this isn't necessary, but we will err on + /* 4 = stdin, stdout, stderr, mother_desc. Windows might keep sockets and + * files separate, in which case this isn't necessary, but we will err on * the side of caution. */ if ((wsaData.iMaxSockets - 4) < max_players) { max_players = wsaData.iMaxSockets - 4; @@ -586,7 +587,7 @@ static socket_t init_socket(ush_int local_port) set_sendbuf(s); -/* The GUSI sockets library is derived from BSD, so it defines SO_LINGER, even +/* The GUSI sockets library is derived from BSD, so it defines SO_LINGER, even * though setsockopt() is unimplimented. (from Dean Takemori) */ #if defined(SO_LINGER) && !defined(CIRCLE_MACINTOSH) { @@ -816,9 +817,9 @@ void game_loop(socket_t local_mother_desc) for (d = descriptor_list; d; d = next_d) { next_d = d->next; - /* Not combined to retain --(d->wait) behavior. -gg 2/20/98 If no wait + /* Not combined to retain --(d->wait) behavior. -gg 2/20/98 If no wait * state, no subtraction. If there is a wait state then 1 is subtracted. - * Therefore we don't go less than 0 ever and don't require an 'if' + * Therefore we don't go less than 0 ever and don't require an 'if' * bracket. -gg 2/27/99 */ if (d->character) { GET_WAIT_STATE(d->character) -= (GET_WAIT_STATE(d->character) > 0); @@ -942,6 +943,10 @@ void heartbeat(int heart_pulse) if (!(heart_pulse % PULSE_DG_SCRIPT)) script_trigger_check(); + if (!(heart_pulse % PASSES_PER_SEC)) { /* EVERY second */ + next_tick--; + } + if (!(heart_pulse % PULSE_ZONE)) zone_update(); @@ -955,6 +960,7 @@ void heartbeat(int heart_pulse) perform_violence(); if (!(heart_pulse % (SECS_PER_MUD_HOUR * PASSES_PER_SEC))) { /* Tick ! */ + next_tick = SECS_PER_MUD_HOUR; /* Reset tick coundown */ weather_and_time(1); check_time_triggers(); affect_update(); @@ -980,10 +986,10 @@ void heartbeat(int heart_pulse) extract_pending_chars(); } -/* new code to calculate time differences, which works on systems for which - * tv_usec is unsigned (and thus comparisons for something being < 0 fail). - * Based on code submitted by ss@sirocco.cup.hp.com. Code to return the time - * difference between a and b (a-b). Always returns a nonnegative value +/* new code to calculate time differences, which works on systems for which + * tv_usec is unsigned (and thus comparisons for something being < 0 fail). + * Based on code submitted by ss@sirocco.cup.hp.com. Code to return the time + * difference between a and b (a-b). Always returns a nonnegative value * (floors at 0). */ static void timediff(struct timeval *rslt, struct timeval *a, struct timeval *b) { @@ -1217,18 +1223,18 @@ static char *make_prompt(struct descriptor_data *d) len += count; } - if (GET_LAST_NEWS(d->character) < newsmod) - { - count = snprintf(prompt + len, sizeof(prompt) - len, "(news) "); - if (count >= 0) - len += count; - } - - if (GET_LAST_MOTD(d->character) < motdmod) - { - count = snprintf(prompt + len, sizeof(prompt) - len, "(motd) "); - if (count >= 0) - len += count; + if (GET_LAST_NEWS(d->character) < newsmod) + { + count = snprintf(prompt + len, sizeof(prompt) - len, "(news) "); + if (count >= 0) + len += count; + } + + if (GET_LAST_MOTD(d->character) < motdmod) + { + count = snprintf(prompt + len, sizeof(prompt) - len, "(motd) "); + if (count >= 0) + len += count; } if (len < sizeof(prompt)) @@ -1557,17 +1563,17 @@ static int new_descriptor(socket_t s) 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); + /* 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); return (0); } -/* Send all of the output that we've accumulated for a player out to the +/* Send all of the output that we've accumulated for a player out to the * player's descriptor. 32 byte GARBAGE_SPACE in MAX_SOCK_BUF used for: * 2 bytes: prepended \r\n * 14 bytes: overflow message @@ -1714,7 +1720,7 @@ static ssize_t perform_socket_write(socket_t desc, const char *txt, size_t lengt return (-1); } - /* result < 0, so an error was encountered - is it transient? Unfortunately, + /* result < 0, so an error was encountered - is it transient? Unfortunately, * different systems use different constants to indicate this. */ #ifdef EAGAIN /* POSIX */ @@ -1738,7 +1744,7 @@ static ssize_t perform_socket_write(socket_t desc, const char *txt, size_t lengt #endif /* CIRCLE_WINDOWS */ /* write_to_descriptor takes a descriptor, and text to write to the descriptor. - * It keeps calling the system-level write() until all the text has been + * It keeps calling the system-level write() until all the text has been * delivered to the OS, or until an error is encountered. Returns: * >=0 If all is well and good. * -1 If an error was encountered, so that the player should be cut off. */ @@ -1834,11 +1840,11 @@ static ssize_t perform_socket_read(socket_t desc, char *read_point, size_t space * function is called. We must maintain that before returning. * * Ever wonder why 'tmp' had '+8' on it? The crusty old code could write - * MAX_INPUT_LENGTH+1 bytes to 'tmp' if there was a '$' as the final character - * in the input buffer. This would also cause 'space_left' to drop to -1, - * which wasn't very happy in an unsigned variable. Argh. So to fix the - * above, 'tmp' lost the '+8' since it doesn't need it and the code has been - * changed to reserve space by accepting one less character. (Do you really + * MAX_INPUT_LENGTH+1 bytes to 'tmp' if there was a '$' as the final character + * in the input buffer. This would also cause 'space_left' to drop to -1, + * which wasn't very happy in an unsigned variable. Argh. So to fix the + * above, 'tmp' lost the '+8' since it doesn't need it and the code has been + * changed to reserve space by accepting one less character. (Do you really * need 256 characters on a line?) -gg 1/21/2000 */ static int process_input(struct descriptor_data *t) { @@ -1868,7 +1874,7 @@ static int process_input(struct descriptor_data *t) /* at this point, we know we got some data from the read */ *(read_point + bytes_read) = '\0'; /* terminate the string */ - + /* search for a newline in the data we just read */ for (ptr = read_point; *ptr && !nl_pos; ptr++) if (ISNEWL(*ptr)) @@ -1965,12 +1971,12 @@ static int process_input(struct descriptor_data *t) t->history_pos = 0; } - /* The '--' command flushes the queue. */ - if ( (*tmp == '-') && (*(tmp+1) == '-') && !(*(tmp+2)) ) - { - write_to_output(t, "All queued commands cancelled.\r\n"); - flush_queues(t); /* Flush the command queue */ - failed_subst = 1; /* Allow the read point to be moved, but don't add to queue */ + /* The '--' command flushes the queue. */ + if ( (*tmp == '-') && (*(tmp+1) == '-') && !(*(tmp+2)) ) + { + write_to_output(t, "All queued commands cancelled.\r\n"); + flush_queues(t); /* Flush the command queue */ + failed_subst = 1; /* Allow the read point to be moved, but don't add to queue */ } if (!failed_subst) @@ -1996,8 +2002,8 @@ static int process_input(struct descriptor_data *t) return (1); } -/* Perform substitution for the '^..^' csh-esque syntax orig is the orig string, - * i.e. the one being modified. subst contains the substition string, i.e. +/* Perform substitution for the '^..^' csh-esque syntax orig is the orig string, + * i.e. the one being modified. subst contains the substition string, i.e. * "^telm^tell" */ static int perform_subst(struct descriptor_data *t, char *orig, char *subst) { @@ -2005,7 +2011,7 @@ static int perform_subst(struct descriptor_data *t, char *orig, char *subst) char *first, *second, *strpos; - /* First is the position of the beginning of the first string (the one to be + /* First is the position of the beginning of the first string (the one to be * replaced. */ first = subst + 1; @@ -2328,6 +2334,28 @@ static void signal_setup(void) #endif /* CIRCLE_UNIX || CIRCLE_MACINTOSH */ /* Public routines for system-to-player-communication. */ +void game_info(const char *format, ...) +{ + struct descriptor_data *i; + va_list args; + char messg[MAX_STRING_LENGTH]; + if (format == NULL) + return; + sprintf(messg, "@cInfo: @y"); + for (i = descriptor_list; i; i = i->next) { + if (STATE(i) != CON_PLAYING) + continue; + if (!(i->character)) + continue; + + write_to_output(i, "%s", messg); + va_start(args, format); + vwrite_to_output(i, format, args); + va_end(args); + write_to_output(i, "@n\r\n"); + } +} + size_t send_to_char(struct char_data *ch, const char *messg, ...) { if (ch->desc && messg && *messg) { @@ -2554,9 +2582,9 @@ void perform_act(const char *orig, struct char_data *ch, struct obj_data *obj, if ((IS_NPC(to) && dg_act_check) && (to != ch)) act_mtrigger(to, lbuf, ch, dg_victim, obj, dg_target, dg_arg); - if (last_act_message) - free(last_act_message); - last_act_message = strdup(lbuf); + if (last_act_message) + free(last_act_message); + last_act_message = strdup(lbuf); } char *act(const char *str, int hide_invisible, struct char_data *ch, @@ -2569,11 +2597,11 @@ char *act(const char *str, int hide_invisible, struct char_data *ch, return NULL; /* Warning: the following TO_SLEEP code is a hack. I wanted to be able to tell - * act to deliver a message regardless of sleep without adding an additional - * argument. TO_SLEEP is 128 (a single bit high up). It's ONLY legal to - * combine TO_SLEEP with one other TO_x command. It's not legal to combine - * TO_x's with each other otherwise. TO_SLEEP only works because its value - * "happens to be" a single bit; do not change it to something else. In + * act to deliver a message regardless of sleep without adding an additional + * argument. TO_SLEEP is 128 (a single bit high up). It's ONLY legal to + * combine TO_SLEEP with one other TO_x command. It's not legal to combine + * TO_x's with each other otherwise. TO_SLEEP only works because its value + * "happens to be" a single bit; do not change it to something else. In * short, it is a hack. */ /* check if TO_SLEEP is there, and remove it if it is. */ @@ -2582,21 +2610,21 @@ char *act(const char *str, int hide_invisible, struct char_data *ch, /* this is a hack as well - DG_NO_TRIG is 256 -- Welcor */ /* If the bit is set, unset dg_act_check, thus the ! below */ - if (!(dg_act_check = !IS_SET(type, DG_NO_TRIG))) + if (!(dg_act_check = !IS_SET(type, DG_NO_TRIG))) REMOVE_BIT(type, DG_NO_TRIG); if (type == TO_CHAR) { - if (ch && SENDOK(ch)) { - perform_act(str, ch, obj, vict_obj, ch); - return last_act_message; + if (ch && SENDOK(ch)) { + perform_act(str, ch, obj, vict_obj, ch); + return last_act_message; } return NULL; } if (type == TO_VICT) { - if ((to = vict_obj) != NULL && SENDOK(to)) { - perform_act(str, ch, obj, vict_obj, to); - return last_act_message; + if ((to = vict_obj) != NULL && SENDOK(to)) { + perform_act(str, ch, obj, vict_obj, to); + return last_act_message; } return NULL; } @@ -2604,7 +2632,7 @@ char *act(const char *str, int hide_invisible, struct char_data *ch, if (type == TO_GMOTE && !IS_NPC(ch)) { struct descriptor_data *i; char buf[MAX_STRING_LENGTH]; - + for (i = descriptor_list; i; i = i->next) { if (!i->connected && i->character && !PRF_FLAGGED(i->character, PRF_NOGOSS) && @@ -2612,7 +2640,7 @@ char *act(const char *str, int hide_invisible, struct char_data *ch, !ROOM_FLAGGED(IN_ROOM(i->character), ROOM_SOUNDPROOF)) { sprintf(buf, "%s%s%s", CCYEL(i->character, C_NRM), str, CCNRM(i->character, C_NRM)); - perform_act(buf, ch, obj, vict_obj, i->character); + perform_act(buf, ch, obj, vict_obj, i->character); } } return last_act_message; @@ -2635,7 +2663,7 @@ char *act(const char *str, int hide_invisible, struct char_data *ch, continue; if (type != TO_ROOM && to == vict_obj) continue; - perform_act(str, ch, obj, vict_obj, to); + perform_act(str, ch, obj, vict_obj, to); } return last_act_message; } diff --git a/src/comm.h b/src/comm.h index bbeb9ee..af63d4b 100644 --- a/src/comm.h +++ b/src/comm.h @@ -1,13 +1,13 @@ /** * @file comm.h * Header file, prototypes of public communication functions. -* +* * Part of the core tbaMUD source code distribution, which is a derivative * of, and continuation of, CircleMUD. -* -* All rights reserved. See license for complete information. -* Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University -* CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991. +* +* All rights reserved. See license for complete information. +* Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University +* CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991. * */ #ifndef _COMM_H_ @@ -18,9 +18,10 @@ /* comm.c */ void close_socket(struct descriptor_data *d); -size_t send_to_char(struct char_data *ch, const char *messg, ...) __attribute__ +void game_info(const char *messg, ...) __attribute__ ((format (printf, 1, 2))); +size_t send_to_char(struct char_data *ch, const char *messg, ...) __attribute__ ((format (printf, 2, 3))); -void send_to_all(const char *messg, ...) __attribute__ ((format (printf, 1, +void send_to_all(const char *messg, ...) __attribute__ ((format (printf, 1, 2))); void send_to_room(room_rnum room, const char *messg, ...) __attribute__ ((format (printf, 2, 3))); @@ -29,8 +30,8 @@ void send_to_outdoor(const char *messg, ...) __attribute__ ((format (printf, 1, void send_to_range(room_vnum start, room_vnum finish, const char *messg, ...) __attribute__ ((format (printf, 3, 4))); -/* Act type settings and flags */ -#define TO_ROOM 1 /**< act() type: to everyone in room, except ch. */ +/* Act type settings and flags */ +#define TO_ROOM 1 /**< act() type: to everyone in room, except ch. */ #define TO_VICT 2 /**< act() type: to vict_obj. */ #define TO_NOTVICT 3 /**< act() type: to everyone in room, not ch or vict_obj. */ #define TO_CHAR 4 /**< act() type: to ch. */ @@ -40,7 +41,7 @@ void send_to_range(room_vnum start, room_vnum finish, const char *messg, ...) /* act functions */ -void perform_act(const char *orig, struct char_data *ch, struct obj_data *obj, void *vict_obj, struct char_data *to); +void perform_act(const char *orig, struct char_data *ch, struct obj_data *obj, void *vict_obj, struct char_data *to); char * act(const char *str, int hide_invisible, struct char_data *ch, struct obj_data *obj, void *vict_obj, int type); /* I/O functions */ @@ -75,6 +76,7 @@ extern FILE *logfile; extern unsigned long pulse; extern ush_int port; extern socket_t mother_desc; +extern int next_tick; #endif /* __COMM_C__ */ diff --git a/src/db.c b/src/db.c index 1d71177..86fdd1f 100644 --- a/src/db.c +++ b/src/db.c @@ -120,6 +120,7 @@ struct weather_data weather_info; /* the infomation about the weather */ struct player_special_data dummy_mob; /* dummy spec area for mobs */ struct reset_q_type reset_q; /* queue of zones to be reset */ +struct happyhour happy_data = {0,0,0,0}; /* declaration of local (file scope) variables */ static int converting = FALSE; diff --git a/src/db.h b/src/db.h index 5b537de..42c1992 100644 --- a/src/db.h +++ b/src/db.h @@ -401,6 +401,9 @@ extern struct message_list fight_messages[MAX_MESSAGES]; extern struct aq_data *aquest_table; extern qst_rnum total_quests; +/* Happyhour global */ +extern struct happyhour happy_data; + /* begin previously located in players.c, returned to db.c */ extern struct player_index_element *player_table; extern int top_of_p_table; diff --git a/src/fight.c b/src/fight.c index e77f955..0003eef 100644 --- a/src/fight.c +++ b/src/fight.c @@ -379,10 +379,16 @@ void die(struct char_data * ch, struct char_data * killer) static void perform_group_gain(struct char_data *ch, int base, struct char_data *victim) { - int share; + int share, hap_share; share = MIN(CONFIG_MAX_EXP_GAIN, MAX(1, base)); + if ((IS_HAPPYHOUR) && (IS_HAPPYEXP)) + { + /* This only reports the correct amount - the calc is done in gain_exp */ + hap_share = share + (int)((float)share * ((float)HAPPY_EXP / (float)(100))); + share = MIN(CONFIG_MAX_EXP_GAIN, MAX(1, hap_share)); + } if (share > 1) send_to_char(ch, "You receive your share of experience -- %d points.\r\n", share); else @@ -432,7 +438,7 @@ static void group_gain(struct char_data *ch, struct char_data *victim) static void solo_gain(struct char_data *ch, struct char_data *victim) { - int exp; + int exp, happy_exp; exp = MIN(CONFIG_MAX_EXP_GAIN, GET_EXP(victim) / 3); @@ -444,6 +450,11 @@ static void solo_gain(struct char_data *ch, struct char_data *victim) exp = MAX(exp, 1); + if (IS_HAPPYHOUR && IS_HAPPYEXP) { + happy_exp = exp + (int)((float)exp * ((float)HAPPY_EXP / (float)(100))); + exp = MAX(happy_exp, 1); + } + if (exp > 1) send_to_char(ch, "You receive %d experience points.\r\n", exp); else @@ -659,7 +670,7 @@ int skill_message(int dam, struct char_data *ch, struct char_data *vict, * > 0 How much damage done. */ int damage(struct char_data *ch, struct char_data *victim, int dam, int attacktype) { - long local_gold = 0; + long local_gold = 0, happy_gold = 0; char local_buf[256]; struct char_data *tmp_char; struct obj_data *corpse_obj; @@ -822,6 +833,12 @@ int damage(struct char_data *ch, struct char_data *victim, int dam, int attackty } /* Cant determine GET_GOLD on corpse, so do now and store */ if (IS_NPC(victim)) { + if ((IS_HAPPYHOUR) && (IS_HAPPYGOLD)) + { + happy_gold = (long)(GET_GOLD(victim) * (((float)(HAPPY_GOLD))/(float)100)); + happy_gold = MAX(0, happy_gold); + GET_GOLD(victim) += happy_gold; + } local_gold = GET_GOLD(victim); sprintf(local_buf,"%ld", (long)local_gold); } diff --git a/src/interpreter.c b/src/interpreter.c index 709e223..825303a 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -158,10 +158,11 @@ cpp_extern const struct command_info cmd_info[] = { { "gtell" , "gt" , POS_SLEEPING, do_gsay , 0, 0 }, { "help" , "h" , POS_DEAD , do_help , 0, 0 }, + { "happyhour", "ha" , POS_DEAD , do_happyhour, 0, 0 }, { "hedit" , "hedit" , POS_DEAD , do_oasis_hedit, LVL_GOD , 0 }, - { "hindex" , "hind" , POS_DEAD , do_hindex , 0, 0 }, { "helpcheck", "helpch" , POS_DEAD , do_helpcheck, LVL_GOD, 0 }, { "hide" , "hi" , POS_RESTING , do_hide , 1, 0 }, + { "hindex" , "hind" , POS_DEAD , do_hindex , 0, 0 }, { "handbook" , "handb" , POS_DEAD , do_gen_ps , LVL_IMMORT, SCMD_HANDBOOK }, { "hcontrol" , "hcontrol", POS_DEAD , do_hcontrol , LVL_GRGOD, 0 }, { "history" , "history" , POS_DEAD , do_history, 0, 0}, @@ -1509,6 +1510,11 @@ void nanny(struct descriptor_data *d, char *arg) case CON_RMOTD: /* read CR after printing motd */ write_to_output(d, "%s", CONFIG_MENU); + if (IS_HAPPYHOUR > 0){ + write_to_output(d, "\r\n"); + write_to_output(d, "@yThere is currently a Happyhour!@n\r\n"); + write_to_output(d, "\r\n"); + } add_llog_entry(d->character, LAST_CONNECT); STATE(d) = CON_MENU; break; diff --git a/src/limits.c b/src/limits.c index 35800f9..822cddf 100644 --- a/src/limits.c +++ b/src/limits.c @@ -50,9 +50,9 @@ static int graf(int grafage, int p0, int p1, int p2, int p3, int p4, int p5, int } /* The hit_limit, mana_limit, and move_limit functions are gone. They added an - * unnecessary level of complexity to the internal structure, weren't + * unnecessary level of complexity to the internal structure, weren't * particularly useful, and led to some annoying bugs. From the players' point - * of view, the only difference the removal of these functions will make is + * of view, the only difference the removal of these functions will make is * that a character's age will now only affect the HMV gain per tick, and _not_ * the HMV maximums. */ /* manapoint gain pr. game hour */ @@ -180,7 +180,7 @@ void set_title(struct char_data *ch, char *title) if (title == NULL) { GET_TITLE(ch) = strdup(GET_SEX(ch) == SEX_FEMALE ? - title_female(GET_CLASS(ch), GET_LEVEL(ch)) : + title_female(GET_CLASS(ch), GET_LEVEL(ch)) : title_male(GET_CLASS(ch), GET_LEVEL(ch))); } else { if (strlen(title) > MAX_TITLE_LENGTH) @@ -230,6 +230,9 @@ void gain_exp(struct char_data *ch, int gain) return; } if (gain > 0) { + if ((IS_HAPPYHOUR) && (IS_HAPPYEXP)) + gain += (int)((float)gain * ((float)HAPPY_EXP / (float)(100))); + gain = MIN(CONFIG_MAX_EXP_GAIN, gain); /* put a cap on the max gain per kill */ GET_EXP(ch) += gain; while (GET_LEVEL(ch) < LVL_IMMORT - CONFIG_NO_MORT_TO_IMMORT && @@ -266,6 +269,9 @@ void gain_exp_regardless(struct char_data *ch, int gain) int is_altered = FALSE; int num_levels = 0; + if ((IS_HAPPYHOUR) && (IS_HAPPYEXP)) + gain += (int)((float)gain * ((float)HAPPY_EXP / (float)(100))); + GET_EXP(ch) += gain; if (GET_EXP(ch) < 0) GET_EXP(ch) = 0; @@ -448,4 +454,15 @@ void point_update(void) timer_otrigger(j); } } + + /* Take 1 from the happy-hour tick counter, and end happy-hour if zero */ + if (HAPPY_TIME > 1) HAPPY_TIME--; + else if (HAPPY_TIME == 1) /* Last tick - set everything back to zero */ + { + HAPPY_QP = 0; + HAPPY_EXP = 0; + HAPPY_GOLD = 0; + HAPPY_TIME = 0; + game_info("Happy hour has ended!"); + } } diff --git a/src/quest.c b/src/quest.c index 6aa0e40..1afd72a 100644 --- a/src/quest.c +++ b/src/quest.c @@ -294,24 +294,51 @@ void generic_complete_quest(struct char_data *ch) qst_rnum rnum; qst_vnum vnum = GET_QUEST(ch); struct obj_data *new_obj; + int happy_qp, happy_gold, happy_exp; if (--GET_QUEST_COUNTER(ch) <= 0) { rnum = real_quest(vnum); - GET_QUESTPOINTS(ch) += QST_POINTS(rnum); - send_to_char(ch, + if (IS_HAPPYHOUR && IS_HAPPYQP) { + happy_qp = (int)(QST_POINTS(rnum) * (((float)(100+HAPPY_QP))/(float)100)); + happy_qp = MAX(happy_qp, 0); + GET_QUESTPOINTS(ch) += happy_qp; + send_to_char(ch, + "%s\r\nYou have been awarded %d quest points for your service.\r\n", + QST_DONE(rnum), happy_qp); + } else { + GET_QUESTPOINTS(ch) += QST_POINTS(rnum); + send_to_char(ch, "%s\r\nYou have been awarded %d quest points for your service.\r\n", QST_DONE(rnum), QST_POINTS(rnum)); + } if (QST_GOLD(rnum)) { - GET_GOLD(ch) += QST_GOLD(rnum); - send_to_char(ch, - "You have been awarded %d gold coins for your service.\r\n", - QST_GOLD(rnum)); + if ((IS_HAPPYHOUR) && (IS_HAPPYGOLD)) { + happy_gold = (int)(QST_GOLD(rnum) * (((float)(100+HAPPY_GOLD))/(float)100)); + happy_gold = MAX(happy_gold, 0); + GET_GOLD(ch) += happy_gold; + send_to_char(ch, + "You have been awarded %d gold coins for your service.\r\n", + happy_gold); + } else { + GET_GOLD(ch) += QST_GOLD(rnum); + send_to_char(ch, + "You have been awarded %d gold coins for your service.\r\n", + QST_GOLD(rnum)); + } } if (QST_EXP(rnum)) { gain_exp(ch, QST_EXP(rnum)); - send_to_char(ch, - "You have been awarded %d experience points for your service.\r\n", - QST_EXP(rnum)); + if ((IS_HAPPYHOUR) && (IS_HAPPYEXP)) { + happy_exp = (int)(QST_EXP(rnum) * (((float)(100+HAPPY_EXP))/(float)100)); + happy_exp = MAX(happy_exp, 0); + send_to_char(ch, + "You have been awarded %d experience for your service.\r\n", + happy_exp); + } else { + send_to_char(ch, + "You have been awarded %d experience points for your service.\r\n", + QST_EXP(rnum)); + } } if (QST_OBJ(rnum) && QST_OBJ(rnum) != NOTHING) { if (real_object(QST_OBJ(rnum)) != NOTHING) { diff --git a/src/structs.h b/src/structs.h index ea58ac9..f1e986b 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1232,6 +1232,14 @@ struct guild_info_type int direction; }; +/** Happy Hour Data */ +struct happyhour { + int qp_rate; + int exp_rate; + int gold_rate; + int ticks_left; +}; + /* Config structs */ /** The game configuration structure used for configurating the game play diff --git a/src/utils.h b/src/utils.h index daac0be..1c51dcb 100644 --- a/src/utils.h +++ b/src/utils.h @@ -851,6 +851,19 @@ do \ /** Defines if ch is outdoors or not. */ #define OUTSIDE(ch) (!ROOM_FLAGGED(IN_ROOM(ch), ROOM_INDOORS)) +/* Happy-hour defines */ +#define IS_HAPPYQP (happy_data.qp_rate > 0) +#define IS_HAPPYEXP (happy_data.exp_rate > 0) +#define IS_HAPPYGOLD (happy_data.gold_rate > 0) + +#define HAPPY_EXP happy_data.exp_rate +#define HAPPY_GOLD happy_data.gold_rate +#define HAPPY_QP happy_data.qp_rate + +#define HAPPY_TIME happy_data.ticks_left + +#define IS_HAPPYHOUR ((IS_HAPPYEXP || IS_HAPPYGOLD || IS_HAPPYQP) && (HAPPY_TIME > 0)) + /* OS compatibility */ #ifndef NULL /** Just in case NULL is not defined. */