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_levelTAGS: arena_level no_mons_genMARKER: A = feat: stone_stairs_up_iMARKER: B = feat: stone_stairs_down_iMARKER: O = feat: escape_hatch_upSUBST: A = ., B = ., O = .ORIENT: encompassMAPXXXXXXXXXXXXXXXXXX...............XX.......B.......XX...............XX...............XX...............XX...............XX...............XX.......O.......XX...............XX...............XX...............XX...............XX...............XX.......A.......XX...............XXXXXXXXXXXXXXXXXXENDMAP
#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();}