/**************************************************************************
* 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-2002 by Ryan Jennings *
* http://1stmud.dlmud.com/ <r-jenn@shaw.ca> *
***************************************************************************/
#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include "merc.h"
#include "tables.h"
#include "recycle.h"
#include "interp.h"
void make_note(const char *board_name, const char *sender, const char *to,
const char *subject, const int expire_days, const char *text);
#define IS_SET_WAR(ch) (!IS_NPC(ch) && (IS_SET((ch)->act, PLR_WAR) || (ch)->pcdata->still_in_war == TRUE))
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}
};
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";
}
#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 *wch, *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 (arg1[0] == '\0' || arg2[0] == '\0' || arg3[0] == '\0')
{
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.iswar != WAR_OFF)
{
chprintln(ch, "There is already a war going!");
return FALSE;
}
if (!IS_IMMORTAL(ch))
{
char buf[MSL];
if (ch->pcdata->trivia < WAR_COST)
{
sprintf(buf,
"It costs %d Trivia Points to start a %s war.",
WAR_COST, wartype_name(type, FALSE));
do_mob_tell(ch, warmaster, buf);
return FALSE;
}
else
{
sprintf(buf,
"Thank you %s, %s war started, you are %d trivia points lighter.",
ch->name, wartype_name(type, FALSE), WAR_COST);
do_mob_tell(ch, warmaster, buf);
}
}
war_info.iswar = 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);
if (ch)
chprintf(ch,
"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;
war_info.next = 0;
for (wch = player_first; wch != NULL; wch = wch->next_player)
{
if (IS_SET(wch->act, PLR_WAR))
REMOVE_BIT(wch->act, PLR_WAR);
if (wch->pcdata->still_in_war)
wch->pcdata->still_in_war = FALSE;
}
return TRUE;
}
void auto_war(void)
{
CHAR_DATA *wch, *wch_last, *warmaster;
int maxlvl = 0, minlvl = MAX_LEVEL, middle = LEVEL_HERO / 2;
int clan = 0, count = 0, lbonus = 0, half = 0;
int heros = 0;
if (war_info.iswar != 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 == LEVEL_HERO)
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(LEVEL_HERO, 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 = LEVEL_HERO;
else
maxlvl = UMIN(LEVEL_HERO, number_range((middle * 3) / 2, maxlvl));
for (warmaster = char_first; warmaster != NULL; warmaster = warmaster->next)
if (warmaster->pIndexData
&& warmaster->pIndexData->vnum == MOB_VNUM_WARMASTER)
break;
war_info.iswar = WAR_WAITING;
replace_string(war_info.who,
(!warmaster ? "AutoWar (tm)" : 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" : "");
if (warmaster)
chprintf(warmaster,
"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;
war_info.next = 0;
for (wch = player_first; wch != NULL; wch = wch->next_player)
{
if (IS_SET(wch->act, PLR_WAR))
REMOVE_BIT(wch->act, PLR_WAR);
if (wch->pcdata->still_in_war)
wch->pcdata->still_in_war = FALSE;
}
}
void end_war(void)
{
CHAR_DATA *wch;
replace_string(war_info.who, "");
war_info.wartype = WAR_NONE;
war_info.min_level = 0;
war_info.max_level = 0;
war_info.iswar = WAR_OFF;
war_info.inwar = 0;
war_info.timer = 0;
war_info.next = number_range(100, 200);
for (wch = player_first; wch != NULL; wch = wch->next_player)
{
if (IS_SET_WAR(wch))
{
stop_fighting(wch, TRUE);
REMOVE_BIT(wch->act, PLR_WAR);
wch->pcdata->still_in_war = FALSE;
if (IS_SET(wch->in_room->room_flags, ROOM_ARENA)
|| wch->in_room->vnum == ROOM_VNUM_WAITROOM)
{
char_from_room(wch);
char_to_room(wch, get_room_index(ROOM_VNUM_TEMPLE));
}
wch->hit = wch->max_hit;
wch->mana = wch->max_mana;
wch->move = wch->max_move;
update_pos(wch);
do_function(wch, &do_look, "auto");
}
}
}
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[ch->Class[0]].name;
case WAR_GENOCIDE:
return ch->name;
case WAR_CLAN:
return ch->clan->who_name;
case WAR_DEITY:
return ch->deity->name;
}
}
void *wartype_data(CHAR_DATA * ch)
{
switch (war_info.wartype)
{
default:
return NULL;
case WAR_RACE:
return ch->race;
case WAR_CLASS:
return &ch->Class[0];
case WAR_GENOCIDE:
return &ch->id;
case WAR_CLAN:
return ch->clan;
case WAR_DEITY:
return ch->deity;
}
}
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 (arg[0] == '\0')
{
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");
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.iswar == WAR_RUNNING)
{
chprintln(ch, "Not while a war is running.");
return;
}
i = is_number(argument) ? atoi(argument) : number_range(30, 100);
war_info.next = i;
chprintf(ch, "The next war will start in %d minutes.\n\r",
war_info.next);
return;
}
if (war_info.iswar != WAR_RUNNING && war_info.iswar != WAR_WAITING)
{
chprintf(ch,
"There is no war going! The next war will start in %d minutes.",
war_info.next);
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.next);
announce(ch, INFO_WAR | INFO_PRIVATE,
"You have ended the war. The next autowar will start in %d minutes.",
war_info.next);
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.iswar == 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"))
{
CHAR_DATA *wch;
bool found = FALSE;
chprintlnf(ch, "{g%s{x",
stringf(ch, 0, ALIGN_CENTER, "-", "[ {WWAR COMBATENTS{g ]"));
for (wch = player_first; wch != NULL; wch = wch->next_player)
{
if (IS_SET(wch->act, PLR_WAR))
{
chprintf(ch,
"{W%s : [{R%ld%% hit{W] [{M%ld%% mana{W] [Pos: {G%s{W]{x",
warrior_status(wch),
wch->hit * 100 / wch->max_hit,
wch->mana * 100 / wch->max_mana,
position_flags[wch->position].name);
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, "join"))
{
if (ch->fighting != NULL)
{
chprintln(ch, "You're a little busy right now.");
return;
}
if (war_info.iswar == 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 (IS_SET_WAR(ch))
{
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);
ch->pcdata->still_in_war = TRUE;
SET_BIT(ch->act, PLR_WAR);
announce(NULL, INFO_WAR, "%s joins the war!", warrior_status(ch));
act("$n arrives to get $s ass whipped!", ch, NULL, NULL, TO_ROOM);
war_info.inwar++;
do_function(ch, &do_look, "auto");
}
return;
}
do_war(ch, "");
return;
}
bool abort_war(void)
{
CHAR_DATA *ch;
CHAR_DATA *vict;
for (ch = player_first; ch != NULL; ch = ch->next_player)
{
if (IS_SET(ch->act, PLR_WAR))
{
for (vict = player_first; vict != NULL; vict = vict->next_player)
{
if (IS_SET(vict->act, PLR_WAR))
{
if (wartype_data(ch) != wartype_data(vict))
return FALSE;
}
}
}
}
return TRUE;
}
void note_war(CHAR_DATA * ch)
{
BUFFER *output;
char sender[MIL], subject[MIL], buf[MSL];
CHAR_DATA *wch;
if (war_info.iswar != WAR_RUNNING)
return;
output = new_buf();
add_buf(output, "{WWAR INFO{g\n\r--------{x\n\r");
sprintf(buf, "{RStarted by : {W%s\n\r",
IS_NULLSTR(war_info.who) ? "AutoWar (Tm)" : war_info.who);
add_buf(output, buf);
sprintf(buf, "{RLevels : {W%d - %d{x\n\r", war_info.min_level,
war_info.max_level);
add_buf(output, buf);
sprintf(buf, "{RType : {W%s war.{x\n\r",
wartype_name(war_info.wartype, FALSE));
add_buf(output, buf);
add_buf(output, "{WWAR COMBATENTS{g\n\r--------------{x\n\r");
for (wch = player_first; wch != NULL; wch = wch->next_player)
{
if (!IS_SET_WAR(wch))
continue;
sprintf(buf, "{W%s{x\n\r", warrior_status(wch));
add_buf(output, buf);
}
add_buf(output, "{g--------------{x\n\r");
switch (war_info.wartype)
{
case WAR_RACE:
case WAR_CLASS:
sprintf(buf, "{WThe {R%s's{W won this war.{x\n\r", wartype_info(ch));
add_buf(output, buf);
break;
default:
sprintf(buf, "{R%s{W won this war.{x\n\r", wartype_info(ch));
add_buf(output, buf);
break;
}
sprintf(subject, "War Info %s\n\r", str_time(current_time, -1, NULL));
sprintf(sender, "%s",
IS_NULLSTR(war_info.who) ? "AutoWar (Tm)" : war_info.who);
make_note("General", sender, "All", subject, 15, buf_string(output));
free_buf(output);
return;
}
void war_update(void)
{
if (war_info.iswar == WAR_OFF && war_info.next > 0)
{
if (--war_info.next <= 0)
auto_war();
}
else if (war_info.iswar == 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
{
CHAR_DATA *wch;
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.iswar = WAR_RUNNING;
for (wch = player_first; wch != NULL; wch = wch->next_player)
{
if (IS_SET(wch->act, PLR_WAR))
{
randm = number_range(17601, 17636);
char_from_room(wch);
char_to_room(wch, get_room_index(randm));
do_function(wch, &do_look, "auto");
}
}
}
}
}
else if (war_info.iswar == 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)
{
CHAR_DATA *wch;
int reward;
int qreward;
if (IS_NPC(ch) || IS_NPC(victim))
return;
reward = number_range(500, 1500);
qreward = number_range(50, 150);
REMOVE_BIT(victim->act, PLR_WAR);
victim->pcdata->still_in_war = TRUE;
war_info.inwar--;
stop_fighting(victim, TRUE);
stop_fighting(ch, TRUE);
char_from_room(victim);
char_to_room(victim, get_room_index(ROOM_VNUM_WAITROOM));
if (victim->hit < 1)
victim->hit = 1;
if (victim->mana < 1)
victim->mana = 1;
if (victim->move < 1)
victim->move = 1;
update_pos(victim);
do_function(victim, &do_look, "auto");
chprintln(victim,
"Please wait here untill the war ends and you'll be transfered and healed.");
chprintln(ch, "");
chprintln(victim, "");
announce(NULL, INFO_WAR, "%s was killed in combat by %s!{x",
victim->name, ch->name);
if (abort_war())
{
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);
for (wch = player_first; wch != NULL; wch = wch->next_player)
{
if (!IS_SET_WAR(wch))
continue;
if (wartype_data(wch) == wartype_data(ch))
{
wch->gold += reward;
wch->pcdata->questpoints += qreward;
chprintf(wch,
"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.iswar == WAR_OFF)
return FALSE;
if (!IS_IN_WAR(ch) || !IS_IN_WAR(wch))
return FALSE;
if (wartype_data(ch) == wartype_data(wch))
return TRUE;
return FALSE;
}
void war_talk(CHAR_DATA * ch, const char *argument)
{
DESCRIPTOR_DATA *d;
if (argument[0] == '\0')
{
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))
{
chprintf(victim, "{Y({RWarTalk{Y) {g%s drums: %s{x",
PERS(ch, victim), argument);
}
}
return;
}
void extract_war(CHAR_DATA * ch)
{
if (war_info.iswar != WAR_OFF && IS_SET(ch->act, PLR_WAR))
{
REMOVE_BIT(ch->act, PLR_WAR);
war_info.inwar--;
if (war_info.iswar == 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));
}
}