/** * dice.C: Dice generator. * * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team * Rights to this code are as documented in COPYING. * * * Portions of this file were derived from sources bearing the following license: * Copyright © 2005-2007 William Pitcock * Copyright © 2006-2007 Jilles Tjoelker * * Rights to this code are documented in doc/pod/license.pod. * * $Id: dice.C,v 1.7 2007/09/22 14:27:27 pippijn Exp $ */ #include "atheme.h" #include #include static char const rcsid[] = "$Id: dice.C,v 1.7 2007/09/22 14:27:27 pippijn Exp $"; REGISTER_MODULE ("gameserv/dice", false, "The Ermyth Team "); static void command_dice (sourceinfo_t *si, int parc, char *parv[]); static void command_wod (sourceinfo_t *si, int parc, char *parv[]); static void command_df (sourceinfo_t *si, int parc, char *parv[]); command_t const cmd_dice = { "ROLL", N_("Rolls one or more dice."), AC_NONE, 2, command_dice }; command_t const cmd_wod = { "WOD", N_("WOD-style dice generation."), AC_NONE, 7, command_wod }; command_t const cmd_df = { "DF", N_("Fudge-style dice generation."), AC_NONE, 2, command_df }; E cmdvec gs_cmdtree; E cmdvec cs_cmdtree; E helpvec gs_helptree; E helpvec cs_helptree; bool _modinit (module *m) { gs_cmdtree << cmd_dice; gs_cmdtree << cmd_wod; gs_cmdtree << cmd_df; cs_cmdtree << cmd_dice; cs_cmdtree << cmd_wod; cs_cmdtree << cmd_df; help_addentry (gs_helptree, "ROLL", "help/gameserv/roll", NULL); help_addentry (cs_helptree, "ROLL", "help/gameserv/roll", NULL); return true; } void _moddeinit () { gs_cmdtree >> cmd_dice; gs_cmdtree >> cmd_wod; gs_cmdtree >> cmd_df; cs_cmdtree >> cmd_dice; cs_cmdtree >> cmd_wod; cs_cmdtree >> cmd_df; help_delentry (gs_helptree, "ROLL"); help_delentry (cs_helptree, "ROLL"); } /* * Handle reporting for both fantasy commands and normal commands in GameServ * quickly and easily. Of course, sourceinfo has a vtable that can be manipulated, * but this is quicker and easier... -- nenolod */ static void gs_command_report (sourceinfo_t *si, char const * const fmt, ...) { va_list args; char buf[BUFSIZE]; va_start (args, fmt); vsnprintf (buf, BUFSIZE, fmt, args); va_end (args); if (si->c != NULL) phandler->privmsg (chansvs.nick, si->c->name, "%s", buf); else command_success_nodata (si, "%s", buf); } static void command_dice (sourceinfo_t *si, int parc, char *parv[]) { char *arg = si->c != NULL ? parv[1] : parv[0]; int dice = 0, sides = 0, i = 0, roll = 0, modifier = 0; char buf[BUFSIZE]; if (!arg) return; sscanf (arg, "%dd%d+%d", &dice, &sides, &modifier); if (dice <= 0) { modifier = 0; sscanf (arg, "%dd%d", &dice, &sides); if (dice <= 0) { dice = 1; sscanf (arg, "d%d+%d", &sides, &modifier); if (sides <= 0) sscanf (arg, "d%d", &sides); } } if (dice > 100) dice = 100; if (sides > 100) sides = 100; if (dice <= 0 || sides <= 0) { dice = 1; sides = 1; } *buf = '\0'; for (i = 0; i < dice; i++) { unsigned int y = 1 + gen_rand32 () % sides; char buf2[BUFSIZE]; if (*buf != '\0') { snprintf (buf2, BUFSIZE, ", %d", y); strlcat (buf, buf2, BUFSIZE); } else { snprintf (buf2, BUFSIZE, "%d", y); strlcpy (buf, buf2, BUFSIZE); } roll += y; } if (modifier != 0) gs_command_report (si, "(%s) + %d == \2%d\2", buf, modifier, (roll + modifier)); else gs_command_report (si, "%s == \2%d\2", buf, roll); } static void command_wod (sourceinfo_t *si, int parc, char *parv[]) { int ii = si->c != NULL ? 1 : 0; char *arg_dice = parv[ii++]; char *arg_difficulty = parv[ii++]; int dice, difficulty; int roll, total = 0, roll_count = 0, i; int success = 0, failure = 0, botches = 0, rerolls = 0; static char buf[BUFSIZE]; char *end_p; if (arg_dice == NULL || arg_difficulty == NULL) { command_fail (si, fault::needmoreparams, _("Syntax: WOD ")); return; } while (roll_count < 3 && arg_dice != NULL && arg_difficulty != NULL) { total = 0, success = 0, failure = 0, botches = 0, rerolls = 0; roll_count++; dice = atoi (arg_dice); difficulty = atoi (arg_difficulty); if (dice > 30 || dice < 1) { command_fail (si, fault::badparams, _("Only 1-30 dice may be thrown at one time.")); return; } else if (difficulty > 10 || difficulty < 1) { command_fail (si, fault::badparams, _("Difficulty setting must be between 1 and 10.")); return; } else { end_p = buf; for (i = 0; i < dice; i++) { roll = (gen_rand32 () % 10) + 1; end_p += snprintf (end_p, BUFSIZE - (end_p - buf), "%d ", roll); if (roll == 1) { botches++; continue; } else if (roll == 10) rerolls++; if (roll >= difficulty) success++; else failure++; } rerolls = rerolls - botches; total = success - botches; gs_command_report (si, _("%s rolls %d dice at difficulty %d: %s"), si->su->nick, dice, difficulty, buf); if (rerolls > 0) gs_command_report (si, _("Successes: %d, Failures: %d, Botches: %d, Total: %d. You may reroll %d if you have a specialty."), success, failure, botches, total, rerolls); else gs_command_report (si, _("Successes: %d, Failures: %d, Botches: %d, Total: %d."), success, failure, botches, total); } /* prepare for another go. */ arg_dice = parv[ii++]; arg_difficulty = parv[ii++]; } } static char const * const df_dice_table[] = { "[-]", "[ ]", "[+]" }; static void command_df (sourceinfo_t *si, int parc, char *parv[]) { int ii = si->c != NULL ? 1 : 0; char *arg_dice = parv[ii++]; char buf[BUFSIZE]; int i, dice; if (arg_dice == NULL) { command_fail (si, fault::needmoreparams, _("Syntax: DF ")); return; } dice = atoi (arg_dice); *buf = '\0'; if (dice > 30 || dice < 1) { command_fail (si, fault::badparams, _("Only 1-30 dice may be thrown at one time.")); return; } for (i = 0; i < dice; i++) { int roll = gen_rand32 () % 3; if (*buf != '\0') strlcat (buf, df_dice_table[roll], BUFSIZE); else strlcpy (buf, df_dice_table[roll], BUFSIZE); } gs_command_report (si, _("Result: %s"), buf); }