/*! \file vote.c This module is a full fledged voting system. \author Jon A. Lambert \version 1.96 \date 06/27/2000 \remarks This code copyright (C) 2000 by Jon A. Lambert<BR> <sourcery@alltel.net> - All rights reserved.<BR> No part of this code may be used without my written consent.<BR> This code released to the PUBLIC DOMAIN on 4/2/2006 */ #include <stdio.h> #include <stdlib.h> #include <time.h> #include "merc.h" #include "recycle.h" #include "tables.h" /* lookup.c */ extern int flag_lookup (const char *name, const struct flag_type *flag_table); #define ISSUES_FILE "issues" #define ISSUE_IMMONLY (A) #define ISSUE_HEROONLY (B) #define ISSUE_ALL (C) #define ISSUE_OPEN (D) #define ISSUE_CLOSED (E) #define ISSUE_DELETED (F) #define ISSUE_SECRET (G) #define ISSUE_TALLY (H) #define ISSUE_NORMAL (I) #define ISSUE_ATCLOSE (J) #define IS_NULLSTR(str) ((str) == NULL || (str)[0] == '\0') #define CHECKNULLSTR(str) ( (str) == NULL ? "" : (str) ) const struct flag_type issue_flags[] = { {"imm", ISSUE_IMMONLY, TRUE}, {"hero", ISSUE_HEROONLY, TRUE}, {"all", ISSUE_ALL, TRUE}, {"open", ISSUE_OPEN, TRUE}, {"closed", ISSUE_CLOSED, TRUE}, {"deleted", ISSUE_DELETED, TRUE}, {"secret", ISSUE_SECRET, TRUE}, {"tally", ISSUE_TALLY, TRUE}, {"normal", ISSUE_NORMAL, TRUE}, {"atclose", ISSUE_ATCLOSE, TRUE}, {NULL, 0, FALSE} }; struct voting_record { char *voting_name; char *voting_ip; struct voting_record *voting_next; }; struct choice_record { int choice_votes; char *choice_text; struct choice_record *choice_next; }; struct issue_record { int issue_no; int issue_votes; long issue_flags; char *issue_text; struct choice_record *issue_choices; struct voting_record *issue_voting; }; int MAX_ISSUES; struct issue_record *issue_table; static void save_issues (void); static void issue_list (CHAR_DATA * ch, char *argument); static void issue_create (CHAR_DATA * ch, char *argument); static void issue_edit (CHAR_DATA * ch, char *argument); static void issue_set (CHAR_DATA * ch, char *argument); static void issue_choice (CHAR_DATA * ch, int issue_no, char *argument); static void vote_result (CHAR_DATA * ch, char *argument); static void vote_for_choice (CHAR_DATA * ch, int issue_no, char *argument); void load_issues (void) { FILE *fp; int i; fp = fopen (ISSUES_FILE, "r"); if (!fp) { bug ("Could not read " ISSUES_FILE " to load voting issues.", 0); exit (1); } int letter; char *word; word = fread_word (fp); if (!str_cmp (word, "#ISSUES")) { MAX_ISSUES = fread_number (fp); issue_table = (struct issue_record *) malloc (sizeof (struct issue_record) * (MAX_ISSUES + 1)); if (!issue_table) { bug ("Error! Voting Issues Table == NULL, MAX_ISSUES : %d", MAX_ISSUES); exit (1); } letter = fread_letter (fp); if (letter != '#') { bug ("Load_issues: # not found.", 0); exit (1); } for (i = 0; i < MAX_ISSUES; ++i) { issue_table[i].issue_choices = NULL; issue_table[i].issue_voting = NULL; issue_table[i].issue_no = fread_number (fp); issue_table[i].issue_votes = fread_number (fp); issue_table[i].issue_flags = fread_flag (fp); issue_table[i].issue_text = fread_string (fp); for (;;) { letter = fread_letter (fp); if (letter == '#') { break; } else if (letter == 'C') { struct choice_record *pChoice = (struct choice_record *) alloc_perm (sizeof (*pChoice)); pChoice->choice_votes = fread_number (fp); pChoice->choice_text = fread_string (fp); pChoice->choice_next = issue_table[i].issue_choices; issue_table[i].issue_choices = pChoice; } else if (letter == 'F') { struct voting_record *pVoting = (struct voting_record *) alloc_perm (sizeof (*pVoting)); pVoting->voting_name = fread_string (fp); pVoting->voting_ip = fread_string (fp); pVoting->voting_next = issue_table[i].issue_voting; issue_table[i].issue_voting = pVoting; } else { bug ("Load_issues: # not found.", 0); exit (1); } } // endfor } // endfor } else { bug ("Load_issues: #ISSUES not found.", 0); exit (1); } log_string ("Table of issues loaded."); fclose (fp); } static void save_issues (void) { int i; FILE *fp; fp = fopen (ISSUES_FILE, "w"); if (!fp) { bug ("save_issues : fp null when saving issues", 0); return; } fprintf (fp, "#ISSUES\n"); fprintf (fp, "%d\n", MAX_ISSUES); for (i = 0; i < MAX_ISSUES; ++i) { // if (IS_SET(issue_table[i].issue_flags,ISSUE_DELETED) // continue; fprintf (fp, "#%d ", issue_table[i].issue_no); fprintf (fp, "%d ", issue_table[i].issue_votes); fprintf (fp, "%s ", print_flags (issue_table[i].issue_flags)); fprintf (fp, "\n"); fprintf (fp, "%s~\n", CHECKNULLSTR (issue_table[i].issue_text)); struct choice_record *pChoice; for (pChoice = issue_table[i].issue_choices; pChoice != NULL; pChoice = pChoice->choice_next) { fprintf (fp, "C\n"); fprintf (fp, "%d ", pChoice->choice_votes); fprintf (fp, "\n"); fprintf (fp, "%s~\n", CHECKNULLSTR (pChoice->choice_text)); } struct voting_record *pVoting; for (pVoting = issue_table[i].issue_voting; pVoting != NULL; pVoting = pVoting->voting_next) { fprintf (fp, "F\n"); fprintf (fp, "%s~\n", CHECKNULLSTR (pVoting->voting_name)); fprintf (fp, "%s~\n", CHECKNULLSTR (pVoting->voting_ip)); } } fprintf (fp, "#0\n\n\n\n"); fclose (fp); } /*! This is the command used to create issues and choices for the voting system. It should be an imm only command. \param ch the character issuing the command. \param argument the string containing the rest of command \return none \remarks Syntax: <> indicates optional | indicates choose one - ISSUE LIST <issue_no|IMM|HERO|CLOSED> shows all OPEN issues by default without parameter, a specific issue #, IMM only, HERO only, or CLOSED issues only. - ISSUE CREATE "Question?" creates a new issue. - ISSUE EDIT issue_no "Question?" changes the issue test. - ISSUE SAVE saves the issues and results. - ISSUE issue_no CHOICE CREATE "choice" creates a new choice for an issue. - ISSUE issue_no CHOICE LIST lists the choices for an issue. - ISSUE issue_no CHOICE DELETE choice_no deletes a choice for an issue. - ISSUE issue_no CHOICE EDIT choice_no "choice" changes the text of a choice. - ISSUE SET issue_no OPEN|CLOSED|DELETED - OPEN opens up the issue for a vote. - CLOSED closes the issue to voting {the default}. - DELETED marks the issue as deleted. - ISSUE SET issue_no IMM|HERO|ALL - IMM makes the issue only appear to IMMORTALS {the default}. - HERO makes the issue only appear to HEROS. - ALL opens the voting to any characters. - NORMAL open to players level 10 and above. {the default} - ISSUE SET issue_no TALLY|SECRET - TALLY allows voting results to be viewed while the issue is open. - SECRET makes voting results only viewable by immortals. - ATCLOSE makes voting results viewable when issue is closed. {the default} */ void do_issue (CHAR_DATA * ch, char *argument) { char arg1[MAX_STRING_LENGTH]; if (IS_NPC (ch)) send_to_char ("NPCs can't set up issues for polls.......yet.", ch); if (IS_NULLSTR (argument)) { send_to_char ("\ Syntax: <> indicates optional | indicates choose one\n\r\ - ISSUE LIST <issue_no|IMM|HERO|CLOSED|NV> shows all OPEN issues\n\r\ by default without parameter, a specific issue #, IMM only,\n\r\ HERO only, CLOSED issues only, or those not voted on.\n\r\ - ISSUE CREATE \"Question?\" creates a new issue.\n\r\ - ISSUE EDIT issue_no \"Question?\" changes the issue test.\n\r\ - ISSUE SAVE saves the issues and results.\n\r\ - ISSUE issue_no CHOICE CREATE \"choice\" creates a new choice for an issue.\n\r\ - ISSUE issue_no CHOICE LIST lists the choices for an issue.\n\r\ - ISSUE issue_no CHOICE DELETE choice_no deletes a choice for an issue.\n\r\ - ISSUE issue_no CHOICE EDIT choice_no \"choice\" changes the text of a choice.\n\r\ - ISSUE SET issue_no OPEN|CLOSED|DELETED\n\r\ - OPEN opens up the issue for a vote.\n\r\ - CLOSED closes the issue to voting {the default}.\n\r\ - DELETED marks the issue as deleted.\n\r\ - ISSUE SET issue_no IMM|HERO|ALL\n\r\ - IMM makes the issue only appear to IMMORTALS {the default}.\n\r\ - HERO makes the issue only appear to HEROS.\n\r\ - ALL opens the voting to any characters.\n\r\ - NORMAL open to players level 10 and above. {the default}\n\r\ - ISSUE SET issue_no TALLY|SECRET\n\r\ - TALLY allows voting results to be viewed while the issue is open.\n\r\ - SECRET makes voting results only viewable by immortals.\n\r\ - ATCLOSE makes voting results viewable when issue is closed. {the default}\n\r\ ", ch); return; } argument = one_argument (argument, arg1); if (!str_prefix (arg1, "list")) { issue_list (ch, argument); } else if (!str_prefix (arg1, "create")) { issue_create (ch, argument); } else if (!str_prefix (arg1, "edit")) { issue_edit (ch, argument); } else if (!str_prefix (arg1, "save")) { save_issues (); } else if (!str_prefix (arg1, "set")) { issue_set (ch, argument); } else if (is_number (arg1)) { issue_choice (ch, atoi (arg1), argument); } else { send_to_char ("Sorry, I don't understand your command.\r\n\r\n", ch); do_issue (ch, NULL); } return; } void issue_list (CHAR_DATA * ch, char *argument) { char arg1[MAX_STRING_LENGTH]; char buf[MAX_STRING_LENGTH]; bool list_nv = FALSE; bool list_all = FALSE; bool list_imm = FALSE; bool list_hero = FALSE; bool list_single = FALSE; bool list_closed = FALSE; int issue_no = 0; // ISSUE LIST <issue_no|IMM|HERO|CLOSED> argument = one_argument (argument, arg1); if (IS_NULLSTR (arg1)) { list_all = TRUE; } else if (is_number (arg1)) { issue_no = atoi (arg1); list_single = TRUE; } else if (!str_prefix (arg1, "imm")) { if (IS_IMMORTAL (ch)) { list_imm = TRUE; } else { send_to_char ("You're not an immortal.\r\n", ch); return; } } else if (!str_prefix (arg1, "hero")) { if (IS_HERO (ch)) { list_hero = TRUE; } else { send_to_char ("You're not a hero yet.\r\n", ch); return; } } else if (!str_prefix (arg1, "closed")) { list_closed = TRUE; } else if (!str_prefix (arg1, "nv")) { list_nv = TRUE; } else { send_to_char ("Sorry, I don't understand your command.\r\n", ch); return; } int i = 0; int single_issue = 0; if (list_single) { for (i = 0; i < MAX_ISSUES; ++i) { if (issue_table[i].issue_no == issue_no) break; } if (i == MAX_ISSUES || IS_SET (issue_table[i].issue_flags, ISSUE_DELETED) || IS_NULLSTR (issue_table[i].issue_text) || (!IS_IMMORTAL (ch) && IS_SET (issue_table[i].issue_flags, ISSUE_IMMONLY)) || (!IS_HERO (ch) && IS_SET (issue_table[i].issue_flags, ISSUE_HEROONLY))) { send_to_char ("Sorry, that issue number is not in the list.\r\n", ch); return; } single_issue = i; } bool any_to_vote_on = FALSE; if (list_nv) { for (i = 0; i < MAX_ISSUES; ++i) { if (IS_SET (issue_table[i].issue_flags, ISSUE_DELETED) || IS_SET (issue_table[i].issue_flags, ISSUE_CLOSED) || IS_NULLSTR (issue_table[i].issue_text) || (!IS_IMMORTAL (ch) && IS_SET (issue_table[i].issue_flags, ISSUE_IMMONLY)) || (!IS_HERO (ch) && IS_SET (issue_table[i].issue_flags, ISSUE_HEROONLY))) { continue; } struct voting_record *pVoting = NULL; bool already_voted = FALSE; for (pVoting = issue_table[i].issue_voting; pVoting != NULL; pVoting = pVoting->voting_next) { if (!str_cmp (ch->name, pVoting->voting_name) || !str_cmp (ch->desc->host, pVoting->voting_ip)) { already_voted = TRUE; break; } } // endfor pVoting if (!already_voted) { any_to_vote_on = TRUE; break; } } // endfor i if (!any_to_vote_on) { send_to_char ("There are no issues left for you to vote on.\r\n", ch); return; } } // endif list_nv // print headers send_to_char ("----------------------- MUD Polling System------------------------\r\n", ch); send_to_char ("Legend: [O]pen for votes, [C]losed for votes\r\n", ch); send_to_char (" [A]nyone can vote, [L]evel 10+ can vote, [I]mm only, [H]ero only\r\n", ch); send_to_char (" [T] results tallied, [X] results at close, [S] results secret\r\n\r\n", ch); if (list_single) { sprintf (buf, "%d) [%s%s%s] %s\r\n\r\n", issue_table[single_issue].issue_no, IS_SET (issue_table[single_issue].issue_flags, ISSUE_OPEN) ? "O" : IS_SET (issue_table[single_issue]. issue_flags, ISSUE_CLOSED) ? "C" : "D", IS_SET (issue_table[single_issue].issue_flags, ISSUE_TALLY) ? "T" : IS_SET (issue_table[single_issue]. issue_flags, ISSUE_SECRET) ? "S" : "X", IS_SET (issue_table[single_issue].issue_flags, ISSUE_ALL) ? "A" : IS_SET (issue_table[single_issue]. issue_flags, ISSUE_HEROONLY) ? "H" : IS_SET (issue_table[single_issue].issue_flags, ISSUE_IMMONLY) ? "I" : "L", issue_table[i].issue_text); send_to_char (buf, ch); struct choice_record *pChoice = NULL; int choice_count = 0; for (pChoice = issue_table[single_issue].issue_choices; pChoice != NULL; pChoice = pChoice->choice_next) { if (!IS_NULLSTR (pChoice->choice_text)) { choice_count++; sprintf (buf, " %d) %s\r\n", choice_count, pChoice->choice_text); send_to_char (buf, ch); } } if (choice_count == 0) { send_to_char ("Sorry there are no choices for this issue.\r\n", ch); } return; } if (!list_hero && !list_imm && !list_all && !list_closed && !list_nv) { send_to_char ("Sorry, I don't understand your command.\r\n", ch); return; } BUFFER *buffer = new_buf (); bool some_issues = FALSE; for (i = 0; i < MAX_ISSUES; ++i) { if (IS_SET (issue_table[i].issue_flags, ISSUE_DELETED) || IS_NULLSTR (issue_table[i].issue_text) || (list_hero && !IS_SET (issue_table[i].issue_flags, ISSUE_HEROONLY)) || (list_imm && !IS_SET (issue_table[i].issue_flags, ISSUE_IMMONLY)) || (list_closed && !IS_SET (issue_table[i].issue_flags, ISSUE_CLOSED)) || (!list_closed && IS_SET (issue_table[i].issue_flags, ISSUE_CLOSED)) || (!IS_IMMORTAL (ch) && IS_SET (issue_table[i].issue_flags, ISSUE_IMMONLY)) || (!IS_HERO (ch) && IS_SET (issue_table[i].issue_flags, ISSUE_HEROONLY))) { continue; } struct voting_record *pVoting = NULL; bool already_voted = FALSE; for (pVoting = issue_table[i].issue_voting; pVoting != NULL; pVoting = pVoting->voting_next) { if (!str_cmp (ch->name, pVoting->voting_name) || !str_cmp (ch->desc->host, pVoting->voting_ip)) { already_voted = TRUE; break; } } // endfor pVoting if (list_nv && already_voted) { continue; } some_issues = TRUE; sprintf (buf, "%d) [%s%s%s] %s\r\n", issue_table[i].issue_no, IS_SET (issue_table[i].issue_flags, ISSUE_OPEN) ? "O" : IS_SET (issue_table[i].issue_flags, ISSUE_CLOSED) ? "C" : "D", IS_SET (issue_table[i].issue_flags, ISSUE_TALLY) ? "T" : IS_SET (issue_table[i].issue_flags, ISSUE_SECRET) ? "S" : "X", IS_SET (issue_table[i].issue_flags, ISSUE_ALL) ? "A" : IS_SET (issue_table[i].issue_flags, ISSUE_HEROONLY) ? "H" : IS_SET (issue_table[i].issue_flags, ISSUE_IMMONLY) ? "I" : "L", issue_table[i].issue_text); add_buf (buffer, buf); } if (!some_issues) { add_buf (buffer, "Sorry there are no issues listed.\r\n"); } page_to_char (buf_string (buffer), ch); free_buf (buffer); } void issue_create (CHAR_DATA * ch, char *argument) { if (IS_NULLSTR (argument)) { send_to_char ("\ Syntax: <> indicates optional parameters\r\n\ - ISSUE CREATE \"Question?\" creates a new issue\r\n\ ", ch); return; } struct issue_record *new_table; MAX_ISSUES++; new_table = (struct issue_record *) realloc (issue_table, sizeof (struct issue_record) * (MAX_ISSUES + 1)); if (!new_table) { /* realloc failed */ bug ("failed to realloc issues.", 0); return; } issue_table = new_table; issue_table[MAX_ISSUES - 1].issue_choices = NULL; issue_table[MAX_ISSUES - 1].issue_voting = NULL; issue_table[MAX_ISSUES - 1].issue_no = MAX_ISSUES; issue_table[MAX_ISSUES - 1].issue_votes = 0; issue_table[MAX_ISSUES - 1].issue_flags = 0; SET_BIT (issue_table[MAX_ISSUES - 1].issue_flags, ISSUE_CLOSED); SET_BIT (issue_table[MAX_ISSUES - 1].issue_flags, ISSUE_IMMONLY); smash_tilde (argument); issue_table[MAX_ISSUES - 1].issue_text = str_dup (argument); send_to_char ("Issue created. It is flagged closed and imm only by default.\r\n", ch); } void issue_edit (CHAR_DATA * ch, char *argument) { char arg1[MAX_STRING_LENGTH]; if (IS_NULLSTR (argument)) { send_to_char ("\ Syntax: <> indicates optional parameters\r\n\ - ISSUE EDIT issue_no \"Question?\" changes the issue test\r\n\ ", ch); return; } argument = one_argument (argument, arg1); if (!is_number (arg1)) { send_to_char ("Invalid issue number.\r\n", ch); return; } int issue_no = atoi (arg1); int i = 0; for (i = 0; i < MAX_ISSUES; i++) { if (issue_table[i].issue_no == issue_no) break; } if (i == MAX_ISSUES) { send_to_char ("Sorry, that issue number is not in the list.\r\n", ch); return; } if (IS_NULLSTR (argument)) { send_to_char ("You must include the question text.\r\n", ch); return; } free_string (issue_table[i].issue_text); smash_tilde (argument); issue_table[i].issue_text = str_dup (argument); send_to_char ("Question text has been changed.\r\n", ch); } void issue_set (CHAR_DATA * ch, char *argument) { char arg1[MAX_STRING_LENGTH]; if (IS_NULLSTR (argument)) { send_to_char ("\ ISSUE SET issue_no OPEN|CLOSED|DELETED\r\n\ - OPEN opens up the issue for a vote.\r\n\ - CLOSED closes the issue to voting {the default}.\r\n\ - DELETED marks the issue as deleted.\r\n\ ISSUE SET issue_no IMM|HERO|ALL\r\n\ - IMM makes the issue only appear to IMMORTALS {the default}.\r\n\ - HERO makes the issue only appear to HEROS.\r\n\ - ALL opens the voting to any characters.\r\n\ - NORMAL open to players level 10 and above. {the default}\r\n\ ISSUE SET issue_no TALLY|SECRET\r\n\ - TALLY allows voting results to be viewed while the issue is open.\r\n\ - SECRET makes voting results only viewable by immortals.\r\n\ - ATCLOSE makes voting results viewable when issue is closed. {the default}\r\n\ ", ch); return; } argument = one_argument (argument, arg1); if (!is_number (arg1)) { send_to_char ("Invalid issue number.\r\n", ch); return; } int issue_no = atoi (arg1); int i = 0; for (i = 0; i < MAX_ISSUES; i++) { if (issue_table[i].issue_no == issue_no) break; } if (i == MAX_ISSUES) { send_to_char ("Sorry, that issue number is not in the list.\r\n", ch); return; } argument = one_argument (argument, arg1); if (IS_NULLSTR (arg1)) { send_to_char ("No settings specified.\r\n", ch); issue_set (ch, ""); return; } int value = flag_lookup (arg1, issue_flags); switch (value) { case ISSUE_OPEN:; SET_BIT (issue_table[i].issue_flags, ISSUE_OPEN); REMOVE_BIT (issue_table[i].issue_flags, ISSUE_CLOSED); REMOVE_BIT (issue_table[i].issue_flags, ISSUE_DELETED); break; case ISSUE_CLOSED: SET_BIT (issue_table[i].issue_flags, ISSUE_CLOSED); REMOVE_BIT (issue_table[i].issue_flags, ISSUE_OPEN); REMOVE_BIT (issue_table[i].issue_flags, ISSUE_DELETED); break; case ISSUE_DELETED: SET_BIT (issue_table[i].issue_flags, ISSUE_DELETED); REMOVE_BIT (issue_table[i].issue_flags, ISSUE_CLOSED); REMOVE_BIT (issue_table[i].issue_flags, ISSUE_OPEN); break; case ISSUE_IMMONLY: SET_BIT (issue_table[i].issue_flags, ISSUE_IMMONLY); REMOVE_BIT (issue_table[i].issue_flags, ISSUE_HEROONLY); REMOVE_BIT (issue_table[i].issue_flags, ISSUE_ALL); REMOVE_BIT (issue_table[i].issue_flags, ISSUE_NORMAL); break; case ISSUE_HEROONLY: SET_BIT (issue_table[i].issue_flags, ISSUE_HEROONLY); REMOVE_BIT (issue_table[i].issue_flags, ISSUE_IMMONLY); REMOVE_BIT (issue_table[i].issue_flags, ISSUE_ALL); REMOVE_BIT (issue_table[i].issue_flags, ISSUE_NORMAL); break; case ISSUE_ALL: SET_BIT (issue_table[i].issue_flags, ISSUE_ALL); REMOVE_BIT (issue_table[i].issue_flags, ISSUE_HEROONLY); REMOVE_BIT (issue_table[i].issue_flags, ISSUE_IMMONLY); REMOVE_BIT (issue_table[i].issue_flags, ISSUE_NORMAL); break; case ISSUE_NORMAL: SET_BIT (issue_table[i].issue_flags, ISSUE_NORMAL); REMOVE_BIT (issue_table[i].issue_flags, ISSUE_HEROONLY); REMOVE_BIT (issue_table[i].issue_flags, ISSUE_IMMONLY); REMOVE_BIT (issue_table[i].issue_flags, ISSUE_ALL); break; case ISSUE_TALLY:; SET_BIT (issue_table[i].issue_flags, ISSUE_TALLY); REMOVE_BIT (issue_table[i].issue_flags, ISSUE_SECRET); REMOVE_BIT (issue_table[i].issue_flags, ISSUE_ATCLOSE); break; case ISSUE_SECRET:; SET_BIT (issue_table[i].issue_flags, ISSUE_SECRET); REMOVE_BIT (issue_table[i].issue_flags, ISSUE_TALLY); REMOVE_BIT (issue_table[i].issue_flags, ISSUE_ATCLOSE); break; case ISSUE_ATCLOSE:; SET_BIT (issue_table[i].issue_flags, ISSUE_ATCLOSE); REMOVE_BIT (issue_table[i].issue_flags, ISSUE_SECRET); REMOVE_BIT (issue_table[i].issue_flags, ISSUE_TALLY); break; default: send_to_char ("Invalid setting.\r\n", ch); issue_set (ch, ""); return; } send_to_char ("Ok. Issue setting changed.\r\n", ch); } void issue_choice (CHAR_DATA * ch, int issue_no, char *argument) { char arg1[MAX_STRING_LENGTH]; char arg2[MAX_STRING_LENGTH]; char buf[MAX_STRING_LENGTH]; int i = 0; if (IS_NULLSTR (argument)) { send_to_char ("\ Syntax: <> indicates optional parameters\r\n\ - ISSUE issue_no CHOICE CREATE \"choice\" creates a new choice for an issue\r\n\ - ISSUE issue_no CHOICE LIST lists the choices for an issue\r\n\ - ISSUE issue_no CHOICE DELETE choice_no deletes a choice for an issue\r\n\ - ISSUE issue_no CHOICE EDIT choice_no \"choice\" changes the text of a choice\r\n\ ", ch); return; } argument = one_argument (argument, arg1); if (str_prefix (arg1, "choice")) { send_to_char ("Invalid argument.\r\n", ch); issue_choice (ch, 0, ""); return; } argument = one_argument (argument, arg1); if (IS_NULLSTR (arg1)) { send_to_char ("Invalid argument.\r\n", ch); issue_choice (ch, 0, ""); return; } for (i = 0; i < MAX_ISSUES; i++) { if (issue_table[i].issue_no == issue_no) break; } if (i == MAX_ISSUES) { send_to_char ("Sorry, that issue number is not in the list.\r\n", ch); return; } struct choice_record *pChoice = NULL; if (!str_prefix (arg1, "create")) { // Create new choice pChoice = (struct choice_record *) alloc_perm (sizeof (*pChoice)); pChoice->choice_votes = 0; smash_tilde (argument); pChoice->choice_text = str_dup (argument); pChoice->choice_next = issue_table[i].issue_choices; issue_table[i].issue_choices = pChoice; send_to_char ("A new choice has been created.\r\n", ch); } else if (!str_prefix (arg1, "list")) { struct choice_record *pChoice = NULL; int choice_count = 0; for (pChoice = issue_table[i].issue_choices; pChoice != NULL; pChoice = pChoice->choice_next) { choice_count++; sprintf (buf, " %d) %s\r\n", choice_count, pChoice->choice_text); send_to_char (buf, ch); } if (choice_count == 0) { send_to_char ("Sorry there are no choices for this issue.\r\n", ch); } } else if (!str_prefix (arg1, "delete")) { argument = one_argument (argument, arg2); if (!is_number (arg2)) { send_to_char ("Invalid choice number.\r\n", ch); return; } int choice = atoi (arg2); int choice_count = 0; bool choice_found = FALSE; struct choice_record *pPrev; for (pPrev = NULL, pChoice = issue_table[i].issue_choices; pChoice != NULL; pPrev = pChoice, pChoice = pChoice->choice_next) { choice_count++; if (choice == choice_count) { choice_found = TRUE; if (!pPrev) issue_table[i].issue_choices = pChoice->choice_next; else pPrev->choice_next = pChoice->choice_next; free_string (pChoice->choice_text); break; } } if (!choice_found) { send_to_char ("Invalid choice number.\r\n", ch); return; } send_to_char ("Choice deleted.\r\n", ch); } else if (!str_prefix (arg1, "edit")) { argument = one_argument (argument, arg2); if (!is_number (arg2)) { send_to_char ("Invalid choice number.\r\n", ch); return; } int choice = atoi (arg2); int choice_count = 0; bool choice_found = FALSE; for (pChoice = issue_table[i].issue_choices; pChoice != NULL; pChoice = pChoice->choice_next) { choice_count++; if (choice == choice_count) { choice_found = TRUE; free_string (pChoice->choice_text); smash_tilde (argument); pChoice->choice_text = str_dup (argument); break; } } if (!choice_found) { send_to_char ("Invalid choice number.\r\n", ch); return; } send_to_char ("Choice text edited.\r\n", ch); } else { send_to_char ("Invalid argument.\r\n", ch); issue_choice (ch, 0, ""); return; } } /*! This is the command used by players/imms to vote on issues. It should be available to all. \param ch the character issuing the command. \param argument the string containing the rest of command \return none \remarks Syntax: <> indicates optional parameter - VOTE LIST <issue_no|HERO|CLOSED> shows all OPEN issues by default without parameter, a specific issue #, HERO only, or CLOSED issues only. - VOTE LIST <issue> shows a list of issues or a specific one. - VOTE RESULT issue shows the voting results of an issue. - VOTE choice ON issue votes for a choice # on a given issue #. */ void do_vote (CHAR_DATA * ch, char *argument) { char arg1[MAX_STRING_LENGTH]; if (IS_NPC (ch)) send_to_char ("NPCs can't vote.......yet.", ch); if (IS_NULLSTR (argument)) { send_to_char ("\ Syntax: <> indicates optional parameter\r\n\ - VOTE LIST <issue_no|IMM|HERO|CLOSED|NV> shows all OPEN issues\r\n\ by default without parameter, a specific issue #, IMM only,\r\n\ HERO only, CLOSED issues only, or those not voted on.\r\n\ - VOTE RESULT issue shows the voting results of an issue.\r\n\ - VOTE choice ON issue votes for a choice # on a given issue #.\r\n\ ", ch); return; } argument = one_argument (argument, arg1); if (!str_prefix (arg1, "list")) { issue_list (ch, argument); } else if (!str_prefix (arg1, "result")) { vote_result (ch, argument); } else if (is_number (arg1)) { vote_for_choice (ch, atoi (arg1), argument); } else { send_to_char ("Sorry, I don't understand your command.\r\n", ch); do_vote (ch, NULL); } return; } void vote_result (CHAR_DATA * ch, char *argument) { char arg1[MAX_STRING_LENGTH]; char buf[MAX_STRING_LENGTH]; int issue_no = 0; int i = 0; if (IS_NULLSTR (argument)) { send_to_char ("\ Syntax: <> indicates optional parameter\r\n\ - VOTE RESULT issue shows the voting results of an issue.\r\n\ ", ch); return; } argument = one_argument (argument, arg1); if (!is_number (arg1)) { send_to_char ("Invalid issue number.\r\n", ch); return; } issue_no = atoi (arg1); for (i = 0; i < MAX_ISSUES; i++) { if (issue_table[i].issue_no == issue_no) break; } if (i == MAX_ISSUES || IS_NULLSTR (issue_table[i].issue_text) || (!IS_IMMORTAL (ch) && IS_SET (issue_table[i].issue_flags, ISSUE_IMMONLY)) || (!IS_HERO (ch) && IS_SET (issue_table[i].issue_flags, ISSUE_HEROONLY)) || IS_SET (issue_table[i].issue_flags, ISSUE_DELETED)) { send_to_char ("That issue cannot be found.\r\n", ch); return; } if (!IS_IMMORTAL (ch) && !IS_SET (issue_table[i].issue_flags, ISSUE_TALLY) && IS_SET (issue_table[i].issue_flags, ISSUE_OPEN)) { send_to_char ("Results can be viewed when that issue is closed.\r\n", ch); return; } if (!IS_IMMORTAL (ch) && IS_SET (issue_table[i].issue_flags, ISSUE_SECRET)) { send_to_char ("Results of this issue have been closed to public viewing.\r\n", ch); return; } send_to_char ("-----------------------MUD Polling System------------------------\r\n", ch); sprintf (buf, "%d) %s\r\n", issue_table[i].issue_no, issue_table[i].issue_text); send_to_char (buf, ch); sprintf (buf, "%d votes were cast on this issue and the results are...\r\n\r\n", issue_table[i].issue_votes); send_to_char (buf, ch); struct choice_record *pChoice = NULL; int choice_count = 0; for (pChoice = issue_table[i].issue_choices; pChoice != NULL; pChoice = pChoice->choice_next) { int percent = 0; if (!IS_NULLSTR (pChoice->choice_text)) { if (issue_table[i].issue_votes > 0) { percent = 100 * pChoice->choice_votes / issue_table[i].issue_votes; } choice_count++; sprintf (buf, " %d) %-50s ---> %d votes (%d%%)\r\n", choice_count, pChoice->choice_text, pChoice->choice_votes, percent); send_to_char (buf, ch); } } if (choice_count == 0) { send_to_char ("Sorry there are no choices listed for this issue.\r\n", ch); } } void vote_for_choice (CHAR_DATA * ch, int choice, char *argument) { char arg1[MAX_STRING_LENGTH]; int issue_no = 0; int i = 0; if (IS_NULLSTR (argument)) { send_to_char ("\ Syntax: <> indicates optional parameter\r\n\ - VOTE choice ON issue votes for a choice # on a given issue #.\r\n\ ", ch); return; } argument = one_argument (argument, arg1); if (str_prefix (arg1, "on")) { send_to_char ("Sorry, I don't understand your command.\r\n", ch); // force syntax error vote_for_choice (ch, 0, ""); return; } argument = one_argument (argument, arg1); if (!is_number (arg1)) { send_to_char ("That's not a valid issue number.\r\n", ch); return; } issue_no = atoi (arg1); for (i = 0; i < MAX_ISSUES; i++) { if (issue_table[i].issue_no == issue_no) break; } if (i == MAX_ISSUES || IS_NULLSTR (issue_table[i].issue_text) || (!IS_IMMORTAL (ch) && IS_SET (issue_table[i].issue_flags, ISSUE_IMMONLY)) || (!IS_HERO (ch) && IS_SET (issue_table[i].issue_flags, ISSUE_HEROONLY)) || IS_SET (issue_table[i].issue_flags, ISSUE_DELETED)) { send_to_char ("That issue cannot be found.\r\n", ch); return; } if (IS_SET (issue_table[i].issue_flags, ISSUE_CLOSED)) { send_to_char ("That issue is closed and cannot be voted on.\r\n", ch); return; } if (!IS_SET (issue_table[i].issue_flags, ISSUE_ALL) && ch->level < 10) { send_to_char ("You must be at level 10 or above to vote on that issue.\r\n", ch); return; } struct voting_record *pVoting = NULL; bool already_voted = FALSE; for (pVoting = issue_table[i].issue_voting; pVoting != NULL; pVoting = pVoting->voting_next) { if (!str_cmp (ch->name, pVoting->voting_name) || !str_cmp (ch->desc->host, pVoting->voting_ip)) already_voted = TRUE; } if (already_voted) { send_to_char ("You have already voted on that issue.\r\n", ch); return; } struct choice_record *pChoice = NULL; int choice_count = 0; for (pChoice = issue_table[i].issue_choices; pChoice != NULL; pChoice = pChoice->choice_next) { choice_count++; if (choice == choice_count) { // record vote issue_table[i].issue_votes++; pChoice->choice_votes++; break; } } if (pChoice == NULL) { send_to_char ("Sorry that is not a valid choice.\r\n", ch); return; } // Update that we voted pVoting = (struct voting_record *) alloc_perm (sizeof (*pVoting)); pVoting->voting_name = str_dup (ch->name); pVoting->voting_ip = str_dup (ch->desc->host); pVoting->voting_next = issue_table[i].issue_voting; issue_table[i].issue_voting = pVoting; send_to_char ("Your vote has been recorded.\r\n", ch); save_issues (); }