/************************************************************************** * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * * * Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * * * In order to use any part of this Merc Diku Mud, you must comply with * * both the original Diku license in 'license.doc' as well the Merc * * license in 'license.txt'. In particular, you may not remove either of * * these copyright notices. * * * * Much time and thought has gone into this software and you are * * benefiting. 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 * *************************************************************************** * 1stMUD ROM Derivative (c) 2001-2003 by Ryan Jennings * * http://1stmud.dlmud.com/ <r-jenn@shaw.ca> * ***************************************************************************/ #include "merc.h" #include "tables.h" #include "recycle.h" #include "interp.h" #define WAR_KILLED (BIT_A) #define WAR_DECOY (BIT_B) struct war_type { const char *name; const char *plural; enum war_types type; }; const struct war_type war_table[MAX_WAR] = { {"none", "none", WAR_NONE}, {"clan", "clans", WAR_CLAN}, {"race", "races", WAR_RACE}, {"class", "classes", WAR_CLASS}, {"genocide", "people", WAR_GENOCIDE}, {"deity", "deities", WAR_DEITY}, {"sex", "sexes", WAR_SEX} }; int war_lookup(const char *arg) { int i; for (i = WAR_NONE; i < MAX_WAR; i++) { if (is_number(arg) ? atoi(arg) == war_table[i].type : !str_prefix(arg, war_table[i].name)) return i; } return -1; } char *wartype_name(int type, bool plural) { int i; for (i = 0; i < MAX_WAR; i++) if (war_table[i].type == type) return capitalize(!plural ? war_table[i].name : war_table[i].plural); return "Unknown"; } void new_warlist(CHAR_DATA * ch) { WAR_DATA *wl; if (!ch) return; alloc_mem(wl, WAR_DATA, 1); wl->hit = ch->hit; wl->mana = ch->mana; wl->move = ch->move; if (IS_NPC(ch)) wl->flags = WAR_DECOY; else wl->flags = 0; wl->ch = ch; ch->war = wl; LINK(wl, war_info.first, war_info.last, next, prev); return; } void free_warlist(WAR_DATA * wl) { if (wl->ch) { if (!IS_NPC(wl->ch)) wl->ch->war = NULL; else extract_char(wl->ch, TRUE); } UNLINK(wl, war_info.first, war_info.last, next, prev); free_mem(wl); } #define WAR_COST 3 // in trivia points bool start_war(CHAR_DATA * ch, const char *argument) { char arg1[MIL], arg2[MIL]; char arg3[MIL]; CHAR_DATA *warmaster = NULL; int blevel, elevel, type; for (warmaster = ch->in_room->first_person; warmaster != NULL; warmaster = warmaster->next_in_room) { if (!IS_NPC(warmaster)) continue; if (warmaster->spec_fun == spec_lookup("spec_warmaster")) break; } if (!IS_IMMORTAL(ch) && (warmaster == NULL || warmaster->spec_fun != spec_lookup("spec_warmaster"))) { chprintln(ch, "You can't do that here."); return FALSE; } if (!IS_IMMORTAL(ch) && warmaster->fighting != NULL) { chprintln(ch, "Wait until the fighting stops."); return FALSE; } argument = one_argument(argument, arg1); argument = one_argument(argument, arg2); argument = one_argument(argument, arg3); if (IS_NULLSTR(arg1) || IS_NULLSTR(arg2) || IS_NULLSTR(arg3)) { int i; chprintln(ch, "Syntax: war start <min_level> <max_level> <type>\n\r" "where <type> is either:"); for (i = 1; war_table[i].name != NULL; i++) chprintf(ch, "%d - %s war\n\r", war_table[i].type, war_table[i].name); return FALSE; } blevel = atoi(arg1); elevel = atoi(arg2); type = war_lookup(arg3); if (blevel <= 0 || blevel > MAX_LEVEL) { chprintf(ch, "Level must be between 1 and %d.\n\r", MAX_LEVEL); return FALSE; } if (blevel <= 0 || elevel > MAX_LEVEL) { chprintf(ch, "Level must be between 1 and %d.\n\r", MAX_LEVEL); return FALSE; } if (elevel < blevel) { chprintln(ch, "Max level must be greater than the min level."); return FALSE; } if (elevel - blevel < 5) { chprintln(ch, "Levels must have a difference of at least 5."); return FALSE; } if (type == -1) { int i; chprintln(ch, "The type either has to be:"); for (i = 1; war_table[i].name != NULL; i++) chprintf(ch, "%d (%s)\n\r", war_table[i].type, war_table[i].name); return FALSE; } if (war_info.status != WAR_OFF) { chprintln(ch, "There is already a war going!"); return FALSE; } if (!IS_IMMORTAL(ch)) { if (ch->pcdata->trivia < WAR_COST) { mob_tell(ch, warmaster, "It costs %d Trivia Points to start a %s war.", WAR_COST, wartype_name(type, FALSE)); return FALSE; } else { mob_tell(ch, warmaster, "Thank you %s, %s war started, you are %d trivia points lighter.", ch->name, wartype_name(type, FALSE), WAR_COST); } } war_info.status = WAR_WAITING; replace_string(war_info.who, ch->name); war_info.min_level = blevel; war_info.max_level = elevel; war_info.wartype = war_table[type].type; announce(ch, INFO_WAR, "$n announces a %s war for levels %d to %d. Type 'WAR JOIN' to kill or be killed.", wartype_name(war_info.wartype, FALSE), war_info.min_level, war_info.max_level); announce(ch, INFO_WAR | INFO_PRIVATE, "You announce a %s war for levels %d to %d. Type 'WAR JOIN' to kill or be killed.", wartype_name(war_info.wartype, FALSE), war_info.min_level, war_info.max_level); war_info.timer = 3; return TRUE; } void auto_war(void) { CHAR_DATA *wch, *wch_last; static CHAR_DATA *warmaster = NULL; int maxlvl = 0, minlvl = MAX_LEVEL, middle = MAX_MORTAL_LEVEL / 2; int clan = 0, count = 0, lbonus = 0, half = 0; int heros = 0; if (war_info.status != WAR_OFF) return; for (wch = player_first; wch != NULL; wch = wch->next_player) { if (!wch->desc) continue; if (!IS_NPC(wch) && !IS_IMMORTAL(wch)) { count++; maxlvl = UMAX(maxlvl, wch->level); minlvl = UMIN(minlvl, wch->level); if (wch->level >= LEVEL_HERO && wch->level <= MAX_MORTAL_LEVEL) heros++; if (is_clan(wch)) { for (wch_last = player_first; wch_last != NULL; wch_last = wch_last->next_player) { if (!IS_NPC(wch_last) && !IS_IMMORTAL(wch_last) && is_clan(wch_last) && !is_same_clan(wch, wch_last)) clan++; } } } } if (count < 2) { end_war(); return; } lbonus = number_range(15, 30); minlvl = UMAX(1, minlvl - lbonus); maxlvl = UMIN(MAX_MORTAL_LEVEL, maxlvl + lbonus); half = ((maxlvl - minlvl) / 2); middle = URANGE(minlvl, maxlvl - half, maxlvl); minlvl = UMAX(1, number_range(minlvl, (middle * 2) / 3)); if (heros > 2 && number_percent() < 25) maxlvl = MAX_MORTAL_LEVEL; else maxlvl = UMIN(MAX_MORTAL_LEVEL, number_range((middle * 3) / 2, maxlvl)); if (warmaster == NULL) { for (warmaster = char_first; warmaster != NULL; warmaster = warmaster->next) if (warmaster->pIndexData && warmaster->pIndexData->vnum == MOB_VNUM_WARMASTER) break; } war_info.status = WAR_WAITING; replace_string(war_info.who, (!warmaster ? "AutoWar" : warmaster->short_descr)); war_info.min_level = minlvl; war_info.max_level = maxlvl; if (clan >= 2) war_info.wartype = (enum war_types) number_range(WAR_NONE + 1, MAX_WAR - 1); else war_info.wartype = (enum war_types) number_range(WAR_CLAN + 1, MAX_WAR - 1); if (war_info.wartype == WAR_NONE) war_info.wartype = WAR_GENOCIDE; announce(warmaster, INFO_WAR, "%s %s war for levels %d to %d%s. Type 'WAR JOIN' to kill or be killed.", !warmaster ? "A" : "$n announces a", wartype_name(war_info.wartype, FALSE), war_info.min_level, war_info.max_level, !warmaster ? " has started" : ""); announce(warmaster, INFO_WAR | INFO_PRIVATE, "You announce a %s war for levels %d" " to %d. Type 'WAR JOIN' to kill or be killed.", wartype_name(war_info.wartype, FALSE), war_info.min_level, war_info.max_level); war_info.timer = 3; } void end_war(void) { WAR_DATA *wl, *wl_next; for (wl = war_info.first; wl != NULL; wl = wl_next) { wl_next = wl->next; if (wl->ch) { stop_fighting(wl->ch, TRUE); if (!IS_SET(wl->flags, WAR_DECOY)) { if (!IS_SET(wl->flags, WAR_KILLED)) { char_from_room(wl->ch); char_to_room(wl->ch, get_room_index(ROOM_VNUM_TEMPLE)); } wl->ch->hit = wl->hit; wl->ch->mana = wl->mana; wl->ch->move = wl->move; update_pos(wl->ch); do_function(wl->ch, &do_look, "auto"); } } free_warlist(wl); } replace_string(war_info.who, ""); war_info.wartype = WAR_NONE; war_info.min_level = 0; war_info.max_level = 0; war_info.status = WAR_OFF; war_info.inwar = 0; war_info.timer = number_range(100, 200); war_info.first = war_info.last = NULL; } const char *wartype_info(CHAR_DATA * ch) { switch (war_info.wartype) { default: return ""; case WAR_RACE: return ch->race->name; case WAR_CLASS: return class_table[prime_class(ch)].name; case WAR_GENOCIDE: return ch->name; case WAR_CLAN: return ch->clan->who_name; case WAR_DEITY: return ch->deity->name; case WAR_SEX: return flag_string(sex_flags, ch->sex); } } bool check_wartype_data(CHAR_DATA * ch, CHAR_DATA * victim) { switch (war_info.wartype) { default: return FALSE; case WAR_RACE: return (ch->race == victim->race); case WAR_CLASS: return (prime_class(ch) == prime_class(victim)); case WAR_GENOCIDE: return (ch->id == victim->id); case WAR_CLAN: return (ch->clan == victim->clan); case WAR_DEITY: return (ch->deity == victim->deity); case WAR_SEX: return (ch->sex == victim->sex); } } char *warrior_status(CHAR_DATA * ch) { if (war_info.wartype != WAR_GENOCIDE) return FORMATF("%s (%s, Lvl %d)", ch->name, wartype_info(ch), ch->level); else return FORMATF("%s (Lvl %d)", ch->name, ch->level); } CH_CMD(do_war) { char arg[MIL]; ROOM_INDEX_DATA *location; int i = 0; if (IS_NPC(ch)) { chprintln(ch, "Mobiles not supported yet."); return; } argument = one_argument(argument, arg); if (IS_NULLSTR(arg)) { chprintln(ch, "{gSyntax:{R war {Wstart <minlev> <maxlev> <#type>"); chprintln(ch, " {Rwar {Wtalk <message>"); chprintln(ch, " {Rwar {Wstatus"); chprintln(ch, " {Rwar {Winfo"); chprintln(ch, " {Rwar {Wjoin{x"); chprintln(ch, " {Rwar {Wdecoy{x"); if (IS_IMMORTAL(ch)) chprintln(ch, " {Rwar {Wend{x"); return; } else if (!str_cmp(arg, "start")) { if (ch->pcdata->trivia < WAR_COST && !IS_IMMORTAL(ch)) { chprintf(ch, "It costs %d Trivia Points to start a war.\n\r", WAR_COST); return; } if (start_war(ch, argument) && !IS_IMMORTAL(ch)) ch->pcdata->trivia -= WAR_COST; return; } else if (!str_cmp(arg, "talk")) { war_talk(ch, argument); return; } else if (!str_cmp(arg, "next") && IS_IMMORTAL(ch)) { if (war_info.status != WAR_OFF) { chprintln(ch, "Not while a war is running."); return; } i = is_number(argument) ? atoi(argument) : number_range(30, 100); war_info.timer = i; chprintf(ch, "The next war will start in %d minutes.\n\r", war_info.timer); return; } if (war_info.status != WAR_RUNNING && war_info.status != WAR_WAITING) { chprintf(ch, "There is no war going! The next war will start in %d minutes.", war_info.timer); return; } if (!str_cmp(arg, "end") && IS_IMMORTAL(ch)) { end_war(); announce(ch, INFO_WAR, "$n has ended the war. The next autowar will start in %d minutes.", war_info.timer); announce(ch, INFO_WAR | INFO_PRIVATE, "You have ended the war. The next autowar will start in %d minutes.", war_info.timer); return; } else if (!str_cmp(arg, "info")) { stringf(ch, 0, ALIGN_CENTER, "-", "[ {WWAR INFO{g ]"); chprintlnf(ch, "{g%s{x", stringf(ch, 0, ALIGN_CENTER, "-", "[ {WWAR INFO{g ]")); chprintlnf(ch, "{RStarted by : {W%s", IS_NULLSTR(war_info.who) ? "Unknown" : war_info.who); chprintlnf(ch, "{RFighting : {W%d player%s.", war_info.inwar, war_info.inwar == 1 ? "" : "s"); chprintlnf(ch, "{RLevels : {W%d - %d{x", war_info.min_level, war_info.max_level); chprintlnf(ch, "{RStatus : {W%s for %d minutes.{x", war_info.status == WAR_WAITING ? "Waiting" : "Running", war_info.timer); chprintlnf(ch, "{RType : {W%s war.{x", wartype_name(war_info.wartype, FALSE)); chprintlnf(ch, "{g%s{x", draw_line(ch, NULL, 0)); return; } else if (!str_cmp(arg, "status")) { WAR_DATA *wl; bool found = FALSE; chprintlnf(ch, "{g%s{x", stringf(ch, 0, ALIGN_CENTER, "-", "[ {WWAR COMBATENTS{g ]")); for (wl = war_info.first; wl != NULL; wl = wl->next) { if (!IS_SET(wl->flags, WAR_DECOY) && wl->ch) { if (!IS_SET(wl->flags, WAR_KILLED)) chprintlnf(ch, "{W%-25s : [{R%ld%% hit{W] [{M%ld%% mana{W] [Pos: {G%s{W]{x", warrior_status(wl->ch), wl->ch->hit * 100 / wl->ch->max_hit, wl->ch->mana * 100 / wl->ch->max_mana, position_flags[wl->ch->position].name); else chprintlnf(ch, "{W%-25s [{RKILLED{W]{x", warrior_status(wl->ch)); found = TRUE; } } if (!found) chprintln(ch, "No one in the war yet."); chprintf(ch, "{g%s{x\n\r", draw_line(ch, NULL, 0)); return; } else if (!str_cmp(arg, "decoy")) { WAR_DATA *wl; CHAR_DATA *dc; char buf[MSL]; int count = 0; if (war_info.status != WAR_RUNNING) { chprintln(ch, "Wait untill the war starts."); return; } if (!IS_IN_WAR(ch)) { chprintln(ch, "You aren't in the war."); return; } for (wl = war_info.first; wl; wl = wl->next) { if (!IS_SET(wl->flags, WAR_DECOY)) continue; if (!wl->ch || wl->ch == ch) continue; if (str_cmp(wl->ch->name, ch->name)) continue; count++; } if (count >= 5) { chprintln(ch, "I'm sorry you are only allowed to deploy 5 decoys."); return; } if ((dc = create_mobile(get_mob_index(MOB_VNUM_DUMMY))) == NULL) { chprintln(ch, "Opps, seems there was a problem creating a decoy!"); return; } replace_string(dc->name, ch->name); sprintf(buf, "%s's Decoy", ch->name); replace_string(dc->short_descr, buf); sprintf(buf, "%s%s is here.\n\r", ch->name, ch->pcdata->title); replace_string(dc->long_descr, buf); replace_string(dc->description, ch->description); dc->affected_by = ch->affected_by; dc->level = ch->level; dc->sex = ch->sex; dc->race = ch->race; memcpy(dc->Class, ch->Class, MAX_MCLASS); dc->deity = ch->deity; dc->hit = ch->hit; dc->max_hit = ch->max_hit; dc->clan = ch->clan; char_to_room(dc, ch->in_room); new_warlist(dc); chprintln(ch, "A decoy of yourself suddenly appears in the room."); return; } else if (!str_cmp(arg, "join")) { if (ch->fighting != NULL) { chprintln(ch, "You're a little busy right now."); return; } if (war_info.status == WAR_RUNNING) { chprintln(ch, "The war has already started, your too late."); return; } if (ch->level < war_info.min_level || ch->level > war_info.max_level) { chprintln(ch, "Sorry, you can't join this war."); return; } if (ch->war != NULL) { chprintln(ch, "You are already in the war."); return; } if (IS_QUESTOR(ch) || ON_GQUEST(ch)) { chprintln(ch, "What? And leave your quest?"); return; } if (IS_SET(ch->in_room->room_flags, ROOM_NO_RECALL)) { chprintln(ch, "Something prevents you from leaving."); return; } if (war_info.wartype == WAR_CLAN && !is_clan(ch)) { chprintln(ch, "You aren't in a clan, you can't join this war."); return; } if ((location = get_room_index(ROOM_VNUM_WAITROOM)) == NULL) { chprintln(ch, "Arena is not yet completed, sorry."); return; } else { act("$n goes to get $s ass whipped in war!", ch, NULL, NULL, TO_ROOM); char_from_room(ch); char_to_room(ch, location); new_warlist(ch); war_info.inwar++; announce(NULL, INFO_WAR, "%s joins the war!", warrior_status(ch)); act("$n arrives to get $s ass whipped!", ch, NULL, NULL, TO_ROOM); do_function(ch, &do_look, "auto"); } return; } do_war(ch, ""); return; } bool abort_war(void) { WAR_DATA *cwl, *vwl; for (cwl = war_info.first; cwl != NULL; cwl = cwl->next) { if (IS_SET(cwl->flags, WAR_KILLED | WAR_DECOY)) continue; for (vwl = war_info.first; vwl != NULL; vwl = vwl->next) { if (IS_SET(vwl->flags, WAR_KILLED | WAR_DECOY)) continue; if (!check_wartype_data(cwl->ch, vwl->ch)) return FALSE; } } return TRUE; } void note_war(CHAR_DATA * ch) { BUFFER *output; char sender[MIL], subject[MIL]; WAR_DATA *wl; if (war_info.status != WAR_RUNNING) return; output = new_buf(); bprintln(output, "{WWAR INFO{g\n\r--------{x"); bprintlnf(output, "{RStarted by : {W%s", IS_NULLSTR(war_info.who) ? "AutoWar" : war_info.who); bprintlnf(output, "{RLevels : {W%d - %d{x", war_info.min_level, war_info.max_level); bprintlnf(output, "{RType : {W%s war.{x", wartype_name(war_info.wartype, FALSE)); bprintln(output, "{WWAR COMBATENTS{g\n\r--------------{x"); for (wl = war_info.first; wl != NULL; wl = wl->next) { if (IS_SET(wl->flags, WAR_DECOY) || !wl->ch) continue; bprintlnf(output, "{W%s{x\n\r", warrior_status(wl->ch)); } bprintln(output, "{g--------------{x"); switch (war_info.wartype) { case WAR_RACE: case WAR_CLASS: bprintlnf(output, "{WThe {R%s's{W won this war.{x", wartype_info(ch)); break; default: bprintlnf(output, "{R%s{W won this war.{x", wartype_info(ch)); break; } sprintf(subject, "War Info %s\n\r", str_time(current_time, -1, NULL)); sprintf(sender, "%s", IS_NULLSTR(war_info.who) ? "AutoWar" : war_info.who); make_note("General", sender, "All", subject, 15, buf_string(output)); free_buf(output); return; } void war_update(void) { if (war_info.status == WAR_OFF && war_info.timer > 0) { if (--war_info.timer <= 0) auto_war(); } else if (war_info.status == WAR_WAITING) { vnum_t randm = 0; war_info.timer--; if (war_info.timer > 0) { announce(NULL, INFO_WAR, "%d minute%s left to join the war. (Levels %d - %d, %s War)", war_info.timer, war_info.timer == 1 ? "" : "s", war_info.min_level, war_info.max_level, wartype_name(war_info.wartype, FALSE)); } else { if (war_info.inwar < 2) { end_war(); announce(NULL, INFO_WAR, "Not enough people for war."); } else if (abort_war()) { announce(NULL, INFO_WAR, "Not enough %s for war.", wartype_name(war_info.wartype, TRUE)); end_war(); } else { WAR_DATA *wl; announce(NULL, INFO_WAR, "The battle begins! %d players are fighting!", war_info.inwar); war_info.timer = number_range(3 * war_info.inwar, 5 * war_info.inwar); war_info.status = WAR_RUNNING; for (wl = war_info.first; wl != NULL; wl = wl->next) { randm = number_range(17601, 17636); char_from_room(wl->ch); char_to_room(wl->ch, get_room_index(randm)); do_function(wl->ch, &do_look, "auto"); } } } } else if (war_info.status == WAR_RUNNING) { if (war_info.inwar == 0) { end_war(); announce(NULL, INFO_WAR, "No one left in the war"); return; } switch (war_info.timer) { case 0: end_war(); announce(NULL, INFO_WAR, "Time has run out!"); return; case 1: case 2: case 3: case 4: case 5: case 10: case 15: announce(NULL, INFO_WAR, "%d minute%s remaining in the war.", war_info.timer, war_info.timer > 1 ? "s" : ""); default: war_info.timer--; break; } return; } } void check_war(CHAR_DATA * ch, CHAR_DATA * victim) { WAR_DATA *wl, *wl_next; if (war_info.status == WAR_OFF) return; if (!IS_IN_WAR(ch) || !IS_IN_WAR(victim)) return; war_info.inwar--; stop_fighting(victim, TRUE); stop_fighting(ch, TRUE); if (IS_NPC(victim)) { act("$n disappears suddenly.", victim, NULL, NULL, TO_ROOM); free_warlist(victim->war); return; } char_from_room(victim); char_to_room(victim, get_room_index(ROOM_VNUM_TEMPLE)); for (wl = war_info.first; wl; wl = wl_next) { wl_next = wl->next; if (!IS_SET(wl->flags, WAR_DECOY)) continue; if (!str_cmp(wl->ch->name, victim->name)) { act("$n dissapears suddenly.", wl->ch, NULL, NULL, TO_ROOM); free_warlist(wl); } } victim->hit = victim->war->hit; victim->mana = victim->war->mana; victim->move = victim->war->move; SET_BIT(victim->war->flags, WAR_KILLED); update_pos(victim); do_function(victim, &do_look, "auto"); chprintln(ch, ""); announce(NULL, INFO_WAR, "%s was killed in combat by %s!{x", victim->name, IS_NPC(ch) ? ch->short_descr : ch->name); if (abort_war()) { int reward; int qreward; switch (war_info.wartype) { case WAR_RACE: case WAR_CLASS: announce(NULL, INFO_WAR, "The %s's have won the war!", wartype_info(ch)); break; default: announce(NULL, INFO_WAR, "%s has won the war!", wartype_info(ch)); break; } note_war(ch); reward = number_range(500, 1500); qreward = number_range(50, 150); for (wl = war_info.first; wl != NULL; wl = wl->next) { if (IS_SET(wl->flags, WAR_DECOY)) continue; if (check_wartype_data(wl->ch, ch)) { wl->ch->gold += reward; wl->ch->pcdata->questpoints += qreward; chprintf(wl->ch, "You recieve %d gold and %d questpoints from the war tribunal!", reward, qreward); } } end_war(); return; } return; } bool is_safe_war(CHAR_DATA * ch, CHAR_DATA * wch) { if (war_info.status == WAR_OFF) return FALSE; if (!IS_IN_WAR(ch) || !IS_IN_WAR(wch)) return FALSE; return check_wartype_data(ch, wch); } void war_talk(CHAR_DATA * ch, const char *argument) { DESCRIPTOR_DATA *d; if (IS_NULLSTR(argument)) { chprintln(ch, "Wartalk about what?\n\rUse 'info war' to toggle this channel."); return; } chprintf(ch, "{Y({RWarTalk{Y) {gYou drum: %s{x\n\r", argument); for (d = descriptor_first; d != NULL; d = d->next) { CHAR_DATA *victim; if (d->connected == CON_PLAYING && (victim = CH(d)) != ch && !IS_SET(victim->info_settings, INFO_WAR) && !IS_SET(victim->comm, COMM_QUIET) && !is_ignoring(ch, victim->name, IGNORE_CHANNELS)) { chprintf(victim, "{Y({RWarTalk{Y) {g%s drums: %s{x", PERS(ch, victim), argument); } } return; } void extract_war(CHAR_DATA * ch) { if (war_info.status != WAR_OFF && ch->war != NULL) { war_info.inwar--; if (war_info.status == WAR_RUNNING) { if (war_info.inwar == 0 || war_info.inwar == 1) { announce(ch, INFO_WAR, "$n has left. War over."); end_war(); } if (abort_war()) { announce(ch, INFO_WAR, "$n has left. War over."); end_war(); } else { announce(ch, INFO_WAR, "$n has left. %d players in the war.", war_info.inwar); } } char_from_room(ch); char_to_room(ch, get_room_index(ROOM_VNUM_TEMPLE)); free_warlist(ch->war); } }