/*************************************************************************** * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * * * Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * * * In order to use any part of this Envy Diku Mud, you must comply with * * the original Diku license in 'license.doc', the Merc license in * * 'license.txt', as well as the Envy license in 'license.nvy'. * * In particular, you may not remove either of these copyright notices. * * * * Much time and thought has gone into this software and you are * * benefitting. We hope that you share your changes too. What goes * * around, comes around. * * * * ROM 2.4 is copyright 1993-1998 Russ Taylor * * ROM has been brought to you by the ROM consortium * * Russ Taylor (rtaylor@hypercube.org) * * Gabrielle Taylor (gtaylor@hypercube.org) * * Brian Moore (zump@rom.org) * * By using this code, you have agreed to follow the terms of the * * ROM license, in the file Rom24/doc/rom.license * * * * Code Adapted and Improved by Abandoned Realms Mud * * and Aabahran: The Forsaken Lands Mud by Virigoth * * * * Continued Production of this code is available at www.flcodebase.com * ***************************************************************************/ #include <sys/types.h> #include <ctype.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <time.h> #include <malloc.h> #include "merc.h" #include "vote.h" #include "cabal.h" #include "save_mud.h" #include "recycle.h" #include "interp.h" #include "jail.h" #include "olc.h" #include "db.h" #include "armies.h" #include "tome.h" #include "clan.h" /***************************************************************/ /*Following are vote orientanted routines for Forsaken Lands */ /*mud created by Virigoth circa 2002. Copyrighted for Forsaken*/ /*Lands mud Feb 20, 2002. Do not use or copy without explicit */ /*permission of author. (Voytek Plawny aka Virigoth) */ /***************************************************************/ extern void connect_char( DESCRIPTOR_DATA* d ); /* global vote list */ VOTE_DATA* vote_list = NULL; /* table listing all the possible votes, entries MUST correspond to the "type" constant */ const struct vote_type vote_table [] = { /* name life_time flags */ {"none", 0, 0 }, {"general vote", VOTE_DUR_LONG, VOTE_URGE | VOTE_SUBJ | VOTE_NOOWNER | VOTE_DUP | VOTE_NOCAB_COST}, {"cabal application", VOTE_DUR_LONG, VOTE_NOOWNER }, {"promotion", VOTE_DUR_VLONG, VOTE_URGE }, {"demotion", VOTE_DUR_LONG, 0 }, {"eldership", VOTE_DUR_VLONG, 0 }, {"leadership", VOTE_DUR_VLONG, 0 }, {"poll", VOTE_DUR_MED, VOTE_URGE | VOTE_SUBJ | VOTE_NOOWNER | VOTE_DUP | VOTE_NOCAB_COST}, {"laws", VOTE_DUR_VLONG, VOTE_URGE }, {"pact", VOTE_DUR_VLONG, VOTE_URGE }, {"cabal tax", VOTE_DUR_MED, VOTE_URGE }, {"build", VOTE_DUR_MED, VOTE_URGE }, {"tithe", VOTE_DUR_SHORT, VOTE_URGE }, {"expel", VOTE_DUR_VLONG, VOTE_URGE }, {"sponsorship", VOTE_DUR_LONG, VOTE_URGE | VOTE_NOOWNER}, {"tome", VOTE_DUR_VLONG, 0 }, {NULL, 0, 0} }; int vote_lookup (const char *name ){ int vote; for (vote = 0; vote_table[vote].name != NULL; vote++){ if (LOWER(name[0]) == LOWER(vote_table[vote].name[0]) && !str_prefix(name, vote_table[vote].name)) return vote; } return 0; } void show_votes( CHAR_DATA* ch ){ int vote; for (vote = 1; vote_table[vote].name != NULL; vote++){ sendf( ch, "%-2d. %-30s [%-2d days]\n\r", vote, vote_table[vote].name, vote_table[vote].life_time / VOTE_DAY); } } /* creates destroys votes */ VOTE_DATA *vote_free; VOTE_DATA *new_vote() { VOTE_DATA *vote; if (vote_free == NULL) vote = alloc_perm(sizeof(*vote)); else { vote = vote_free; vote_free = vote_free->next; } VALIDATE(vote); return vote; } void free_vote(VOTE_DATA *vote) { if (!IS_VALID(vote)) return; if (!IS_NULLSTR(vote->owner)) free_string( vote->owner); if (!IS_NULLSTR(vote->from)) free_string( vote->from ); if (!IS_NULLSTR(vote->subject)) free_string( vote->subject ); if (!IS_NULLSTR(vote->string)) free_string( vote->string ); INVALIDATE(vote); vote->next = vote_free; vote_free = vote; } /* adds a vote onto the vote list */ void add_vote( VOTE_DATA* pv ){ CHAR_DATA* vch; if (vote_list == NULL){ vote_list = pv; pv->next = NULL; } else{ /* we always insert the votes from oldest to newest */ VOTE_DATA* last = vote_list; for (last = vote_list; last->next != NULL; last = last->next); pv->time_stamp = UMAX(last->time_stamp + 1, pv->time_stamp ); last->next = pv; pv->next = NULL; } /* Let char know he/they recived a vote */ for ( vch = player_list; vch != NULL; vch = vch->next_player ){ if (is_vote_to(vch, pv) ) act_new("`8A messenger hands you a scroll marked \"vote\"``.", vch, NULL, NULL, TO_CHAR, POS_DEAD); } } /* removes a vote from the vote list */ bool rem_vote( VOTE_DATA* pv ){ VOTE_DATA* prev = vote_list; if (vote_list == NULL){ bug("rem_vote: vote_list null.", 0); return FALSE; } if (prev == pv ) vote_list = pv->next; else{ while (prev->next && prev->next != pv){ prev = prev->next; } } if (prev == NULL){ bug("rem_vote: vote note found.", 0); return FALSE; } prev->next = pv->next; pv->next = NULL; return TRUE; } /* writes the data of a single vote */ /* votes are saved in mudsave file */ void write_vote(FILE* fp, VOTE_DATA* vote){ int i = 0; /* owner, subject, type */ fprintf( fp, "%s~ %s~ %s~ %d\n", vote->owner, vote->from, vote->subject, vote->type); /* votes yes, no, pass, max vaote*/ fprintf( fp, "%d %d %d %d\n", vote->yes, vote->no, vote->pass, vote->max_vote ); /* time stamp, and lifetime */ fprintf( fp, "%ld %ld\n", vote->time_stamp, vote->life_time); /* values */ fprintf(fp, "%d ", VOTE_VALS); for (i = 0; i < VOTE_VALS; i++){ fprintf( fp, "%d ", vote->value[i]); } fprintf( fp, "\n"); /* text/string */ fprintf( fp, "%s~", vote->string); fprintf( fp, "\n" ); } /* reads the data of a single vote */ void read_vote(FILE* fp, VOTE_DATA* vote){ int vals = VOTE_VALS; int i = 0; vote->owner = fread_string( fp ); vote->from = fread_string( fp ); vote->subject = fread_string( fp ); vote->type = fread_number( fp ); vote->yes = fread_number( fp ); vote->no = fread_number( fp ); vote->pass = fread_number( fp ); vote->max_vote = fread_number( fp ); vote->time_stamp = fread_number( fp ); vote->life_time = fread_number( fp ); vals = fread_number( fp ); for (i = 0; i < VOTE_VALS; i ++){ if (i < vals) vote->value[i] = fread_number( fp ); else vote->value[i] = 0; } vote->string = fread_string( fp ); VALIDATE( vote ); } /* sets up a vote weight based on cabal */ int get_max_vote( CABAL_DATA* pc, int type ){ CMEMBER_DATA* cm; int mod = 1; int max_vote = 0; if (IS_CABAL(pc, CABAL_ROYAL) ){ mod = 10; /* Viri: Not used, citizens can try to sway the royal votes check if this is one of the votes that citizens vote on if (type == VOTE_CAB_APPLY || type == VOTE_PACT || type == VOTE_CAB_SPONS || type == VOTE_LAW){ max_vote += mud_data.pfiles / 15; } */ } /* run through all members of the cabal and tally up the total */ for (cm = get_parent(pc)->members; cm; cm = cm->next ){ if (mud_data.current_time - cm->last_login > 4 * VOTE_DAY) continue; if (cm->rank == RANK_LEADER){ if (str_cmp(cm->name, get_parent(cm->pCabal)->immortal)) max_vote += VOTE_WEIGHT_LEADER * mod; } else if (cm->rank == RANK_ELDER) max_vote += VOTE_WEIGHT_ELDER * mod; else max_vote += VOTE_WEIGHT_NORM * mod; } /* max_vote += (pc->cur_member - pc->cur_elder - pc->cur_leader) * VOTE_WEIGHT_NORM * mod; max_vote += pc->cur_elder * VOTE_WEIGHT_ELDER * mod; max_vote += pc->cur_leader * VOTE_WEIGHT_LEADER * mod; */ max_vote = UMAX(1, max_vote); return max_vote; } /* creates a fresh vote based on info passed */ VOTE_DATA* init_vote( int type, char* owner, char* from, char* subject, char* string, int max_vote, int life_time){ VOTE_DATA* pv = NULL; /* safety */ if (IS_NULLSTR(owner) || IS_NULLSTR(subject)){ bug("init_vote: null owner or subject on vote type %d", type); return pv; } if (max_vote < 1) max_vote = VOTE_DEFMAX; if (life_time < 1) life_time = VOTE_DUR_MED; /* get the vote pointer */ if ( (pv = new_vote()) == NULL){ bug("init_vote: could not get a new pointer", 0); return pv; } /* reset data */ pv->type = type; pv->owner = str_dup( owner ); pv->from = str_dup( from ); pv->subject = str_dup( subject ); pv->string = str_dup( string ); pv->yes = 0; pv->no = 0; pv->pass = 0; pv->veto = FALSE; pv->max_vote = max_vote; pv->time_stamp= mud_data.current_time; pv->life_time = pv->time_stamp + life_time; return pv; } /* sets up the vote based on the type and info passed */ VOTE_DATA* create_vote(CHAR_DATA* ch, char* owner, char* subject, char* string, int type, int v0, int v1, int v2, int v3, int v4){ VOTE_DATA* pv = NULL; CABAL_DATA* pc = ch->pCabal; //parent of cabal CABAL_DATA* po = ch->pCabal; //original cabal CABAL_DATA* pc2 = ch->pCabal; //second cabal as needed CABAL_DATA* po2 = ch->pCabal; //second cabal as needed char from[MIL]; //this is almost never changed, unless its from a cabal name. char v_subj[MIL]; int value[VOTE_VALS]; int max_vote = 0; int life_time = 0; int i = 0; if (ch == NULL) return pv; else sprintf(from,"%s", ch->name); /* reset values */ for (i = 0; i < VOTE_VALS; i++){ value[i] = 0; } /* set values up based on type */ switch ( type ){ case VOTE_CAB_APPLY: if ( (po = get_cabal_vnum( v0 )) == NULL){ bug("create_vote/CAB_APPLY: could not get cabal index.", 0); return pv; } pc = get_parent( po ); /* change subject to match now */ sprintf(v_subj, "Admission to %s", pc->name); max_vote = get_max_vote( pc, type ); life_time = vote_table[type].life_time; value[0] = pc->vnum; value[1] = po->vnum; break; case VOTE_CAB_PROM: if ( (po = get_cabal_vnum( v0 )) == NULL){ bug("create_vote/CAB_PROM: could not get cabal index.", 0); return pv; } pc = get_parent( po ); /* change subject to match now */ sprintf(v_subj, "Promotion of %s", owner); max_vote = get_max_vote( pc, type ); life_time = vote_table[type].life_time; sprintf(from, "%s", pc->who_name); value[0] = po->vnum; value[1] = pc->vnum; break; case VOTE_CAB_DEMO: if ( (po = get_cabal_vnum( v0 )) == NULL){ bug("create_vote/CAB_DEMO: could not get cabal index.", 0); return pv; } pc = get_parent( po ); /* change subject to match now */ sprintf(v_subj, "Demotion of %s", owner); max_vote = get_max_vote( pc, type ); life_time = vote_table[type].life_time; sprintf(from, "%s", pc->who_name); value[0] = pc->vnum; break; case VOTE_CAB_EXPEL: if ( (po = get_cabal_vnum( v0 )) == NULL){ bug("create_vote/CAB_EXPEL: could not get cabal index.", 0); return pv; } pc = get_parent( po ); /* change subject to match now */ sprintf(v_subj, "Expulsion of %s from %s", owner, po->who_name); max_vote = get_max_vote( pc, type ); life_time = vote_table[type].life_time; sprintf(from, "%s", pc->who_name); value[0] = po->vnum; value[1] = pc->vnum; break; case VOTE_CAB_ELDER: if ( (po = get_cabal_vnum( v0 )) == NULL){ bug("create_vote/CAB_ELDER: could not get cabal index.", 0); return pv; } pc = get_parent( po ); /* change subject to match now */ sprintf(v_subj, "Proposed Eldership of %s", owner); max_vote = get_max_vote( pc, type ); life_time = vote_table[type].life_time; sprintf(from, "%s", pc->who_name); value[0] = po->vnum; value[1] = pc->vnum; break; case VOTE_CAB_LEADER: if ( (po = get_cabal_vnum( v0 )) == NULL){ bug("create_vote/CAB_LEADER: could not get cabal index.", 0); return pv; } pc = get_parent( po ); /* change subject to match now */ sprintf(v_subj, "Proposed Leadership of %s", owner); max_vote = get_max_vote( pc, type ); sprintf(from, "%s", pc->who_name); value[0] = po->vnum; value[1] = pc->vnum; break; case VOTE_CAB_POLL: if ( (po = get_cabal_vnum( v0 )) == NULL){ bug("create_vote/CAB_POLL: could not get cabal index.", 0); return pv; } pc = get_parent( po ); sprintf(v_subj, "%s", subject); max_vote = get_max_vote( pc, type ); life_time = vote_table[type].life_time; value[0] = po->vnum; value[1] = pc->vnum; break; case VOTE_TOME: if ( (po = get_cabal_vnum( v0 )) == NULL){ bug("create_vote/TOME: could not get cabal index.", 0); return pv; } pc = get_parent( po ); /* create title for the author */ sprintf(from, "%s %s%s%s", get_crank(ch), ch->name, IS_NULLSTR(ch->pcdata->family)? "" : " ", IS_NULLSTR(ch->pcdata->family)? "" : ch->pcdata->family); sprintf(v_subj, "%s", subject); max_vote = get_max_vote( pc, type ); life_time = vote_table[type].life_time; value[0] = po->vnum; value[1] = pc->vnum; break; case VOTE_LAW: if ( (po = get_cabal_vnum( v0 )) == NULL){ bug("create_vote/LAW: could not get cabal index.", 0); return pv; } pc = get_parent( po ); sprintf(v_subj, "Proposed change of %s to %s", crime_table[v1].name, punish_table[v2].name); max_vote = get_max_vote( pc, type ); life_time = vote_table[type].life_time; sprintf(from, "%s", pc->who_name); value[0] = pc->vnum; value[1] = v1; value[2] = v2; break; case VOTE_CAB_TAX: if ( (po = get_cabal_vnum( v0 )) == NULL){ bug("create_vote/TAX: could not get cabal index.", 0); return pv; } pc = get_parent( po ); sprintf(v_subj, "Proposed change of tax from %d%% to %d%%", pc->cp_tax, v1 ); max_vote = get_max_vote( pc, type ); life_time = vote_table[type].life_time; sprintf(from, "%s", pc->who_name); value[0] = pc->vnum; value[1] = v1; break; case VOTE_CAB_SPONS: if ( (po = get_cabal_vnum( v0 )) == NULL){ bug("create_vote/SPONSOR: could not get cabal index.", 0); return pv; } pc = get_parent( po ); sprintf(v_subj, "Proposed %s of sponsorship for inductions.", IS_CABAL(pc, CABAL_SPONSOR) ? "removal" : "requirement"); max_vote = get_max_vote( pc, type ); life_time = vote_table[type].life_time; value[0] = pc->vnum; break; case VOTE_TITHE: if ( (po = get_cabal_vnum( v0 )) == NULL){ bug("create_vote/TITHE: could not get cabal index.", 0); return pv; } pc = get_parent( po ); if ( (po2 = get_cabal_vnum( v1 )) == NULL){ bug("create_vote/TITHE: could not get second cabal index.", 0); return pv; } pc2 = get_parent( po2 ); sprintf(v_subj, "Proposed tithe of %d %s%s to %s", v2, pc->currency, v2 == 1 ? "" : "s", pc2->who_name); max_vote = get_max_vote( pc, type ); life_time = vote_table[type].life_time; sprintf(from, "%s", pc->who_name); value[0] = pc->vnum; value[1] = v1; value[2] = v2; break; case VOTE_PACT: /* get creator pointer */ if ( (po = get_cabal_vnum( v0 )) == NULL){ bug("create_vote/PACT: could not get creator index.", 0); return pv; } else { pc = get_parent( po ); } /* get benefactor index */ if ( (po2 = get_cabal_vnum( v1 )) == NULL){ bug("create_vote/PACT: could not get benefactor index.", 0); return pv; } else { pc2 = get_parent( po2 ); } /* vendetta and embargo votes do not create a mirror vote, rather the pact is completed as soon as the vote in one cabal is success */ if (!IS_SET(v4, PACT_VENDETTA) && !IS_SET(v4, PACT_BREAK)){ /* we first create a mirror image of this vote for the benefactor cabal */ sprintf(v_subj, "Proposal of %s with [%s]", IS_SET(v4, PACT_IMPROVE) ? flag_string(pact_flags, v2) : flag_string(pact_flags, v4), pc->who_name ); max_vote = get_max_vote( pc2, type ); life_time = vote_table[type].life_time; sprintf(from, "%s", pc2->who_name); value[0] = pc2->vnum; //creator vnum value[1] = pc->vnum; //benefactor vnum /* Service Cabals give negative gain on all trade pacts to the other cabal */ if (IS_CABAL(pc, CABAL_SERVICE) && !IS_SET(v4, PACT_IMPROVE)){ value[2] = TRADE_CP_SERVE; //cp % gain for benefactor value[3] = TRADE_SUP_SERVE; //sup % gain for benefactor } else{ value[2] = v2; //cp % gain for benefactor value[3] = v3; //sup % gain for benefactor } value[4] = v4; //type of pact if (mud_data.mudport == TEST_PORT && IS_IMMORTAL(ch)) life_time = VOTE_MINUTE; if ( (pv = init_vote( type, owner, from, v_subj, string, max_vote, life_time)) == NULL){ bug("create_vote: VOTE_PACT could not initialize vote.(type %d)", type); return pv; } /* set the values up */ for (i = 0; i < VOTE_VALS; i++){ pv->value[i] = value[i]; } /* attach the vote */ add_vote( pv ); /* reset values */ for (i = 0; i < VOTE_VALS; i++){ value[i] = 0; } }//END if not vendetta /* do the original now */ sprintf(v_subj, "Proposal of %s with [%s]", IS_SET(v4, PACT_IMPROVE) ? flag_string(pact_flags, v2) : flag_string(pact_flags, v4), pc2->who_name ); max_vote = get_max_vote( pc, type ); life_time = vote_table[type].life_time; sprintf(from, "%s", pc->who_name); value[0] = pc->vnum; //creator vnum value[1] = pc2->vnum; //benefactor vnum /* service cabals do not give the other cabal any gain, but make the area lawful with exception of vendetta votes */ if (IS_CABAL(pc2, CABAL_SERVICE) && !IS_SET(v4, PACT_VENDETTA) && !IS_SET(v4, PACT_IMPROVE) ){ value[2] = TRADE_CP_SERVE; //cp % gain for benefactor value[3] = TRADE_SUP_SERVE; //sup % gain for benefactor } else{ value[2] = v2; //cp % gain for creator value[3] = v3; //sup % gain for creator } value[4] = v4; //type of pact break; case VOTE_BUILD: if ( (po = get_cabal_vnum( v0 )) == NULL){ bug("create_vote/BUILD: could not get cabal index.", 0); return pv; } pc = get_parent( po ); sprintf(v_subj, subject ); max_vote = get_max_vote( pc, type ); life_time = get_trust(ch) == IMPLEMENTOR ? VOTE_MINUTE : vote_table[type].life_time; value[0] = pc->vnum; value[1] = v1; value[2] = v2; value[3] = v3; value[4] = v4; break; default: case VOTE_GENERAL: sprintf(v_subj, "%s", subject); max_vote = 3 * mud_data.pfiles / 4; life_time = vote_table[type].life_time; break; } /* test port has very short lifetiems */ if (mud_data.mudport == TEST_PORT) life_time = VOTE_MINUTE; if ( (pv = init_vote( type, owner, from, v_subj, string, max_vote, life_time)) == NULL){ bug("create_vote: could not initialize vote.(type %d)", type); return pv; } /* set the values up */ for (i = 0; i < VOTE_VALS; i++){ pv->value[i] = value[i]; } /* test for duplicate */ if (is_duplicated( pv )){ send_to_char("Duplicate vote.\n\r", ch); return NULL; } /* attach the vote */ return pv; } /* shows a list of all votes */ void list_votes( CHAR_DATA* ch){ VOTE_DATA* pv = vote_list; BUFFER *buffer; char buf[MSL]; int counter = 0; buffer=new_buf(); buf[0] = 0; for (;pv != NULL; pv = pv->next){ if (!is_vote_to( ch, pv) && get_trust(ch) < IMPLEMENTOR && str_cmp(ch->name, pv->owner)){ continue; } else counter++; if (IS_IMMORTAL(ch)){ sprintf(buf, "%3d.[%-10s] %-40s: Y:%-3d N:%-3d P:%-3d Tot: %d [%ld D] [%s]\n\r", counter, pv->from, pv->subject, pv->yes, pv->no, pv->pass, pv->max_vote, ( pv->life_time - mud_data.current_time) / VOTE_DAY, pv->owner); } else{ sprintf(buf, "%3d.[%-10s] %-40s:[%-2ld D]\n\r", counter, pv->from, pv->subject, ( pv->life_time - mud_data.current_time) / VOTE_DAY ); } add_buf(buffer,buf); } if (IS_NULLSTR(buf)){ send_to_char("No votes found.\n\r", ch); } else{ page_to_char(buf_string(buffer),ch); } free_buf(buffer); } /* finds cabal vote data based on type NULL if not found*/ CVOTE_DATA* get_cvote( CABAL_INDEX_DATA* pCabal, int type ){ CVOTE_DATA* cVote; CABAL_INDEX_DATA* pCab = pCabal; CABAL_INDEX_DATA* pPar; if (pCab == NULL) return NULL; /* we run through the cabal and its partents looking for the vote */ while (pCab != NULL){ for( cVote = pCab->votes; cVote; cVote = cVote->next ){ if (cVote->vote == type) return cVote; } if ( pCab->parent_vnum && (pPar = get_cabal_index(pCab->parent_vnum)) != NULL) pCab = pPar; else pCab = NULL; } return NULL; } /* checks if the player can create a given vote */ bool can_create_cvote( CHAR_DATA* ch, CVOTE_DATA* cVote){ if (ch == NULL || cVote == NULL) return FALSE; if (ch->pcdata->rank < cVote->min || ch->pcdata->rank > cVote->max) return FALSE; return TRUE; } /* shows votes avaliable to character */ void show_cvotes( CHAR_DATA* ch, CABAL_INDEX_DATA* pCabal ){ CVOTE_DATA* cVote; CABAL_INDEX_DATA* pCab = pCabal, *pPar; if (pCab == NULL) return; /* we run through the cabal and its partents looking for the vote */ while (pCab != NULL){ for( cVote = pCab->votes; cVote; cVote = cVote->next ){ if (can_create_cvote( ch, cVote)){ sendf( ch, "%-20s %-4d %s%-5s [%d days]\n\r", vote_table[cVote->vote].name, cVote->cost, pCabal->currency, (cVote->cost) == 1 ? "" : "s", vote_table[cVote->vote].life_time / VOTE_DAY); } } if ( pCab->parent_vnum && (pPar = get_cabal_index(pCab->parent_vnum)) != NULL) pCab = pPar; else pCab = NULL; } } /* checks if the player can create a given type of vote, returns type or unkown */ int get_vote_type( CHAR_DATA* ch, const char* name ){ int type = vote_lookup( name ); CVOTE_DATA* cVote = get_cvote( ch->pCabal->pIndexData, type ); if (cVote && can_create_cvote( ch, cVote )) return cVote->vote; else return VOTE_UNKNOWN; } /* attaches a few vote data to be filled in and created */ void attach_vote( CHAR_DATA* ch, int type ){ VOTE_DATA* pv; int i = 0; if (ch->pcdata->pvote != NULL) return; pv = new_vote(); pv->next = NULL; pv->owner = NULL; //owner stays null untill valid target is assigned pv->subject = str_dup( "" ); pv->string = str_dup( "" ); pv->from = str_dup( ch->name ); pv->type = type; for (i = 0; i < VOTE_VALS; i++){ pv->value[i] = 0; } ch->pcdata->pvote = pv; } /* checks if this type of vote is allowed to be posted based on other votes that exist */ bool is_duplicated( VOTE_DATA* pVote ){ VOTE_DATA* pv; if (IS_SET(vote_table[pVote->type].flag, VOTE_DUP)) return FALSE; /* run through all the votes and check for duplicates */ for (pv = vote_list; pv; pv = pv->next ){ if (pv->type != pVote->type || str_cmp(pv->owner, pVote->owner)) continue; switch ( pv->type ){ case VOTE_CAB_PROM: case VOTE_CAB_DEMO: case VOTE_CAB_EXPEL: case VOTE_CAB_ELDER: case VOTE_CAB_LEADER: case VOTE_CAB_APPLY: if (pv->value[0] == pVote->value[0]) return TRUE; break; case VOTE_LAW: if (pv->value[0] == pVote->value[0] && pv->value[1] == pVote->value[1]) return TRUE; break; case VOTE_CAB_TAX: case VOTE_CAB_SPONS: if (pv->value[0] == pVote->value[0]) return TRUE; case VOTE_TITHE: if (pv->value[0] == pVote->value[0] && pv->value[1] == pVote->value[1]) return TRUE; break; case VOTE_TOME: if (pv->value[0] == pVote->value[0] && !strcasecmp(pv->subject, pVote->subject)) return TRUE; break; case VOTE_PACT: if ( pv->value[0] == pVote->value[0] && pv->value[1] == pVote->value[1] && pv->value[4] == pVote->value[4]) return TRUE; break; case VOTE_BUILD: if (pv->value[0] == pVote->value[0] && pv->value[1] == pVote->value[1] && pv->value[2] == pVote->value[2] && pv->value[3] == pVote->value[3]) return TRUE; break; } } return FALSE; } /* attempts to return a vote type, with given set of values */ VOTE_DATA* get_vote( int type, int v0, int v1, int v2, int v3, int v4 ){ VOTE_DATA* pv; for (pv = vote_list; pv; pv = pv->next){ if (pv->type == type && pv->value[0] == v0 && pv->value[1] == v1 && pv->value[2] == v2 && pv->value[3] == v3 && pv->value[4] == v4) return pv; } return NULL; } /* handles rules and setting of the vote target based on vote type */ void set_vote_target( CHAR_DATA* ch, VOTE_DATA* pv, char* target ){ CMEMBER_DATA* cMem; CABAL_DATA* pCab = ch->pCabal; CABAL_DATA* pPar = get_parent( pCab ); AREA_DATA* pArea = NULL; char* argument = target; if (pPar == NULL){ send_to_char("You must be a member of a cabal to create votes.\n\r", ch); return; } switch ( pv->type ){ /* votes with VOTE_NOOWNER get their owner set to character's name automaticly, this is just for clarity */ default: case VOTE_GENERAL: if (!IS_NULLSTR(pv->owner )) free_string( pv->owner ); pv->owner = str_dup( ch->name ); send_to_char("Ok.\n\r", ch); break; case VOTE_CAB_APPLY: if (!IS_NULLSTR(pv->owner )) free_string( pv->owner ); pv->owner = str_dup( pPar->name ); send_to_char("Ok.\n\r", ch); break; case VOTE_CAB_POLL: if (!IS_NULLSTR(pv->owner )) free_string( pv->owner ); pv->owner = str_dup( ch->name ); send_to_char("Ok.\n\r", ch); if (!ch->pCabal){ send_to_char("You are not in a cabal!\n\r",ch); return; } pv->value[0] = ch->pCabal->vnum; break; case VOTE_CAB_SPONS: pv->value[0] = pPar->vnum; if (!IS_NULLSTR(pv->owner )) free_string( pv->owner ); pv->owner = str_dup( pPar->name ); send_to_char("Ok.\n\r", ch); break; case VOTE_CAB_DEMO: case VOTE_CAB_EXPEL: case VOTE_CAB_PROM: case VOTE_CAB_ELDER: case VOTE_CAB_LEADER: if ( (pv->type == VOTE_CAB_PROM || pv->type == VOTE_CAB_ELDER || pv->type == VOTE_CAB_LEADER) && !IS_IMMORTAL(ch)){ send_to_char("These votes can only be initiated by an Immortal.\n\r", ch); return; } if (IS_NULLSTR( argument )){ send_to_char("Whom is to be the target of this vote?\n\r", ch); return; } if ( (cMem = get_cmember( target, get_parent(ch->pCabal))) == NULL){ send_to_char("They are not a member of your organization.\n\r", ch); break; } /* do checks on the member data */ else{ CABAL_DATA* pCab = cMem->pCabal; CABAL_DATA* pPar = get_parent( pCab ); int rank = cMem->rank; /* first we check minimum hours for this rank */ if (mud_data.mudport != TEST_PORT && pv->type != VOTE_CAB_DEMO && pv->type != VOTE_CAB_EXPEL && !check_promo_hours( cMem, rank )){ sendf(ch, "%s has not been present enough to be promoted to a new rank.\n\r", cMem->name); return; } else if (pv->type != VOTE_CAB_DEMO && pv->type != VOTE_CAB_EXPEL && !check_promo_req(ch, cMem, rank + 1)) return; /* check if there was a recent vote for this */ else if (mud_data.current_time - cMem->time_stamp < VOTE_DAY){ send_to_char("There has already been a recent vote regarding their rank.\n\r", ch); sendf(ch, "A new vote may be created in %ld hours.\n\r", (VOTE_DAY - (mud_data.current_time - cMem->time_stamp)) / 3600); return; } /* check if we can attempt to vote for new leader */ else if (pv->type == VOTE_CAB_LEADER){ if (rank != RANK_ELDER){ sendf( ch, "%s must hold the rank of %s in order to be promoted to a leader.\n\r", cMem->name, pCab->pIndexData->mranks[RANK_ELDER]); return; } if (pPar->cur_leader + 1 > pPar->max_leader){ send_to_char("The Cabal cannot support another leader.\n\r", ch); return; } } else if (pv->type == VOTE_CAB_ELDER){ if (rank < RANK_ELDER - 1){ sendf( ch, "%s must be at the rank of %s in order to be promoted to %s.\n\r", cMem->name, pCab->pIndexData->mranks[RANK_ELDER - 1], pCab->pIndexData->mranks[RANK_ELDER]); return; } if (pPar->cur_elder + 1 > pPar->max_elder){ send_to_char("The Cabal cannot support another elder.\n\r", ch); return; } } else if (pv->type == VOTE_CAB_PROM){ if ((rank + 1) >= RANK_ELDER){ sendf( ch, "You must use Eldership and Leadership votes to promote %s further.\n\r", cMem->name); return; } } else if (pv->type == VOTE_CAB_DEMO){ if (rank <= RANK_NEWBIE){ sendf( ch, "You cannot demote %s any further.\n\r", cMem->name); return; } else if (rank < RANK_ELDER && cMem->rank < RANK_ELDER){ send_to_char("You may only create demotion votes for Elders and Leaders.\n\r", ch); return; } } else if (pv->type == VOTE_CAB_EXPEL){ if (rank >= RANK_ELDER){ sendf( ch, "You cannot vote to expel an Elder or Leader, they must be demoted first.\n\r"); return; } } if (!IS_NULLSTR(pv->owner )) free_string( pv->owner ); pv->owner = str_dup( cMem->name ); pv->value[0] = cMem->pCabal->vnum; pv->value[1] = get_parent(cMem->pCabal)->vnum; } send_to_char("Ok.\n\r", ch); break; case VOTE_LAW: if (!IS_CABAL(pPar, CABAL_ROYAL)){ send_to_char("Only royal cabals may use this vote.\n\r", ch); return; } /* check if city is lawful */ if ( (pArea = pPar->city) == NULL){ bug("set_vote_target: VOTE_LAW could not find an area for cabal vnum %d.", pv->value[0]); break; } else if (!IS_SET(pArea->area_flags, AREA_LAWFUL)){ send_to_char("You must first forge a Trade Pact with a Justice cabal.\n\r", ch ); return; } else if (IS_NULLSTR(argument)){ send_to_char("vote target <crime> <new maximum penalty>\n\r(Use \"vote target list\" to see list of crimes)\n\r", ch); return; } else{ int crime = 0; int pen = CRIME_ALLOW; char arg[MIL]; argument = one_argument( argument, arg ); /* argument is as follows <crime> <new max penalty> */ if ( (crime = crime_lookup( arg )) < 0){ int crime = 0; send_to_char("Criminal acts fall into following categories:\n\r", ch ); for (crime = 0; crime_table[crime].name != NULL; crime++){ sendf( ch, "%s\n\r", crime_table[crime].name); } return; } else if (crime_table[crime].settable == FALSE){ send_to_char("That crime category has been set by the gods and cannot be changed.\n\r", ch); return; } else if ( IS_NULLSTR(argument) || (pen = flag_lookup2( argument, punish_table)) == NO_FLAG){ sendf( ch, "Following penalties are valid:\n\r" ); show_flag_cmds( ch, punish_table ); return; } else if (crime == CRIME_MURDER && pen < CRIME_LIGHT){ send_to_char("You may not allow murder in a lawful city.\n\r", ch); return; } /* we now have the crime and the new penalty, setup the owner, and values */ if (!IS_NULLSTR(pv->owner )) free_string( pv->owner ); pv->owner = str_dup( pPar->name ); pv->value[0] = pPar->vnum; pv->value[1] = crime; pv->value[2] = pen; send_to_char("Ok.\n\r", ch); } break; case VOTE_CAB_TAX: if (IS_NULLSTR(argument)){ send_to_char("vote target <new tax rate>\n\r", ch); return; } else{ int tax = atoi(argument); if (tax < 0 || tax > 50){ send_to_char("The new tax rate must be between 0 and 50%%.\n\r", ch); return; } /* we now have the tax and the new penalty, setup the owner, and values */ if (!IS_NULLSTR(pv->owner )) free_string( pv->owner ); pv->owner = str_dup( pPar->name ); pv->value[0] = pPar->vnum; pv->value[1] = tax; send_to_char("Ok.\n\r", ch); } break; case VOTE_TITHE: if (IS_NULLSTR(argument)){ send_to_char("vote target <cabal> <amount>\n\r", ch); return; } else{ char cabal[MIL]; CABAL_DATA* pTar; int tithe = 0; argument = one_argument( argument, cabal ); tithe = atoi(argument); if ( (pTar = get_cabal( cabal )) == NULL){ send_to_char("No such cabal exists.\n\r", ch ); return; } else if (IS_NULLSTR( argument )){ send_to_char("vote target <cabal> <amount>\n\r", ch ); return; } else if (tithe < 1 || tithe > GET_CAB_CP( pPar )){ send_to_char("Your cabal cannot afford it.\n\r", ch); return; } /* we now have the tax and the new penalty, setup the owner, and values */ if (!IS_NULLSTR(pv->owner )) free_string( pv->owner ); pv->owner = str_dup( pTar->name ); pv->value[0] = pPar->vnum; pv->value[1] = pTar->vnum; pv->value[2] = tithe; CP_CAB_GAIN( pPar, -tithe ); CHANGE_CABAL( pPar ); save_cabals( TRUE, NULL ); send_to_char("Ok.\n\r", ch); } break; case VOTE_PACT: if (IS_NULLSTR(argument)){ send_to_char("vote target <pact> <cabal>\n\r(Use \"vote target list\" to see list of pacts)\n\r", ch); return; } else{ int pact = 0; CABAL_DATA* pBen = NULL; PACT_DATA* pPact = NULL; char arg[MIL]; argument = one_argument( argument, arg ); /* argument is as follows <pact> <cabal> */ if ( (pact = flag_lookup2( arg, pact_flags)) == NO_FLAG){ sendf( ch, "Following pacts may be declared:\n\r" ); show_flag_cmds( ch, pact_flags ); return; } else if (IS_NULLSTR( argument ) || (pBen = get_cabal( argument )) == NULL){ send_to_char("You may not form a pact with that cabal.\n\r", ch ); return; } else pBen = get_parent( pBen ); if (is_same_cabal(pPar, pBen)){ send_to_char("A pact with yourself? How useless.\n\r", ch ); return; } /* we have enoough data to check if such pact exists */ /* vendetta pact blocks all other pacts except for PEACE pact */ if ( get_pact(pPar, pBen, PACT_VENDETTA, FALSE) != NULL && pact != PACT_PEACE){ send_to_char("You may only create a Peace Pact while a Vendetta exists.\n\r", ch); return; } else if (pact == PACT_PEACE && pPar->enemy && pPar->enemy == pBen){ send_to_char("You cannot make peace with your mortal enemies!\n\r", ch); return; } else if ( pact == PACT_PEACE && ( (pPact = get_pact(pPar, pBen, PACT_VENDETTA, FALSE)) == NULL || pPact->complete != PACT_COMPLETE) ){ send_to_char("You may only create a Peace Pact while a Vendetta exists.\n\r", ch ); return; } else if ( pact == PACT_BREAK && ( (pPact = get_pact(pPar, pBen, PACT_TRADE, TRUE)) == NULL || pPact->complete != PACT_COMPLETE) ){ send_to_char("There is no trade between you to stop!\n\r", ch ); return; } else if ( pact == PACT_IMPROVE && ( (pPact = get_pact(pPar, pBen, PACT_TRADE, TRUE)) == NULL || pPact->complete != PACT_COMPLETE) ){ send_to_char("There is no trade between you to improve!\n\r", ch ); return; } else if (pact == PACT_IMPROVE && pPact->type == PACT_NAPACT && IS_CABAL(pPar, CABAL_ALLIANCE)){ send_to_char("You may only be allied with one cabal at a time.\n\r", ch); return; } else if (pact == PACT_IMPROVE && (pPact->Adv > pPact->type || pPact->type == PACT_ALLIANCE)){ send_to_char("Your trade has already been approved for improvement.\n\r", ch); return; } /* cannot delcare vendetta if there is advanced trade */ else if ( pact == PACT_VENDETTA && get_pact(pPar, pBen, PACT_NAPACT, FALSE) != NULL){ send_to_char("The Non-Aggression pact must first be cancelled with the Embargo Pact.\n\r", ch); return; } else if ( pact == PACT_VENDETTA && get_pact(pPar, pBen, PACT_ALLIANCE, FALSE) != NULL){ send_to_char("The Alliance must first be cancelled with the Embargo Pact.\n\r", ch); return; } else if ( get_pact(pPar, pBen, pact, (pact == PACT_TRADE || pact == PACT_NAPACT || pact == PACT_ALLIANCE)) != NULL){ send_to_char("That type of pact already exists between you.\n\r", ch); return; } /* we now have the pact and the cabal, setup the owner, and values */ if (!IS_NULLSTR(pv->owner )) free_string( pv->owner ); pv->owner = str_dup( pPar->name ); pv->value[0] = pPar->vnum; pv->value[1] = pBen->vnum; pv->value[4] = pact; switch (pact){ default: case PACT_TRADE: pv->value[2] = TRADE_CP_START; pv->value[3] = TRADE_SUP_START; break; case PACT_NAPACT: pv->value[2] = TRADE_CP_NA; pv->value[3] = TRADE_SUP_NA; break; case PACT_ALLIANCE: pv->value[2] = TRADE_CP_MAX; pv->value[3] = TRADE_SUP_MAX; break; case PACT_VENDETTA: pv->value[2] = TRADE_CP_WAR; pv->value[3] = TRADE_SUP_WAR; break; case PACT_IMPROVE: if (pPact == NULL ){ send_to_char("Error, no pact found.\n\r", ch ); return; } else if (pPact->type == PACT_TRADE ){ pv->value[2] = PACT_NAPACT; } else if (pPact->type == PACT_NAPACT ){ pv->value[2] = PACT_ALLIANCE; } else{ send_to_char("You cannot improve the trade any further.\n\r", ch); return; } break; } send_to_char("Ok.\n\r", ch); } break; } } /* Command used to create/setup votes, view list of votes, and vote * * vote list shows list of votes (M/IMM) * * vote vote enters the vote booth (M/IMM) * * vote <vote type> creates a given vote type * */ void do_vote( CHAR_DATA* ch, char* argument ){ char arg[MIL]; argument = one_argument(argument, arg); if (IS_NPC(ch)) return; if (IS_NULLSTR(arg)){ if (has_votes (ch)){ ch->desc->connected = CON_VOTE; interpret_vote( ch, ""); return; } else{ send_to_char("You have no pending votes at this time.\n\r", ch); return; } } /* IMMORTAL COMMANDS HERE */ else if (IS_IMMORTAL( ch ) && get_trust( ch ) >= CREATOR ){ if (!str_prefix(arg, "delete")){ int index = atoi( argument ); int counter = 0; VOTE_DATA* pv = vote_list; if (index < 1){ send_to_char("Specify numeric index\n\r", ch); return; } /* get the right vote */ for (;pv != NULL; pv = pv->next){ if (!is_vote_to( ch, pv)){ continue; } else counter++; if (counter == index ) break; } if (pv == NULL){ send_to_char("No vote with that index.\n\r", ch); return; } /* we now nuke the vote */ sendf( ch, "Vote \"%s\" deleted.\n\r", pv->subject); rem_vote( pv ); free_vote( pv ); save_mud(); return; } } if (!str_prefix(arg, "list")){ list_votes(ch); return; } if (ch->pCabal == NULL){ send_to_char("You're not in a cabal.\n\r", ch); return; } /* CREATE */ else if (!str_prefix(arg, "create")){ int type = 0; if (ch->pcdata->pvote != NULL){ send_to_char("You are already working on another vote.\n\r", ch); return; } /* get the type of vote to create */ if (IS_NULLSTR( argument ) || (type = get_vote_type( ch, argument)) == VOTE_UNKNOWN){ send_to_char("Following votes are avaliable to you:\n\r", ch ); show_cvotes( ch, ch->pCabal->pIndexData ); return; } attach_vote( ch, type ); /* auto owner set to name of ch */ if (ch->pcdata->pvote && IS_SET(vote_table[type].flag, VOTE_NOOWNER)) set_vote_target( ch, ch->pcdata->pvote, ch->name ); else send_to_char("Ok.\n\r", ch); } /* CLEAR */ else if (!str_prefix(arg, "clear")){ if (ch->pcdata->pvote == NULL){ send_to_char("You are not working on a vote.\n\r", ch); return; } free_vote( ch->pcdata->pvote ); ch->pcdata->pvote = NULL; send_to_char("Ok.\n\r", ch); } /* SHOW */ else if (!str_prefix(arg, "show")){ VOTE_DATA* pv = ch->pcdata->pvote; if (pv == NULL){ send_to_char("You are not working on a vote.\n\r", ch); return; } sendf( ch, "%s: %-15s [Tar: %s]\n\r\n\r", pv->from, pv->subject, pv->owner ); send_to_char( pv->string, ch ); send_to_char( "\n\r", ch ); } /* FORMAT */ else if (!str_prefix(arg, "format")){ VOTE_DATA* pv = ch->pcdata->pvote; if (pv == NULL){ send_to_char("You are not working on a vote.\n\r", ch); return; } ch->pcdata->pvote->string = format_string(ch->pcdata->pvote->string); send_to_char( "Text formatted\n\r", ch ); } /* SUBJ */ else if (!str_prefix(arg, "subject")){ VOTE_DATA* pv = ch->pcdata->pvote; if (pv == NULL){ send_to_char("You are not working on a vote.\n\r", ch); return; } if (!IS_SET(vote_table[pv->type].flag, VOTE_SUBJ)){ send_to_char("The subject will be created when you post the vote.\n\r", ch); return; } if (IS_NULLSTR( argument )){ send_to_char("Enter what subject?\n\r", ch); return; } if (pv->subject) free_string( pv->subject ); pv->subject = str_dup( argument ); send_to_char("Ok.\n\r", ch); } /* TARGET */ else if (!str_prefix(arg, "target")){ VOTE_DATA* pv = ch->pcdata->pvote; if (pv == NULL){ send_to_char("You are not working on a vote.\n\r", ch); return; } if (IS_SET(vote_table[pv->type].flag, VOTE_NOOWNER)){ send_to_char("Target of this vote is generated when you post the vote.\n\r", ch); return; } set_vote_target( ch, pv, argument ); } /* EDIT TEXT */ else if (!str_prefix(arg, "edit")){ VOTE_DATA* pv = ch->pcdata->pvote; if (pv == NULL){ send_to_char("You are not working on a vote.\n\r", ch); return; } string_append( ch, &pv->string ); return; } /* SEND/POST */ else if (!str_prefix(arg, "send") || !str_cmp(arg, "post")){ VOTE_DATA* pv = ch->pcdata->pvote; CABAL_DATA* pc = get_parent( ch->pCabal ); CVOTE_DATA* cVote = NULL; bool fUrge = !IS_NULLSTR(argument) && !str_prefix( argument, "urgent" ); int cost = 0; if (pv == NULL){ send_to_char("You are not working on a vote.\n\r", ch); return; } /* check over various things */ else if (pv->type == VOTE_UNKNOWN){ send_to_char("Unknown type. Aborting..\n\r", ch); return; } else if (IS_NULLSTR(pv->from )){ send_to_char("Unknown author. Aborting..\n\r", ch); return; } else if (IS_NULLSTR(pv->owner )){ send_to_char("You must first specify the target of this vote (person, cabal etc).\n\r", ch); return; } else if (IS_SET(vote_table[pv->type].flag, VOTE_SUBJ) && IS_NULLSTR(pv->subject )){ send_to_char("You need to provide a subject.\n\r",ch); return; } else if ( (cVote = get_cvote(ch->pCabal->pIndexData, pv->type )) == NULL){ send_to_char("You are not allowed to create this vote.\n\r", ch); return; } else if (is_duplicated( pv )){ send_to_char("A vote on this matter has already been created.\n\r", ch); return; } /* check cost */ else if ( !IS_IMMORTAL(ch) && (cost = fUrge ? 2 * cVote->cost : cVote->cost) > GET_CP( ch)){ sendf( ch, "You will need at least %d %s%s to send this vote%s.\n\r", cost, ch->pCabal->currency, (cost) == 1 ? "" : "s", fUrge ? " urgently" : ""); return; } /* cabal coffers are not affected by urgency */ else if (!IS_IMMORTAL(ch) && !IS_SET(vote_table[pv->type].flag, VOTE_NOCAB_COST) && (pc == NULL || cVote->cost > GET_CAB_CP( pc )) ){ sendf( ch, "[%s] will require at least %d %s%s in its coffers to send this vote.\n\r", pc->who_name, cVote->cost, pc->currency, (cVote->cost) == 1 ? "" : "s" ); return; } /* seems everything is ok now, try to create/post the vote */ else{ VOTE_DATA* pVote = create_vote( ch, pv->owner, pv->subject, pv->string, pv->type, pv->value[0], pv->value[1], pv->value[2], pv->value[3], pv->value[4]); if (pVote == NULL){ bug("do_vote: create: error creating vote type %d.", pv->type); send_to_char("Error!\n\r", ch); return; } /* check urgent flag */ if (fUrge) pVote->life_time -= vote_table[pVote->type].life_time / 3; add_vote( pVote ); /* free the vote we were working on */ free_vote( pv ); ch->pcdata->pvote = NULL; CP_GAIN( ch, fUrge ? -2 * cost : -cost, TRUE ); if (get_trust(ch) != IMPLEMENTOR) CPS_CAB_GAIN( pc, -(cost * CPTS)); send_to_char("Ok.\n\r", ch); save_mud(); return; } } else{ send_to_char("read \"help cabal votes\" for commands and specifics.\n\r", ch); } } /* The following functions handle vote creation for based on an application */ /* the return values control if the app/note is posted, FALSE = yes */ bool create_app_vote( CHAR_DATA* ch, char* to, char* subject, char* text ){ CABAL_DATA* pc = NULL; VOTE_DATA* pv; char cabal[MIL]; one_argument(to, cabal); /* Viri: changed this to not require the subject line, check if this is a cabal app if (is_auto_name("cabal", subject) && is_auto_name("app", subject)){ if ( (pc = get_cabal( cabal )) == NULL){ sendf(ch, "There seems to be no organization named %s.\n\r", cabal); return VOTE_ERROR; } */ if ( (pc = get_cabal( cabal )) != NULL){ /* check if we already belong to a cabal */ if (ch->pCabal){ send_to_char("You've already been inducted to a cabal!\n\r", ch ); return VOTE_ERROR; } /* check if this is a child */ if (pc->parent){ sendf(ch, "You must direct your application to %s.\n\r", pc->parent->name); return VOTE_ERROR; } if (ch->pcdata->last_cabal && ch->pcdata->last_cabal != pc){ send_to_char("You are allowed only to try for a single cabal in your life.\n\r", ch); return VOTE_ERROR; } if (ch->pcdata->last_app && ch->pcdata->last_app + VOTE_TIME_TO_REAPPLY > mud_data.current_time){ sendf(ch, "You will be allowed another chance to apply in %ld days.\n\r", (ch->pcdata->last_app + VOTE_TIME_TO_REAPPLY - mud_data.current_time) / VOTE_DAY); return VOTE_ERROR; } else if (pc->clan && GET_CLAN(ch) != pc->clan){ sendf( ch, "Only members of %s clan may apply.\n\r", GetClanName(pc->clan)); return VOTE_ERROR; } else if (!ClanApplicationCheck(ch, pc)) return VOTE_ERROR; /* we have the cabal he was applying to now, check if we can take on a new member */ if ( !check_cabal_req( ch, pc ) ) return VOTE_ERROR; /* create the app */ if ( (pv = create_vote(ch, ch->name, cabal, text, VOTE_CAB_APPLY, pc->vnum, 0, 0, 0, 0)) == NULL){ send_to_char("Error creating vote.\n\r", ch); return VOTE_ERROR; } /* check for duplicated votes */ if ( is_duplicated( pv )){ send_to_char("You already have a vote pending.\n\r", ch ); free_vote( pv ); return VOTE_ERROR; } /* set character cabal choice and waiting time for re-apply */ ch->pcdata->last_app = mud_data.current_time; ch->pcdata->last_cabal = pc; save_char_obj( ch ); add_vote( pv ); send_to_char("Your application has been accepted.\n\r", ch); return VOTE_ACCEPTED; } else return VOTE_NONE; } /* checks if the particular vote is direcetd to a character */ bool is_vote_to(CHAR_DATA* ch, VOTE_DATA* pv){ CABAL_DATA* pCab = NULL; if (ch == NULL || IS_NPC(ch) || pv== NULL) return FALSE; switch ( pv->type ){ case VOTE_GENERAL: return TRUE; break; case VOTE_CAB_APPLY: /* citizens can vote on this */ pCab = get_cabal_vnum(pv->value[0]); if (pCab && !IS_IMMORTAL(ch) && !str_cmp(hometown_table[ch->hometown].name, pCab->name)) return TRUE; case VOTE_BUILD: case VOTE_CAB_POLL: case VOTE_CAB_TAX: case VOTE_TITHE: case VOTE_TOME: if (str_cmp(ch->name, pv->owner) && is_same_cabal( ch->pCabal, get_cabal_vnum(pv->value[0]))) return TRUE; else return FALSE; case VOTE_PACT: case VOTE_CAB_SPONS: pCab = get_cabal_vnum(pv->value[0]); if (is_same_cabal( ch->pCabal, get_cabal_vnum(pv->value[0])) || (pCab && !IS_IMMORTAL(ch) && !str_cmp(hometown_table[ch->hometown].name, pCab->name))){ return TRUE; } else return FALSE; break; case VOTE_CAB_PROM: case VOTE_CAB_DEMO: case VOTE_CAB_ELDER: case VOTE_CAB_LEADER: case VOTE_CAB_EXPEL: if (str_cmp(ch->name, pv->owner) && is_same_cabal( ch->pCabal, get_cabal_vnum(pv->value[0]))) return TRUE; else return FALSE; break; case VOTE_LAW: pCab = get_cabal_vnum(pv->value[0]); if ( (!IS_IMMORTAL(ch) && !str_cmp(hometown_table[ch->hometown].name, pCab->name)) || is_same_cabal( ch->pCabal, pCab)) return TRUE; else return FALSE; break; default: return FALSE; } return FALSE; } /* checks if the particular vote should be shown to a character or not */ /* used when voting to select next vote to vote on */ bool hide_vote( CHAR_DATA* ch, VOTE_DATA* pv ){ if (pv->time_stamp <= ch->pcdata->last_vote) return TRUE; if (!str_cmp(ch->name, pv->owner)) return TRUE; if (!is_vote_to(ch, pv)) return TRUE; return FALSE; } /* checks if a person should vote, and throws them into the vote interp */ int has_votes( CHAR_DATA* ch ){ VOTE_DATA* pv = vote_list; int count = 0; if (ch->level < 20) return count; for (;pv != NULL; pv = pv->next){ if (!hide_vote(ch, pv)) count ++; } if (count){ sendf(ch, "You have %d votes awaiting your decision. Entering voting booth...\n\r", count); } return count; } VOTE_DATA* next_vote( CHAR_DATA* ch ){ VOTE_DATA* pv = vote_list; while (pv && hide_vote(ch, pv)){ pv = pv->next; } return pv; } /* returns the weight of a vote based on the character and the vote */ int get_voteweight( CHAR_DATA* ch, VOTE_DATA* pv ){ int val = 1; switch (pv->type ){ default: case VOTE_GENERAL: val = 1; break; case VOTE_CAB_APPLY: case VOTE_CAB_PROM: case VOTE_CAB_DEMO: case VOTE_CAB_EXPEL: case VOTE_CAB_ELDER: case VOTE_CAB_LEADER: case VOTE_CAB_POLL: case VOTE_CAB_TAX: case VOTE_CAB_SPONS: case VOTE_BUILD: case VOTE_TITHE: case VOTE_TOME: case VOTE_PACT: case VOTE_LAW: if (IS_ELDER(ch)) val = VOTE_WEIGHT_ELDER; else if (IS_LEADER(ch)){ if (IS_IMMORTAL(ch)) val = 2 * VOTE_WEIGHT_LEADER; else val = VOTE_WEIGHT_LEADER; } else val = VOTE_WEIGHT_NORM; if (ch->pCabal && IS_CABAL(ch->pCabal, CABAL_ROYAL)) val *= 10; break; } return val; } /* checks if the character is a leader of a given cabal vote */ bool can_veto( CHAR_DATA* ch, VOTE_DATA* pv ){ CABAL_DATA *pSec; switch (pv->type ){ default: case VOTE_GENERAL: return FALSE; break; case VOTE_CAB_APPLY: /* royal cabal imms can always veto on apps */ if (IS_IMMORTAL(ch) && ch->pCabal && IS_CABAL(ch->pCabal, CABAL_ROYAL) && !str_cmp(ch->name, (get_parent(ch->pCabal))->immortal)) return TRUE; case VOTE_CAB_PROM: if (ch->pcdata->member && !IS_NULLSTR(ch->pcdata->member->sponsored) && !str_cmp(ch->pcdata->member->sponsored, pv->owner)) return TRUE; case VOTE_CAB_ELDER: case VOTE_CAB_LEADER: case VOTE_CAB_TAX: case VOTE_CAB_SPONS: case VOTE_BUILD: case VOTE_TITHE: case VOTE_TOME: case VOTE_LAW: case VOTE_PACT: pSec = get_cabal_vnum(pv->value[0]); if (ch->pCabal && pSec && IS_LEADER(ch) && is_same_cabal( ch->pCabal, pSec)){ return TRUE; } else{ return FALSE; } case VOTE_CAB_DEMO: case VOTE_CAB_EXPEL: if (ch->pCabal && IS_LEADER(ch) && is_same_cabal( ch->pCabal, get_cabal_vnum(pv->value[0])) ) return TRUE; else return FALSE; } return FALSE; } /* vote interpreter, handles all the commands in the vote booth */ void interpret_vote(CHAR_DATA* ch, char* argument ){ char* strtime; VOTE_DATA* pv = next_vote( ch ); while ( isspace(*argument) ) { argument++; } if ( pv == NULL ){ send_to_char("You have no remaining votes, returning to normal mode.\n\r", ch); if (ch->desc->connected == CON_VOTE) ch->desc->connected = CON_PLAYING; else{ connect_char( ch->desc ); do_save( ch, ""); } return; } if (IS_NULLSTR( argument ) ){ strtime = ctime( &pv->time_stamp ); sendf( ch, "%s: %s\n\r%s\n\r", pv->from, pv->subject, strtime ); send_to_char( pv->string, ch ); send_to_char( "\n\r", ch ); } else if (!str_cmp("yes", argument) ){ pv->yes += get_voteweight(ch, pv ); ch->pcdata->vote_skip = 0; ch->pcdata->last_vote = pv->time_stamp; check_vote( pv ); interpret_vote(ch, "" ); return; } else if (!str_cmp("no", argument) ){ pv->no += get_voteweight(ch, pv ); ch->pcdata->vote_skip = 0; ch->pcdata->last_vote = pv->time_stamp; check_vote ( pv ); interpret_vote(ch, "" ); return; } else if (!str_cmp("pass", argument) ){ pv->pass += get_voteweight(ch, pv ); ch->pcdata->vote_skip = 0; ch->pcdata->last_vote = pv->time_stamp; check_vote( pv ); interpret_vote(ch, "" ); return; } else if (!str_cmp("force", argument) ){ if (get_trust(ch) < IMPLEMENTOR){ send_to_char("You cannot force votes.\n\r",ch); return; } pv->yes = 666; ch->pcdata->vote_skip = 0; ch->pcdata->last_vote = pv->time_stamp; check_vote( pv ); interpret_vote(ch, "" ); return; } else if (!str_cmp("quit", argument) ){ if (ch->pcdata->vote_skip >= VOTE_MAXSKIP){ send_to_char("You must vote at least once before quitting.\n\r", ch); } else{ if (!IS_IMMORTAL(ch)) ch->pcdata->vote_skip++; if (ch->desc->connected == CON_VOTE){ ch->desc->connected = CON_PLAYING; } else{ connect_char( ch->desc ); do_save( ch, ""); } return; } } else if (!str_cmp(argument, "help")){ do_help(ch, "vote"); } else if (!str_cmp(argument, "veto")){ if (!can_veto(ch, pv)) return; pv->veto = TRUE; ch->pcdata->last_vote = pv->time_stamp; check_vote( pv ); interpret_vote(ch, "" ); return; } /* command prompt */ send_to_char("You may \"quit\" from this vote and come back to it at later time.\n\r", ch ); sendf(ch, "Cmds: quit, help, yes, no, pass%s> ", can_veto(ch, pv) ? ", veto" : ""); } /* the following functions are used to decide if the vote passed or failed */ /* Decides if a single vote has passed or failed according to following: * * * 1) yes == no mud selects randomly. * 2) yes > no vote passes * 3) yes < no vote fails * 4) if Vetoed the vote always fails * * Returns TRUE for pass, FALSE for fail * */ bool judge_vote( VOTE_DATA* pv ){ if (pv == NULL){ bug("judge_vote: null vote passed", 0); return FALSE; } if (pv->veto) return FALSE; else if (pv->yes < pv->no ) return FALSE; else if (pv->yes > pv->no ) return TRUE; else if ( (pv->yes || pv->no || pv->pass) && number_range(1, 1000) <= 500) return TRUE; else return FALSE; } /* based on the value of the fPassed executes the effects of the vote based on type and its data */ void execute_vote( VOTE_DATA* pv, bool fPass ){ CHAR_DATA* ch; CMEMBER_DATA* cMem; CABAL_DATA* pc = NULL; CABAL_DATA* pc2 = NULL; DESCRIPTOR_DATA* d; char buf[MSL]; bool fPurge = FALSE; /* standard check */ if (pv == NULL) return; /* meat and potatoes of the function, does work based on the type of vote and if it failed. */ switch (pv->type ){ default: case VOTE_GENERAL: case VOTE_CAB_POLL: sprintf( buf, "The vote %s created by %s has %s.\n\rResults:\n\r"\ "For: %d Against: %d Pass: %d\n\r", pv->subject, pv->from, pv->veto ? "been VETOED" : !fPass ? "FAILED" : "PASSED", pv->yes, pv->no, pv->pass); do_hal( pv->owner, pv->subject, buf, NOTE_NEWS ); break; case VOTE_CAB_APPLY: if ( (pc = get_cabal_vnum( pv->value[0] )) == NULL){ bug("execute_vote: CAB_APPLY could not find cabal index %d.", pv->value[0]); break; } sprintf( buf, "A vote has been completed: %s's %s has been %s.\n\rResults:\n\r"\ "%d For, %d Against, %d Pass\n\r", pv->owner, pv->subject, pv->veto ? "VETOED" : !fPass ? "REJECTED" : "APPROVED", pv->yes, pv->no, pv->pass); do_hal( pc->name, pv->subject, buf, NOTE_NEWS ); sprintf( buf, "The %s of %s have %s your %s.\n\rResults:\n\r"\ "%d For, %d Against, %d Pass\n\r%s\n\r", pv->veto ? "leader" : "members", pc->name, pv->veto ? "VETOED" : !fPass ? "REJECTED" : "APPROVED", pv->subject, pv->yes, pv->no, pv->pass, !fPass ? "You may re-apply in fourteen days." : "Seek further guidance amongst your new faction." ); do_hal( pv->owner, pv->subject, buf, NOTE_NEWS ); if (!fPass){ CMEMBER_DATA* cm; /* clear sponsor if any */ if ( (cm = sponsor_check(pc, pv->owner )) == NULL) break; sprintf( buf, "Your obligations as a sponsor of %s have ended.\n\r", pv->owner); do_hal( cm->name, "End of Sponsorship.", buf, NOTE_NEWS); free_string(cm->sponsored); cm->sponsored = str_dup( "" ); CHANGE_CABAL( pc ); save_cabals( TRUE, NULL ); break; } /* check if player is in the lands */ if ( (ch = get_char( pv->owner )) == NULL){ /* check if we can bring the player on */ if ( (d = bring(pc->anchor ? pc->anchor : get_room_index( ROOM_VNUM_LIMBO ), pv->owner)) == NULL){ bug("execute_vote: Could not find the applicant pfile.", 0); break; } else{ ch = d->character; /* we set the messages for login since he was not online */ SET_BIT(ch->pcdata->messages, !fPass ? MSG_CAB_REJECT : MSG_CAB_ACCEPT); /* if the cabal had an achnor room we make sure that is the room person will log into */ fPurge = TRUE; } } /* approved, we check if member of cabal already, if not we make it so */ if (ch->pCabal == NULL){ CMEMBER_DATA* cm; char_to_cabal( ch, pc ); //saves cabals /* make sure the person has enough hours for this month */ ch->pcdata->member->mhours = 36000; update_cabal_skills(ch, ch->pCabal, FALSE, TRUE); /* check for sponsorship */ if ( (cm = sponsor_check(pc, pv->owner )) != NULL){ if (!IS_NULLSTR(ch->pcdata->member->sponsor)) free_string(ch->pcdata->member->sponsor); ch->pcdata->member->sponsor = strdup( cm->name ); /* increase hours and promote once due to sponsorship */ ch->pcdata->member->hours = 36000; promote(ch, pc, 1 ); } CHANGE_CABAL( pc ); save_cabals( TRUE, NULL ); save_char_obj( ch ); } /* char is present */ sprintf( buf, "By your decision %s has been allowed into the ranks of %s.\n\r", PERS2( ch ), pc->who_name ); cabal_echo( ch->pCabal, buf ); /* check if we need to purge the character */ if (fPurge){ purge( ch ); } break; case VOTE_CAB_PROM: case VOTE_CAB_DEMO: case VOTE_CAB_ELDER: case VOTE_CAB_LEADER: case VOTE_CAB_EXPEL: if ( (pc = get_cabal_vnum( pv->value[0] )) == NULL){ bug("execute_vote: CAB_PROMOTIONS could not find cabal index %d.", pv->value[0]); break; } else pc = get_parent( pc ); /* get their cmember data, and update timestamp if possible */ if ( (cMem = get_cmember( pv->owner, pc )) == NULL){ bug("execute_vote: CAB_PROMOTIONS could not find cmember data.",0); break; } else{ /* set application wait time for demotions (success) and promotions (failure)*/ if (fPass && (pv->type == VOTE_CAB_EXPEL || pv->type == VOTE_CAB_DEMO)) cMem->time_stamp = mud_data.current_time; else if (!fPass && (pv->type == VOTE_CAB_PROM || pv->type == VOTE_CAB_ELDER || pv->type == VOTE_CAB_LEADER)) cMem->time_stamp = mud_data.current_time; } sprintf( buf, "A vote has been completed: %s's %s has been %s.\n\rResults:\n\r"\ "%d For, %d Against, %d Pass\n\r", pv->owner, pv->subject, pv->veto ? "VETOED" : !fPass ? "REJECTED" : "APPROVED", pv->yes, pv->no, pv->pass); do_hal( pc->name, pv->subject, buf, NOTE_NEWS ); if (pv->type == VOTE_CAB_EXPEL ) sprintf( buf, "The %s of %s have %s your explulsion from %s.\n\rResults:\n\r"\ "%d For, %d Against, %d Pass\n\r", pv->veto ? "leader" : "members", pc->name, pv->veto ? "VETOED" : !fPass ? "REJECTED" : "APPROVED", pc->who_name, pv->yes, pv->no, pv->pass); else sprintf( buf, "The %s of %s have %s your %s.\n\rResults:\n\r"\ "%d For, %d Against, %d Pass\n\r%s\n\r", pv->veto ? "leader" : "members", pc->name, pv->veto ? "VETOED" : !fPass ? "REJECTED" : "APPROVED", pv->subject, pv->yes, pv->no, pv->pass, !fPass ? "" : "Seek further guidance amongst your new faction." ); do_hal( pv->owner, pv->subject, buf, NOTE_NEWS ); if (!fPass){ break; } /* check if player is in the lands */ if ( (ch = get_char( pv->owner )) == NULL){ /* check if we can bring the player on */ if ( (d = bring(get_room_index( ROOM_VNUM_LIMBO ), pv->owner)) == NULL){ bug("execute_vote: Could not find the applicant pfile.", 0); break; } else{ ch = d->character; /* we set the messages for login since he was not online */ SET_BIT(ch->pcdata->messages, pv->type == VOTE_CAB_DEMO ? MSG_CAB_DEMO : pv->type == VOTE_CAB_EXPEL ? MSG_CAB_EXPEL : MSG_CAB_PROM); fPurge = TRUE; } } if (ch->pCabal == NULL){ bug("execute_vote: CABAL_PROMOTIONS: character was not member of a cabal.\n\r", 0); } else{ CMEMBER_DATA* cm; /* if expel, we kick them out */ if (pv->type == VOTE_CAB_EXPEL){ char buf[MIL]; sprintf( buf, "By decision of majority %s has been removed from ranks of %s.", ch->name, ch->pCabal->who_name); cabal_echo( ch->pCabal, buf ); /* clear sponsor if any */ if ( (cm = sponsor_check(pc, pv->owner )) != NULL){ sprintf( buf, "Your obligations as a sponsor of %s have ended.\n\r", pv->owner); do_hal( cm->name, "End of Sponsorship.", buf, NOTE_NEWS); free_string(cm->sponsored); cm->sponsored = str_dup( "" ); CHANGE_CABAL( pc ); save_cabals( TRUE, NULL ); } /* remove the person */ ch->pcdata->last_app = mud_data.current_time + VOTE_DAY * 7; update_cabal_skills(ch, ch->pCabal, TRUE, TRUE); char_from_cabal( ch ); save_char_obj( ch ); CHANGE_CABAL( pc ); save_cabals( TRUE, NULL ); } else{ int old_rank = ch->pcdata->rank; /* approved we promote or demote them accordingly */ int rank = promote(ch, ch->pCabal, pv->type == VOTE_CAB_DEMO ? -1 : 1); //saves cabals /* clear sponsor if any */ if ( old_rank < rank && rank >= 2){ if ( (cm = sponsor_check(pc, pv->owner )) != NULL){ char buf[MIL]; sprintf( buf, "Your obligations as a sponsor of %s have ended.\n\r", pv->owner); do_hal( cm->name, "End of Sponsorship.", buf, NOTE_NEWS); free_string(cm->sponsored); cm->sponsored = str_dup( "" ); } if (!IS_NULLSTR(ch->pcdata->member->sponsor )){ free_string( ch->pcdata->member->sponsor ); ch->pcdata->member->sponsor = str_dup( "" ); } CHANGE_CABAL( pc ); save_cabals( TRUE, NULL ); } save_char_obj( ch ); sendf( ch, "You have been %s to the rank of %s!\n\r", pv->type == VOTE_CAB_DEMO ? "demoted" : "promoted", ch->pcdata->true_sex == SEX_FEMALE ? ch->pCabal->pIndexData->franks[rank] : ch->pCabal->pIndexData->mranks[rank] ); } if (!fPurge){ /* char is present */ char buf[MIL]; sprintf( buf, "By your decision %s has been %s to the rank of %s.\n\r", PERS2( ch ), pv->type == VOTE_CAB_DEMO ? "demoted" : "promoted", get_crank( ch )); cabal_echo( ch->pCabal, buf ); if (has_child_choice( ch->pCabal, ch->pcdata->rank )){ send_to_char("`2You are now able to choose further within your organization. (\"cabal join\")``\n\r", ch); } } } /* check if we need to purge the character */ if (fPurge){ purge( ch ); } break; case VOTE_LAW: if ( (pc = get_cabal_vnum( pv->value[0] )) == NULL){ bug("execute_vote: VOTE_LAW could not find cabal index %d.", pv->value[0]); break; } else{ AREA_DATA* pArea; char to [MIL]; sprintf( buf, "The %s of %s have %s %s.\n\rResults:\n\r"\ "%d For, %d Against, %d Pass\n\r%s\n\r", pv->veto ? "leader" : "members", pc->name, pv->veto ? "VETOED" : !fPass ? "REJECTED" : "APPROVED", pv->subject, pv->yes, pv->no, pv->pass, !fPass ? "" : "Seek further guidance in help scrolls about the new penalty." ); sprintf( to, "%s city", pv->owner ); do_hal( to, pv->subject, buf, NOTE_NEWS ); if (!fPass) break; /* we change the cities status */ if ( (pArea = pc->city ) == NULL){ bug("execute_vote: VOTE_LAW could not find an area for cabal vnum %d.", pc->vnum); break; } pArea->crimes[pv->value[1]] = pv->value[2]; save_area( pArea ); } break; case VOTE_CAB_TAX: if ( (pc = get_cabal_vnum( pv->value[0] )) == NULL){ bug("execute_vote: VOTE_CAB_TAX could not find cabal index %d.", pv->value[0]); break; } else{ char to [MIL]; sprintf( buf, "The %s of %s have %s %s.\n\rResults:\n\r"\ "%d For, %d Against, %d Pass\n\r%s\n\r", pv->veto ? "leader" : "members", pc->name, pv->veto ? "VETOED" : !fPass ? "REJECTED" : "APPROVED", pv->subject, pv->yes, pv->no, pv->pass, !fPass ? "" : "Seek further guidance in help scrolls about the effects of tax." ); sprintf( to, "%s", pv->owner ); do_hal( to, pv->subject, buf, NOTE_NEWS ); if (!fPass) break; /* we change the tax status */ pc->cp_tax = pv->value[1]; CHANGE_CABAL( pc ); save_cabals( TRUE, NULL ); } break; case VOTE_CAB_SPONS: if ( (pc = get_cabal_vnum( pv->value[0] )) == NULL){ bug("execute_vote: VOTE_SPONS could not find cabal index %d.", pv->value[0]); break; } else{ char to [MIL]; sprintf( buf, "The %s of %s have %s %s.\n\rResults:\n\r"\ "%d For, %d Against, %d Pass\n\r%s\n\r", pv->veto ? "leader" : "members", pc->name, pv->veto ? "VETOED" : !fPass ? "REJECTED" : "APPROVED", pv->subject, pv->yes, pv->no, pv->pass, !fPass ? "" : "Seek further guidance in help scrolls about the effects of sponsorship." ); sprintf( to, "%s", pc->name ); do_hal( to, pv->subject, buf, NOTE_NEWS ); if (!fPass) break; /* we toggle sponsorship */ TOGGLE_BIT(pc->flags, CABAL_SPONSOR); CHANGE_CABAL( pc ); save_cabals( TRUE, NULL ); } break; case VOTE_TITHE: if ( (pc = get_cabal_vnum( pv->value[0] )) == NULL){ bug("execute_vote: VOTE_TITHE could not find cabal index %d.", pv->value[0]); break; } if ( (pc2 = get_cabal_vnum( pv->value[1] )) == NULL){ bug("execute_vote: VOTE_TITHE could not find second cabal index %d.", pv->value[1]); break; } else{ char to [MIL]; sprintf( buf, "The %s of %s have %s %s.\n\rResults:\n\r"\ "%d For, %d Against, %d Pass\n\r%s\n\r", pv->veto ? "leader" : "members", pc->name, pv->veto ? "VETOED" : !fPass ? "REJECTED" : "APPROVED", pv->subject, pv->yes, pv->no, pv->pass, !fPass ? "" : "Seek further guidance in help scrolls about the effects of tithe." ); sprintf( to, "%s %s", pc->name, pc2->name ); do_hal( to, pv->subject, buf, NOTE_NEWS ); if (!fPass){ CP_CAB_GAIN( pc, pv->value[2] ); break; } CP_CAB_GAIN( pc2, pv->value[2] ); affect_cabal_relations(pc, pc2, pv->value[2] / 4, TRUE ); CHANGE_CABAL( pc2 ); save_cabals( TRUE, NULL ); } break; case VOTE_TOME: if ( (pc = get_cabal_vnum( pv->value[0] )) == NULL){ bug("execute_vote: VOTE_TOME could not find cabal index %d.", pv->value[0]); break; } else{ char to [MIL]; sprintf( buf, "The %s of %s have %s %s.\n\rResults:\n\r"\ "%d For, %d Against, %d Pass\n\r", pv->veto ? "leader" : "members", pc->name, pv->veto ? "VETOED" : !fPass ? "REJECTED" : "APPROVED", pv->subject, pv->yes, pv->no, pv->pass); sprintf( to, "%s", pv->owner ); do_hal( to, pv->subject, buf, NOTE_NEWS ); if (!fPass){ break; } //add the new vote HERE else{ TOME_DATA* tome; char sub[MIL]; char tit[MIL]; char* ptr; /* extract the subject/title from subject line */ if ( (ptr = strchr(pv->subject, ':')) == NULL){ bug("execute_vote: VOTE_TOME could not find subject terminator.", 0); return; } *ptr = 0; strcpy(tit, ptr + 1); strcpy(sub, pv->subject); if ( (tome = AddTome(sub, tit, pv->from, pv->string )) != NULL){ EchoTome( tome ); SaveTomes(); } } } case VOTE_BUILD: if ( (pc = get_cabal_vnum( pv->value[0] )) == NULL){ bug("execute_vote: VOTE_BUILD could not find cabal index %d.", pv->value[0]); break; } else{ char to [MIL]; CVROOM_DATA* pcv, *to_cvroom; CVROOM_DATA* old; EXIT_DATA* pExit; int door = 0; int to_pos[3]; bool fSell = pv->value[4] > 0; sprintf( buf, "The %s of %s have %s %s.\n\rResults:\n\r"\ "%d For, %d Against, %d Pass\n\r", pv->veto ? "leader" : "members", pc->name, pv->veto ? "VETOED" : !fPass ? "REJECTED" : "APPROVED", pv->subject, pv->yes, pv->no, pv->pass); sprintf( to, "%s", pc->name ); do_hal( to, pv->subject, buf, NOTE_NEWS ); /* SELL */ if (fSell){ int doors = 0; EXIT_DATA* pexit; if (!fPass) break; /* get a complete cvroom that this vote referes to */ pcv = get_cvroom_xyz( pv->value[1], pv->value[2], pv->value[3], pc, TRUE, FALSE ); if (pcv == NULL){ sprintf( buf, "execute_vote: CAB_BUILD: could not get cvroom %d %d %d to sell", pv->value[1], pv->value[2], pv->value[3] ); bug( buf, 0); break; } /* give cabal the cost due */ if (pcv->pRoom->vnum != ROOM_VNUM_CROOM_DUMMY) CP_CAB_GAIN( pcv->pRoom->pCabal, pv->value[4] ); /* now we know which room we are selling, we check if this room has more then 1 exit */ for (door = 0; door < MAX_DOOR; door ++ ){ if ( (pexit = pcv->pRoom->exit[door]) != NULL && pexit->to_room != NULL) doors++; } sell_room( pcv, pc, pv->value[4] ); VRCHANGE_CABAL( pc ); CHANGE_CABAL( pc ); save_cabals( TRUE, NULL ); break; } /* EDIT/BUILD */ /* get an incomplete cvroom that this vote referes to */ pcv = get_cvroom_xyz( pv->value[1], pv->value[2], pv->value[3], pc, FALSE, TRUE ); if (pcv == NULL){ sprintf( buf, "execute_vote: CAB_BUILD: could not get cvroom %d %d %d", pv->value[1], pv->value[2], pv->value[3] ); bug( buf, 0); break; } if (!fPass){ CP_CAB_GAIN( pc, -pv->value[4] ); cvroom_from_cabal( pcv, pc ); VRCHANGE_CABAL( pc ); free_cvroom( pcv ); break; } /* find if this overlaps an existing room (edit), and remove it */ if ( (old = get_cvroom_xyz( pv->value[1], pv->value[2], pv->value[3], pc, TRUE, FALSE )) != NULL){ unload_vir_room( old->pRoom ); cvroom_from_cabal( old, pc ); VRCHANGE_CABAL( pc ); free_cvroom( old ); } /* we change the rooms status and load it */ pcv->pRoom->area = pc->anchor->area; pcv->fComplete = TRUE; fix_vir_exits( pcv ); load_vir_room( pcv->pRoom, pc->anchor->area ); /* we check if we have to update exits on rooms waiting to be approved */ for (door = 0; door < MAX_DOOR; door++){ if ( (pExit = pcv->pRoom->exit[door]) == NULL) continue; /* check if this exit leads to another cvroom */ if (!IS_VIRVNUM(pExit->vnum)) continue; /* now we have an exit from cvroom to cvroom, we get that room by our position + exit direction */ to_pos[P_X] = pcv->pos[P_X]; to_pos[P_Y] = pcv->pos[P_Y]; to_pos[P_Z] = pcv->pos[P_Z]; get_new_coordinates( to_pos, door ); /* we now look for INCOMPLETE room in that position */ if ( (to_cvroom = get_cvroom_xyz(to_pos[P_X], to_pos[P_Y], to_pos[P_Z], pcv->pRoom->pCabal, FALSE, TRUE)) == NULL || to_cvroom->pRoom->exit[rev_dir[door]] != NULL) continue; else{ to_cvroom->pRoom->exit[rev_dir[door]] = new_exit(); to_cvroom->pRoom->exit[rev_dir[door]]->vnum = pcv->pRoom->vnum; to_cvroom->pRoom->exit[rev_dir[door]]->key = 0; to_cvroom->pRoom->exit[rev_dir[door]]->orig_door = rev_dir[door]; to_cvroom->pRoom->exit[rev_dir[door]]->exit_info = pExit->rs_flags; to_cvroom->pRoom->exit[rev_dir[door]]->rs_flags = pExit->rs_flags; if (!IS_NULLSTR(pExit->keyword)) to_cvroom->pRoom->exit[rev_dir[door]]->keyword = str_dup(pExit->keyword); if (!IS_NULLSTR(pExit->description)) to_cvroom->pRoom->exit[rev_dir[door]]->description = str_dup(pExit->description); } } refresh_cvroom_flags( pc ); VRCHANGE_CABAL( pc ); CHANGE_CABAL( pc ); } break; case VOTE_PACT: if ( (pc = get_cabal_vnum( pv->value[0] )) == NULL){ bug("execute_vote: VOTE_PACT could not find cabal index %d.", pv->value[0]); break; } else if ( (pc2 = get_cabal_vnum( pv->value[1] )) == NULL){ bug("execute_vote: VOTE_PACT could not find cabal index %d.", pv->value[0]); break; } else{ char to [MIL]; if (pv->value[4] == PACT_VENDETTA){ /* send a message out to the other cabal that a vendetta has been declared */ sprintf( buf, "The members of [%s] have declared a Vendetta against you!\n\r", pc->who_name); do_hal( pc2->name, "A Vendetta has been declared!", buf, NOTE_NEWS ); sprintf( to, "%s", pc->name ); } /* on embargo send a message out that all trade has stopped */ else if (pv->value[4] == PACT_BREAK){ /* send a message out to the other cabal that a vendetta has been declared */ sprintf( buf, "The members of [%s] have stopped all trade with you.\n\r", pc->who_name); do_hal( pc2->name, pv->subject, buf, NOTE_NEWS ); /* we setup "to" so that only the creatore of this embargo gets the next hal note */ sprintf( to, "%s", pc->name ); } else sprintf( to, "%s %s", pc->name, pc2->name ); /* safeguard: PACT_IMPROVE fails if we try to improve a pact to an alliance with an alliance already in cabal */ if (pv->value[4] == PACT_IMPROVE && pv->value[2] == PACT_ALLIANCE && (IS_CABAL(pc, CABAL_ALLIANCE) || IS_CABAL(pc2, CABAL_ALLIANCE)) ){ fPass = FALSE; pv->veto = TRUE; } sprintf( buf, "The %s of %s have %s %s.\n\rResults:\n\r"\ "%d For, %d Against, %d Pass\n\r%s\n\r", pv->veto ? "leader" : "members", pc->name, pv->veto ? "VETOED" : !fPass ? "REJECTED" : "APPROVED", pv->subject, pv->yes, pv->no, pv->pass, fPass ? "" : "Seek further guidance in help scrolls about effects of this pact." ); do_hal( to, pv->subject, buf, NOTE_NEWS ); /* vote failed, we remove the pact and matching votes if needed */ if (!fPass){ PACT_DATA* pp = get_pact_abs( pc, pc2, pv->value[4], FALSE); VOTE_DATA* pVote = NULL; if (pp){ rem_pact( pp ); free_pact ( pp ); save_cabals( FALSE, NULL ); } /* remove matching trade vote if this was a trade vote */ if (pv->value[4] >= PACT_TRADE && pv->value[4] <= PACT_ALLIANCE){ if ( (pVote = get_vote( VOTE_PACT, pc->vnum, pc2->vnum, 0, 0, PACT_TRADE)) != NULL){ rem_vote ( pVote ); free_vote( pVote ); } if ( (pVote = get_vote( VOTE_PACT, pc2->vnum, pc->vnum, 0, 0, PACT_TRADE)) != NULL){ rem_vote ( pVote ); free_vote( pVote ); } } /* remove a matching peace vote if this was a peace vote */ else if (pv->value[4] == PACT_PEACE){ if ( (pVote = get_vote( VOTE_PACT, pc->vnum, pc2->vnum, 0, 0, PACT_PEACE)) != NULL){ rem_vote ( pVote ); free_vote( pVote ); } } /* remove a matching peace vote if this was an improvement vote */ else if (pv->value[4] == PACT_IMPROVE){ if ( (pVote = get_vote( VOTE_PACT, pc->vnum, pc2->vnum, 0, 0, PACT_IMPROVE)) != NULL){ rem_vote ( pVote ); free_vote( pVote ); } break; } } /* vote sucess, we either create incomplete pact, or complete a pact */ else{ PACT_DATA* pp = get_pact_abs( pc, pc2, pv->value[4], FALSE); /* we check if the pact exist or is already completed */ if ( pp == NULL ){ if ( (pp = create_pact(pc, pc2, pv->value[4])) == NULL){ bug("execute_vote: VOTE_PACT could not create a pact type %d", pv->value[4]); break; } /* we have an empty pact now, set the gains on it */ /* SPECIAL CASES: */ /* Vendetta automaticly creates a complete pact */ if (IS_SET(pv->value[4], PACT_VENDETTA)){ VOTE_DATA* pVote; PACT_DATA* pTrade = NULL; pp->complete= PACT_COMPLETE; pp->b_cp = pv->value[2]; pp->b_sup = pv->value[3]; /* remove a vendetta and trade votes from the other cabal if they exists */ if ( (pVote = get_vote( VOTE_PACT, pc2->vnum, pc->vnum, 0, 0, PACT_VENDETTA)) != NULL){ rem_vote ( pVote ); free_vote( pVote ); } /* remove trade votes */ if ( (pVote = get_vote( VOTE_PACT, pc->vnum, pc2->vnum, 0, 0, PACT_TRADE)) != NULL){ rem_vote ( pVote ); free_vote( pVote ); } if ( (pVote = get_vote( VOTE_PACT, pc2->vnum, pc->vnum, 0, 0, PACT_TRADE)) != NULL){ rem_vote ( pVote ); free_vote( pVote ); } /* we clean out all trade pacts between cabals as well */ if ( (pTrade = get_pact_abs( pc, pc2, PACT_TRADE, TRUE)) != NULL){ rem_pact( pTrade); free_pact( pTrade ); } /* we hurt relations between cabals and their trade partners */ affect_cabal_relations(pc, pc2, -1000, FALSE ); } /* EMBARGO automaticly destroyes all trade pacts between cabals, and then expires (does not become a pact) */ else if (IS_SET(pv->value[4], PACT_BREAK)){ PACT_DATA* pTrade = NULL; /* we hurt relations between cabals and their trade partners */ affect_cabal_relations(pc, pc2, -500, FALSE ); /* check for alliance first, in order to dissolve armies */ if ( (pTrade = get_pact_abs( pc, pc2, PACT_ALLIANCE, FALSE)) != NULL){ if (break_alliance_check( pc, pc2 )){ char buf[MIL]; sprintf(buf, "The armies stationed with %s bastions have been dismissed.", pc->name ); do_hal( pc2->name, "Some of your armies have been dismissed.", buf, NOTE_NEWS ); } if (break_alliance_check( pc2, pc )){ char buf[MIL]; sprintf(buf, "The armies stationed with %s bastions have been dismissed.", pc2->name ); do_hal( pc->name, "Some of your armies have been dismissed.", buf, NOTE_NEWS ); } rem_pact( pTrade); free_pact( pTrade ); free_pact( pp ); CHANGE_CABAL( pc ); CHANGE_CABAL( pc2 ); save_cabals( TRUE, NULL ); break; } if ( (pTrade = get_pact_abs( pc, pc2, PACT_TRADE, TRUE)) != NULL){ rem_pact( pTrade); free_pact( pTrade ); free_pact( pp ); save_cabals( TRUE, NULL ); break; } else{ free_pact( pp ); save_cabals( TRUE, NULL ); break; } } else pp->complete = PACT_INCOMPLETE; pp->c_cp = pv->value[2]; pp->c_sup = pv->value[3]; add_pact( pp ); save_cabals( FALSE, NULL ); } /* this should never happen */ else if ( pp->complete == PACT_NONE ){ pp->complete = PACT_INCOMPLETE; pp->c_cp = pv->value[2]; pp->c_sup = pv->value[3]; } /* VOTE WAS COMPLETED ONLY BY ONE SIDE THE OTHER SIDE NOW COMPLETED A VOTE AS WELL */ else{ AREA_DATA* pArea = NULL; /* we complete the vote */ pp->complete = PACT_COMPLETE; pp->b_cp = pv->value[2]; pp->b_sup = pv->value[3]; refresh_pact_flags(); /* special behavior for completion */ /* improvement of trade sets the maximum of trade between cabals to its value[2] value */ if (IS_SET(pv->value[4], PACT_IMPROVE)){ PACT_DATA* pTrade = get_pact( pc, pc2, PACT_TRADE, TRUE); if (pTrade) pTrade->Adv = pv->value[2]; /* expire the improve pact right away */ rem_pact( pp ); free_pact( pp ); } /* if this is a peace vote we remove any vendettas between the cabals, and votes for them then expires */ else if (IS_SET(pv->value[4], PACT_PEACE)){ PACT_DATA* pVen = get_pact_abs( pc, pc2, PACT_VENDETTA, FALSE); VOTE_DATA* pVote; /* remove any vendetta votes */ if ( (pVote = get_vote( VOTE_PACT, pc2->vnum, pc->vnum, 0, 0, PACT_VENDETTA)) != NULL){ rem_vote ( pVote ); free_vote( pVote ); } if ( (pVote = get_vote( VOTE_PACT, pc->vnum, pc2->vnum, 0, 0, PACT_VENDETTA)) != NULL){ rem_vote ( pVote ); free_vote( pVote ); } /* remove a vendetta pact between the cabals */ if (pVen){ rem_pact( pVen ); free_pact ( pVen ); save_cabals( FALSE, NULL ); } /* expire the peace pact right away */ rem_pact( pp ); free_pact( pp ); /* we improve relations between cabals and their trade partners */ affect_cabal_relations(pc, pc2, 200, FALSE ); affect_cabal_relations(pc2, pc, 200, FALSE ); } /* EMBARGO automaticly destroyes all trade pacts between cabals, and then expires (does not become a pact) */ else if (IS_SET(pv->value[4], PACT_BREAK)){ PACT_DATA* pTrade = NULL; /* we hurt relations between cabals and their trade partners */ affect_cabal_relations(pc, pc2, -500, FALSE ); /* check for alliance first, in order to dissolve armies */ if ( (pTrade = get_pact_abs( pc, pc2, PACT_ALLIANCE, FALSE)) != NULL){ if (break_alliance_check( pc, pc2 )){ char buf[MIL]; sprintf(buf, "The armies stationed with %s bastions have been dismissed.", pc->name ); do_hal( pc2->name, "Some of your armies have been dismissed.", buf, NOTE_NEWS ); } if (break_alliance_check( pc2, pc )){ char buf[MIL]; sprintf(buf, "The armies stationed with %s bastions have been dismissed.", pc2->name ); do_hal( pc->name, "Some of your armies have been dismissed.", buf, NOTE_NEWS ); } rem_pact( pTrade); free_pact( pTrade ); rem_pact( pp); free_pact( pp ); save_cabals( TRUE, NULL ); break; } if ( (pTrade = get_pact_abs( pc, pc2, PACT_TRADE, TRUE)) != NULL){ rem_pact( pTrade); free_pact( pTrade ); rem_pact( pp); free_pact( pp ); save_cabals( TRUE, NULL ); break; } else{ rem_pact( pp); free_pact( pp ); save_cabals( TRUE, NULL ); break; } } /* we change the cities status if this was a trade pact with justice */ else if (IS_CABAL(pc2, CABAL_JUSTICE) && IS_CABAL(pc, CABAL_ROYAL)){ if ( (pArea = pc->city) == NULL){ bug("execute_vote: VOTE_PACT could not find an area for cabal vnum %d.", pv->value[0]); break; } else{ /* send a note to the area about lawfulness */ char buf[MIL]; char to[MIL]; sprintf(buf, warn_table[WARN_LAWFUL].subj, pArea->name, pc2->name); sprintf(to, "%s city", pc->name ); do_hal(to, buf, warn_table[WARN_LAWFUL].text, NOTE_NEWS); SET_BIT(pArea->area_flags, AREA_LAWFUL ); affect_cabal_relations(pc, pc2, 200, FALSE ); affect_cabal_relations(pc2, pc, 200, FALSE ); } } else if (IS_CABAL(pc, CABAL_JUSTICE) && IS_CABAL(pc2, CABAL_ROYAL)){ if ( (pArea = pc2->city) == NULL){ bug("execute_vote: VOTE_PACT could not find an area for cabal vnum %d.", pv->value[0]); break; } else{ /* send a note to the area about lawfulness */ char buf[MIL]; char to[MIL]; sprintf(buf, warn_table[WARN_LAWFUL].subj, pArea->name, pc->name); sprintf(to, "%s city", pc2->name ); do_hal(to, buf, warn_table[WARN_LAWFUL].text, NOTE_NEWS); SET_BIT(pArea->area_flags, AREA_LAWFUL ); affect_cabal_relations(pc2, pc, 200, FALSE ); affect_cabal_relations(pc, pc2, 200, FALSE ); } } save_cabals( FALSE, NULL ); }//END COMPLETE PACT }//END if vote was success }//END BOTH CABALS FOUND break; } /* we now nuke the vote */ rem_vote( pv ); free_vote( pv ); save_mud(); save_cabals( TRUE, NULL ); } /* checks a single vote and decides if the vote should be judged for pass/fail * CRITERIA for vote judgement: * * 1) If yes + no + pass >= max_vote * 2) life_time < current_time * 3) If yes + no + pass > 3 * max_vote / 4 && (time_stamp + life_time) / 2 < current_time //allows for early majority vote * 4) vote has been VETOED * * If above are satisfied judge_vote is called. */ void check_vote( VOTE_DATA* pv ){ int rem_votes = 0; if (pv == NULL) return; else rem_votes = pv->max_vote - pv->yes - pv->no - pv->pass; if (pv->veto || (pv->yes + pv->no + pv->pass) >= pv->max_vote //all votes done || pv->life_time < mud_data.current_time //vote expired || pv->yes > pv->no + rem_votes || pv->no > pv->yes + rem_votes || ( (pv->yes + pv->no + pv->pass) >= 3 * pv->max_vote / 4 && (pv->time_stamp + pv->life_time) / 2 < mud_data.current_time) ){ execute_vote( pv, judge_vote( pv ) ); } } /* this function is called once per PULSE_VOTE, and on each reboot to refresh votes */ void vote_update( ){ VOTE_DATA* pv, *pv_next; for (pv = vote_list; pv != NULL; pv = pv_next){ pv_next = pv->next; check_vote( pv ); } }