git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@8059 c06c8d41-db1a-0410-9941-cceddc491573
PKXXBHS3LWLPZI2QVRX22MSQ4R2626IXRSNHFFYHXYTLJJQU54LQC
QBAHRGJ2RVSMWKXY2B4FVR5VX75GILH6HSRYGF44PBPNINST2NIAC
QLV7Y2LTDKTVMYFLM7UCNRUXU6PC5535XV6UE27N56AHHIGXEIWAC
2XFWLQH6DARNQJVPSKLICWD6W62GJCQWVQ4444G3S7HXWWYYLRJAC
VTQBKNSYDYZVBBQTF32DEECEEDYX75GX464E7GVFSK22N5JRNM4QC
ZW4PORTK3G7OJDTPXTXQLXTRCEN4ES2RTS22DSLEAPJALDMRWRVQC
I5FRVRMVT5RKXBMGO546MPF4H4ZHPAL5MXNGOU46MKJ3URNEWX7AC
AMNWAYRX7CBFRYF3DNCHWIMVXLLVISWGJKYYCFN4MUZN7M3XP2KQC
CGYTZT5QWIEGYKUOLOK7MFXSLJKLYRZONER5ZCDZO5XYWSLG475QC
J7GPW2YXLT6FGSKJ24FGQ24GTRZ6A2BDYM6CIXV4R6YBEHP6BGPAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
WT66JDIRTLLP37SHTV4GI3V64JFJ4D25LNRLGCHFG6CLEFKJ3QGQC
SIDH2P7NBIG5KEOE27XHD3ZT2NQ2OJZFN6VZXWNWYFFY5YVXSSVQC
XVFTIQ7MSVKQDMQ2HT3IY6FJOZFK4H6OFGTUAID5VGCA5BGVXYPAC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
ZGZVOMRXLVC42FV67RBTLBOZWFYRL4UHL54A365BR76OUIYRWQXAC
JJULXW764V5C2HJKZNWQAEWB6QM5YZADD7ZCE35LYTBFEM6PMYCAC
TGJZXTUIAKCFZQJ54ZQEBGFBVZSJCAX6AWDRSH3TP7UJRLGUM5SAC
AUXVWXWIFSTWFA6VZXN2FMG7FQEKRZVV6MD32VQQ7J2RKCXHAVGAC
PL6I2CMSTHY5ZHWVMIQE5YTM5S5VPKBNZM6QJVHZSSKOJGIJ5W4AC
KLJIFEBICFQ76DNM3MTS2PJ5LTEIOBIW5QZTNW722WHPKIST5UQQC
4Q5OYUKF2SGF7WHMIVYFZVXXDCFUCYY534VLOGKWYRSPYKRXMVDAC
SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC
JM7UAK777RAVDAVLQLEOBRTGNW2B47S5G55XITJXO243IUNZHVYQC
IUZMNOXWL4ZUYPZIUV7ODZKBXOIECG5TDOKU4OIN6ZJEDCB72QQAC
Z6Q7JVMFQ32SC7FRGOB7CE7JS2HEOPAO3B2VLU3YR3UCUDZFIPFQC
NO2HRD7RZS42S55UG4FQ5EFQDY6WYWKGIXHUKYLWF36HHE3VZ7WAC
HFZQADL3R7ITWM3VPW5G3NCB2AHRMAMKYZOI3STW5LWUCTV4FFFQC
EMOBSWJHHB4V6WVMZL7JCF2V3KZN454Z6NS346OKFPMBNO24EJDQC
QDWDUURSNLMT6AXNNJ3DEQCWAKCAIHV6MP5F7QGIBGXOG2BI2NPQC
5JS3QSE3EIXSBVI4DATH2EIFD7QN3POAFEUM7MK4NRMPH5JOPAAQC
KAOE5HB3THUKVGFZRO5EZESHEB3Q34WUO5DFMLWIKOBF47LZTIYAC
TMN6MGCYNMQL3GG5P3JKKT4ROF2RB26H4AE6LHNEE76MBRVCDZMQC
6GSGCC5JQJ5NOKX36UHRNOCXNHDBS2A2TDMAR34UBOGWE2DORXIQC
ID373JATLMWAY526Q6Q5FXHRNFWMEOFXPHGPAUUY5OAMPFDN5SJAC
OEAIMYCV7XMTH363UVSHMNHHHDZYEGOP3GECLB3SXGAQMOAVJRCQC
DDU4A3JGN5IUIPP5IASOODKPR2WBHSDSV4FITZ6HNXNSXXQACWAQC
FLAGBNUNSIQNFDN53CDWABJRTTFWDL4PG34AI474ZKPXDEPYHOAQC
47NSOFQMBZCDIBHEAZSENFUGDSQCX3GJHFBUZ65ARDKCYIZ435LAC
GPEJOT73KMACP33IPAKFR5ROGHCOIP22VXZMQNYTGLEA2OSZUM2AC
GRH4XPIYHDOXXF3R3QPMZTFHGLO2OJAZS4FLNBBXG3DHTQQM7RDQC
3UKFCWWS5BLFQWZRB5FUA46CE2XGX5VRCEWC3K3XH5RCGQK64N2AC
ZBFNQZV6XCH4NUTHJU4K7RN4KLUMWNCWWO6UP7TIRASCWD5J5OMQC
NKONHW4JNY6HP2M63MNPM3H64ZWSUNUT5FX2STW4KTS4AMXJXXVQC
7YSKYUNV34XIWRTJUHJV4QMQRTXXYDIXM5AZSPSDPAYDW4B4PU6QC
APGCKU4AFOV7Z7XIEO5A27H4IFUGDU227I3Z7OIRROYSLOFFBJ5AC
EH4VJW3I5Y4V6DT3YMLNDA3NW2DEAV4LRE4T5IEXAVB4WB3JJMGAC
MQ62OAMLGJVRW2QIL4PAZRAU6PC52ZVGY2FCOBIY6IWGQIHMU5CAC
C55G5JGGSVWMU7XVEJL6YZZLDXQZGRN7JQOAALS6WIKFPX3L2U6QC
WLX2RQMMOMP2PYPAGJRM4VFD2WTLJTOAZZPPY3MV76FU2EGEJ54QC
Z3RI4XAN7J2GUABAQ5G6YIOQYMBOAEQFFGRBWHMUEB2A2QYXO5MQC
JN4GPMQCXOY5ICTLPLWP6DXBFULN4GMAEK7T4GXTZVIJAUUKBBYAC
P5TRGRH7XMQSPCZKM5IEEO34TY6WMLGHHX7BU6Y453JFRXLUR2VQC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
FSD7GIK3YLZXWLEH37BU6KV3IUCFGXPQL6IZ7H65YWNRBEKDBX5AC
UZ6N6HOUPGVSPC5NQROEEDWMEGJA5XUWUY2AKH5QG65AZ25PVXDAC
3C2VE43SHCSBY4LTRTFYFLIPRWFUN6DXU6D34QVWDQTSNRBUFG7AC
SQDS2YBPOYDDDCW3GGARBZ2HQIUHCQKL7SSHKFQWDENOL5YNNVNQC
TLA5UN6LZPXGKERI27EFY4HKIIU3VU5Y7ZU54WXL6ANBUV2VOTMQC
W45PMU4HNPSAMMEBJ4XH4MTHLPVIASZT4FXTBPID5LFXKIMNUBKAC
B7MSPF6X2RLGWN4M6ZZF3WSOPKGYPTTD7LIJVST7DXN27DG6JHNAC
NVSFIV2ZKP44XHCSCXG6OZVGL67OIFINC34J2EMKTA4KULCERUEAC
2YSMM7QMFZOPD5NXAD2OAMDJEY5LOZO4NCYBC7UCQVANKINJRNBAC
SCWXQW5H65OXUP2MEJ2MEEAVPSRJDT3RQGKYCMKVTORS2334PQSQC
ZJU5Z2WDMI7HN4XJ3NVTVRHIZO2CGFUQ2FSKIRJVTQG47XHNCZFQC
BW6QCGQDWZ6G2UGDD4EXI5VVDZHM5S53MJIC5CKG3Q3VQ4IDQ2VQC
JDM27QE4HR52AYFSQE763BFF57ANOTF5MXKMO377PP5EXMN7SAOAC
R2DQBWKIW7YUJB5SOQ7J274JIYRVX4H3ISFRPAL5RG2RVVP4G2KAC
2TTHWHQ3ZDD3DLB3KRULTBMS3ZREJG472IBVZXIGTP7MBZWAU52QC
ILN2K6ASDZSMEHOPJ22IZLZJUO6DDGZTKAKXM3YXG6JZZHJNLX4AC
WMHFDQKUDCUGM3R245LLVZ5NNEZSCXFDSTNMVS2O5EFUHHO7HU3AC
7XJLSTDZDOSHW6JF3Y4545YGGK5BC2SOXJVQXXVOFR3I7PXYUJZQC
MSQI3TH6T62JAXQGLL52QZCWAMC372TGB6ZNNRDGUGMJKBNNV2VAC
PJ7HBIWAV3H23LXGZAAD2QYJ7HMOFOIR5ZJ4U2UTHI766LOTRRWQC
7UQJTYJTHTDW55ZUKG4TINZTNALGPK5CB7UB7PJ2Y2SKQ5XOYP5AC
7G2RWMLC5YBT3W7DNXDGEA4SMTI524RJIH3VO7MOQYGBMQHML2MAC
BNP25NWD5OXPQEPLM3YJRJCRE24DH55RZKFCZPUX5NLWGOSBIYGAC
X7MFMKQTNZ2IWBFVGS6WQV7NRNKJ3DWQAW2X7IQMFQQXW24AHPZQC
UBQTNLYGD3SNWMUNGWUPX7EXEGQXOXCFCPWIVWBFE7ID7DJLPFWAC
UL7XFKMUX3WIU4O2LZANK4ECJ654UZPDBFGNXUEYZYOLKBYBCG6AC
5UVDIVD4NSXA52U4QMQIVST3GSZJ2A2YZK3RUEXKPM43YVQ7LI5AC
O6ZMFKDI3XO2SWPNEYHIPYFDWJR4TVDP5BAATK6LVCVETQID6E7AC
XCPNY2Q3F3ELK3L2FRCXHVLANQ7JLB47VBIFIUME5I2PCXNRA3ZAC
43ZTEB57FU7KE5EVMYWZONNVJBZCGF3JEAJZIY25LC4LGE65PG5QC
475LL4U4ND6PTNV4XKC7WQAOJC7RF2VCCVX3DRILP2PKIBFYWE6QC
RYT42Z6CED4KV5CCJ45CHZ3DQGLFMDCVH6CSQZNXOILULDG4MXVQC
67WH6I2XIMRRL26UM4FJJJZEMJIDPW5Q77FFNZGKWGTWS7GTCJ6QC
5XNQ3SSNBFXFNWA6DPM74W6FH65NX665P3DMH6YCWVFOPZTJSYCQC
2TECJQA3PK7OYSSTOWZSQFWMTATJRHHA6JV3IGRHFGS3R7U27RZAC
YF2GZWXNV6NVFFEBEOYS67JQJQK2IUS5BZMGJW3XQPYIJYHQJCEQC
CPTUVTBSOJMAUKMS5RFOAEZEVJGPFHMJA2DJWMDTYN7PFNZUGPWQC
XKQ2XYVSHYRTEKIYXFLXCPULEEO6IQUSKQHX32UZGNMAMQN2CTMQC
5BJPWUPLJFS34FUTFJVKA4A52YMIGV6EWDXLNSDCWBJWBGVSQFGQC
// What would be visible, if all of the translucent walls were
// made opaque.
losight( env.no_trans_show, grd, you.pos(), true );
// What would be visible, if all of the translucent walls were
// made opaque.
losight( env.no_trans_show, grd, you.pos(), true );
}
int nearest = -1;
int best_distance = -1;
for (int i = 0; i < MAX_MONSTERS; ++i)
{
if (mind == i)
continue;
const monsters *other(&menv[i]);
if (!other->alive() || mons_aligned(mind, i))
continue;
const int distance = grid_distance(mons->pos(), other->pos());
if (best_distance == -1 || distance < best_distance)
{
best_distance = distance;
nearest = i;
}
}
if (nearest != -1)
{
mons->foe = nearest;
mons->target = menv[nearest].pos();
}
else
{
mons->foe = MHITNOT;
mons->target = mons->pos();
}
}
: mid(id), place(), monbase(base), number(num), genweight(gw),
mlevel(ml), fix_mons(_fixmons), generate_awake(awaken),
patrolling(false), band(false), colour(BLACK), items()
: mid(id), place(), monbase(base), attitude(ATT_HOSTILE), number(num),
quantity(1), genweight(gw), mlevel(ml), fix_mons(_fixmons),
generate_awake(awaken), patrolling(false), band(false),
colour(BLACK), items()
if (!mon_str.empty() && isdigit(mon_str[0]))
{
// Look for space after initial digits.
std::string::size_type pos =
mon_str.find_first_not_of("0123456789");
if (pos != std::string::npos && mon_str[pos] == ' ')
{
const std::string mcount = mon_str.substr(0, pos);
const int count = atoi(mcount.c_str());
if (count >= 1 && count <= 99)
mspec.quantity = count;
mon_str = mon_str.substr(pos);
}
}
bool dgn_place_monster(mons_spec &mspec,
int monster_level, const coord_def& where,
bool force_pos = false, bool generate_awake = false,
bool patrolling = false);
int dgn_place_monster(mons_spec &mspec,
int monster_level, const coord_def& where,
bool force_pos = false, bool generate_awake = false,
bool patrolling = false);
bool dgn_place_monster(mons_spec &mspec,
int monster_level, const coord_def& where,
bool force_pos, bool generate_awake, bool patrolling)
int dgn_place_monster(mons_spec &mspec,
int monster_level, const coord_def& where,
bool force_pos, bool generate_awake, bool patrolling)
NAME: arena_level
TAGS: arena_level no_mons_gen
MARKER: A = feat: stone_stairs_up_i
MARKER: B = feat: stone_stairs_down_i
MARKER: O = feat: escape_hatch_up
SUBST: A = ., B = ., O = .
ORIENT: encompass
MAP
XXXXXXXXXXXXXXXXX
X...............X
X.......B.......X
X...............X
X...............X
X...............X
X...............X
X...............X
X.......O.......X
X...............X
X...............X
X...............X
X...............X
X...............X
X.......A.......X
X...............X
XXXXXXXXXXXXXXXXX
ENDMAP
#ifndef ARENA_H
#define ARENA_H
#include "AppHdr.h"
void run_arena();
#endif
#include "AppHdr.h"
#include "externs.h"
#include "arena.h"
#include "chardump.h"
#include "cio.h"
#include "dungeon.h"
#include "initfile.h"
#include "libutil.h"
#include "maps.h"
#include "message.h"
#include "mon-util.h"
#include "monstuff.h"
#include "monplace.h"
#include "output.h"
#include "skills2.h"
#include "spl-util.h"
#include "state.h"
#include "version.h"
#include "view.h"
extern void world_reacts();
namespace arena
{
// A faction is just a big list of monsters. Monsters will be dropped
// around the appropriate marker.
struct faction
{
std::string desc;
mons_list members;
bool friendly;
faction(bool fr) : members(), friendly(fr) { }
void place_at(const coord_def &pos);
void clear()
{
members.clear();
}
};
int total_trials = 0;
int trials_done = 0;
int team_a_wins = 0;
bool allow_summons = true;
faction faction_a(true);
faction faction_b(false);
void adjust_monsters()
{
if (!allow_summons)
{
for (int m = 0; m < MAX_MONSTERS; ++m)
{
monsters *mons(&menv[m]);
if (!mons->alive())
continue;
monster_spells &spells(mons->spells);
for (int i = 0; i < NUM_MONSTER_SPELL_SLOTS; ++i)
{
spell_type sp = spells[i];
if (spell_typematch(sp, SPTYP_SUMMONING))
spells[i] = SPELL_NO_SPELL;
}
}
}
}
void faction::place_at(const coord_def &pos)
{
ASSERT(in_bounds(pos));
for (int i = 0, size = members.size(); i < size; ++i)
{
mons_spec spec = members.get_monster(i);
if (friendly)
spec.attitude = ATT_FRIENDLY;
for (int q = 0; q < spec.quantity; ++q)
{
const coord_def place =
find_newmons_square_contiguous(MONS_GIANT_BAT, pos, 6);
if (!in_bounds(place))
break;
const int imon = dgn_place_monster(spec, you.your_level,
place, false, true, false);
if (imon == -1)
end(1, false, "Failed to create monster at (%d,%d)",
place.x, place.y);
}
}
}
void center_print(unsigned sz, std::string text, int number = -1)
{
if (number >= 0)
text = make_stringf("(%d) %s", number, text.c_str());
if (text.length() > sz)
text = text.substr(0, sz);
int padding = (sz - text.length()) / 2 + text.length();
cprintf("%*s", padding, text.c_str());
}
void setup_level()
{
dgn_reset_level();
for (int x = 0; x < GXM; ++x)
for (int y = 0; y < GYM; ++y)
grd[x][y] = DNGN_ROCK_WALL;
unwind_bool gen(Generating_Level, true);
typedef unwind_var< std::set<std::string> > unwind_stringset;
const unwind_stringset mtags(you.uniq_map_tags);
const unwind_stringset mnames(you.uniq_map_names);
const map_def *map = random_map_for_tag("arena_level", false);
ASSERT(map);
dgn_place_map(map, true, true);
if (!env.rock_colour)
env.rock_colour = CYAN;
if (!env.floor_colour)
env.floor_colour = LIGHTGREY;
}
std::string find_monster_spec()
{
if (!SysEnv.arena_teams.empty())
return (SysEnv.arena_teams);
throw std::string("No monsters specified for the arena.");
}
void parse_faction(faction &fact, std::string spec)
throw (std::string)
{
fact.clear();
fact.desc = spec;
std::vector<std::string> monsters = split_string(",", spec);
for (int i = 0, size = monsters.size(); i < size; ++i)
{
const std::string err = fact.members.add_mons(monsters[i], false);
if (!err.empty())
throw err;
}
}
void parse_monster_spec()
throw (std::string)
{
std::string spec = find_monster_spec();
allow_summons = !strip_tag(spec, "no_summons");
const int ntrials = strip_number_tag(spec, "t:");
if (ntrials != TAG_UNFOUND && ntrials >= 1 && ntrials <= 99
&& !total_trials)
total_trials = ntrials;
std::vector<std::string> factions = split_string(" v ", spec);
if (factions.size() == 1)
factions = split_string(" vs ", spec);
if (factions.size() != 2)
throw make_stringf("Expected arena monster spec \"xxx v yyy\", "
"but got \"%s\"", spec.c_str());
try
{
parse_faction(faction_a, factions[0]);
parse_faction(faction_b, factions[1]);
}
catch (const std::string &err)
{
throw make_stringf("Bad monster spec \"%s\": %s",
spec.c_str(),
err.c_str());
}
}
void setup_monsters()
throw (std::string)
{
unwind_var< FixedVector<bool, NUM_MONSTERS> >
uniq(you.unique_creatures);
parse_monster_spec();
coord_def place_a(dgn_find_feature_marker(DNGN_STONE_STAIRS_UP_I));
coord_def place_b(dgn_find_feature_marker(DNGN_STONE_STAIRS_DOWN_I));
faction_a.place_at(place_a);
faction_b.place_at(place_b);
adjust_monsters();
}
void show_fight_banner(bool after_fight = false)
{
int line = 1;
cgotoxy(1, line++, GOTO_STAT);
textcolor(WHITE);
center_print(crawl_view.hudsz.x,
"Crawl " VER_NUM VER_QUAL " " VERSION_DETAIL);
line++;
cgotoxy(1, line++, GOTO_STAT);
textcolor(YELLOW);
center_print(crawl_view.hudsz.x, faction_a.desc,
total_trials ? team_a_wins : -1);
cgotoxy(1, line++, GOTO_STAT);
textcolor(LIGHTGREY);
center_print(crawl_view.hudsz.x, "vs");
cgotoxy(1, line++, GOTO_STAT);
textcolor(YELLOW);
center_print(crawl_view.hudsz.x, faction_b.desc,
total_trials ? trials_done - team_a_wins : -1);
if (total_trials > 1 && trials_done < total_trials)
{
cgotoxy(1, line++, GOTO_STAT);
textcolor(BROWN);
center_print(crawl_view.hudsz.x,
make_stringf("Round %d of %d",
after_fight ? trials_done
: trials_done + 1,
total_trials));
}
else
{
cgotoxy(1, line++, GOTO_STAT);
textcolor(BROWN);
clear_to_end_of_line();
}
}
void setup_others()
{
you.species = SP_HUMAN;
you.char_class = JOB_FIGHTER;
you.experience_level = 27;
you.mutation[MUT_ACUTE_VISION] = 3;
coord_def yplace(dgn_find_feature_marker(DNGN_ESCAPE_HATCH_UP));
// Fix up the viewport.
you.moveto(yplace);
strcpy(you.your_name, "Arena");
you.hp = you.hp_max = 99;
you.your_level = 20;
Options.show_gold_turns = false;
show_fight_banner();
}
void expand_mlist(int exp)
{
crawl_view.mlistp.y -= exp;
crawl_view.mlistsz.y += exp;
}
void setup_fight()
throw (std::string)
{
//no_messages mx;
setup_level();
// Monster set up may block waiting for matchups.
setup_monsters();
setup_others();
}
// Returns true as long as at least one member of each faction is alive.
bool fight_is_on()
{
bool found_friend = false;
bool found_enemy = false;
for (int i = 0; i < MAX_MONSTERS; ++i)
{
const monsters *mons(&menv[i]);
if (mons->alive())
{
if (mons->attitude == ATT_FRIENDLY)
found_friend = true;
else if (mons->attitude == ATT_HOSTILE)
found_enemy = true;
if (found_friend && found_enemy)
return (true);
}
}
return (false);
}
void report_foes()
{
for (int i = 0; i < MAX_MONSTERS; ++i)
{
monsters *mons(&menv[i]);
if (mons->alive())
{
if (mons->type == MONS_SIGMUND)
{
coord_def where;
if (mons->get_foe())
where = mons->get_foe()->pos();
mprf("%s (%d,%d) foe: %s (%d,%d)",
mons->name(DESC_PLAIN).c_str(),
mons->pos().x, mons->pos().y,
mons->get_foe()? mons->get_foe()->name(DESC_PLAIN).c_str()
: "(none)",
where.x, where.y);
}
}
}
}
void fixup_foes()
{
for (int i = 0; i < MAX_MONSTERS; ++i)
{
monsters *mons(&menv[i]);
if (mons->alive())
{
behaviour_event(mons, ME_DISTURB, MHITNOT, mons->pos());
}
}
}
bool friendlies_win()
{
for (int i = 0; i < MAX_MONSTERS; ++i)
{
monsters *mons(&menv[i]);
if (mons->alive())
return (mons->attitude == ATT_FRIENDLY);
}
return (false);
}
void do_fight()
{
mesclr(true);
{
cursor_control coff(false);
while (fight_is_on())
{
if (kbhit() && getch() == ESCAPE)
end(0, false, "Canceled contest at user request");
viewwindow(true, false);
unwind_var<coord_def> pos(you.position);
// Move hero offscreen.
you.position.y = -1;
you.time_taken = 10;
//report_foes();
world_reacts();
delay(Options.arena_delay);
mesclr();
}
viewwindow(true, false);
}
mesclr();
const bool team_a_won = friendlies_win();
trials_done++;
if (team_a_won)
team_a_wins++;
show_fight_banner(true);
mprf("Winner: %s!",
team_a_won ? faction_a.desc.c_str() : faction_b.desc.c_str());
}
void global_setup()
{
expand_mlist(5);
}
void write_results()
{
if (FILE *f = fopen("arena.result", "w"))
{
fprintf(f, "%d-%d\n", team_a_wins, trials_done - team_a_wins);
fclose(f);
}
}
void write_error(const std::string &error)
{
if (FILE *f = fopen("arena.result", "w"))
{
fprintf(f, "err: %s\n", error.c_str());
fclose(f);
}
}
void simulate()
{
init_level_connectivity();
do
{
try
{
setup_fight();
}
catch (const std::string &error)
{
write_error(error);
end(0, false, "%s", error.c_str());
}
do_fight();
if (trials_done < total_trials)
delay(Options.arena_delay * 8);
} while (trials_done < total_trials);
if (total_trials > 0)
{
mprf("Final score: %s (%d); %s (%d)",
faction_a.desc.c_str(), team_a_wins,
faction_b.desc.c_str(), trials_done - team_a_wins);
delay(Options.arena_delay * 8);
}
write_results();
}
}
void run_arena()
{
arena::global_setup();
arena::simulate();
}