From 1c3aa7307852793ba0b700874ff92bb05e65a35f Mon Sep 17 00:00:00 2001 From: zelgadis Date: Tue, 6 Jan 2009 05:44:05 +0000 Subject: Consider a round a tie if there aren't any monsters at all left at the end of a turn. Unless one of the monster involved was a giant spore or ball lightning, in which case if the explosion caused the death of the final monster then the exploder is considered to be the winner (with "giant spore v giant spore" the first to explode is the winner). Figure out if a fight is still ongoing by doing book-keeping on how many members of each faction is alive, rather than sweeping through menv[] after every turn looking for living monsters. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@8263 c06c8d41-db1a-0410-9941-cceddc491573 --- crawl-ref/source/arena.cc | 147 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 111 insertions(+), 36 deletions(-) (limited to 'crawl-ref') diff --git a/crawl-ref/source/arena.cc b/crawl-ref/source/arena.cc index cd0b2896d2..2650510515 100644 --- a/crawl-ref/source/arena.cc +++ b/crawl-ref/source/arena.cc @@ -34,15 +34,25 @@ namespace arena struct faction { std::string desc; - mons_list members; - bool friendly; + mons_list members; + bool friendly; + int active_members; + bool suicide_attack; - faction(bool fr) : members(), friendly(fr) { } + faction(bool fr) : members(), friendly(fr), active_members(0), + suicide_attack(false) { } void place_at(const coord_def &pos); + void reset() + { + active_members = 0; + suicide_attack = false; + } + void clear() { + reset(); members.clear(); } }; @@ -53,6 +63,7 @@ namespace arena int trials_done = 0; int team_a_wins = 0; + int ties = 0; bool allow_summons = true; bool allow_chain_summons = true; @@ -332,6 +343,8 @@ namespace arena void setup_monsters() throw (std::string) { + faction_a.reset(); + faction_b.reset(); unwind_var< FixedVector > uniq(you.unique_creatures); @@ -376,7 +389,7 @@ namespace arena cgotoxy(1, line++, GOTO_STAT); textcolor(YELLOW); center_print(crawl_view.hudsz.x, faction_b.desc, - total_trials ? trials_done - team_a_wins : -1); + total_trials ? trials_done - team_a_wins - ties : -1); if (total_trials > 1 && trials_done < total_trials) { @@ -439,25 +452,52 @@ namespace arena setup_others(); } - // Returns true as long as at least one member of each faction is alive. - bool fight_is_on() + // Temporarily unset craw_state.arena to force a --more-- to happen. + void more() + { + unwind_bool state(crawl_state.arena, false); + + ::more(); + } + + void count_foes() { - bool found_friend = false; - bool found_enemy = false; + int orig_a = faction_a.active_members; + int orig_b = faction_b.active_members; + + faction_a.active_members = 0; + faction_b.active_members = 0; + for (int i = 0; i < MAX_MONSTERS; ++i) { const monsters *mons(&menv[i]); if (mons->alive()) { if (mons->attitude == ATT_FRIENDLY) - found_friend = true; + faction_a.active_members++; else if (mons->attitude == ATT_HOSTILE) - found_enemy = true; - if (found_friend && found_enemy) - return (true); + faction_b.active_members++; } } - return (false); + + if (orig_a != faction_a.active_members + || orig_b != faction_b.active_members) + { + mpr("Book-keeping error in faction member count.", MSGCH_ERROR); + more(); + } + } + + // Returns true as long as at least one member of each faction is alive. + bool fight_is_on() + { + if (faction_a.active_members > 0 && faction_b.active_members > 0) + return true; + + // Sync up our book-keeping with the actual state. + count_foes(); + + return (faction_a.active_members > 0 && faction_b.active_members > 0); } void report_foes() @@ -495,18 +535,6 @@ namespace arena } } - 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 dump_messages() { if (!Options.arena_dump_msgs || file == NULL) @@ -577,23 +605,38 @@ namespace arena mesclr(); - const bool team_a_won = friendlies_win(); - trials_done++; - if (team_a_won) + bool team_a_won = false; + bool was_tied = false; + if (faction_a.active_members > 0 || faction_a.suicide_attack) + { team_a_wins++; + team_a_won = true; + } + else if (faction_a.active_members == faction_b.active_members + && !faction_b.suicide_attack) + { + ties++; + was_tied = true; + } show_fight_banner(true); - const char *msg; - if (Options.arena_dump_msgs || Options.arena_list_eq) - msg = "---------- Winner: %s! ----------"; + std::string msg; + if (was_tied) + msg = "Tie"; else msg = "Winner: %s!"; - mprf(msg, - team_a_won ? faction_a.desc.c_str() : faction_b.desc.c_str()); + if (Options.arena_dump_msgs || Options.arena_list_eq) + msg = "---------- " + msg + " ----------"; + + if (was_tied) + mprf(msg.c_str()); + else + mprf(msg.c_str(), + team_a_won ? faction_a.desc.c_str() : faction_b.desc.c_str()); dump_messages(); } @@ -657,7 +700,11 @@ namespace arena { if (Options.arena_dump_msgs || Options.arena_list_eq) fprintf(file, "========================================\n"); - fprintf(file, "%d-%d\n", team_a_wins, trials_done - team_a_wins); + fprintf(file, "%d-%d", team_a_wins, + trials_done - team_a_wins - ties); + if (ties > 0) + fprintf(file, "-%d", ties); + fprintf(file, "\n"); } } @@ -693,9 +740,10 @@ namespace arena if (total_trials > 0) { - mprf("Final score: %s (%d); %s (%d)", + mprf("Final score: %s (%d); %s (%d) [%d ties]", faction_a.desc.c_str(), team_a_wins, - faction_b.desc.c_str(), trials_done - team_a_wins); + faction_b.desc.c_str(), trials_done - team_a_wins - ties, + ties); } delay(Options.arena_delay * 5); @@ -757,6 +805,11 @@ bool arena_veto_random_monster(monster_type type) void arena_placed_monster(monsters *monster, const mgen_data &mg, bool first_band_member) { + if (monster->attitude == ATT_FRIENDLY) + arena::faction_a.active_members++; + else if (monster->attitude == ATT_HOSTILE) + arena::faction_b.active_members++; + for (int i = 0; i < NUM_MONSTER_SLOTS; i++) { short it = monster->inv[i]; @@ -798,6 +851,28 @@ void arena_placed_monster(monsters *monster, const mgen_data &mg, void arena_monster_died(monsters *monster, killer_type killer, int killer_index, bool silent) { + if (monster->attitude == ATT_FRIENDLY) + arena::faction_a.active_members--; + else if (monster->attitude == ATT_HOSTILE) + arena::faction_b.active_members--; + + // Was the death caused by the suicide attack of a gas spore or + // ball lightning which was the final member of its faction? + if (arena::faction_a.active_members <= 0 + && arena::faction_b.active_members <= 0 + && !invalid_monster_index(killer_index) + && menv[killer_index].type != -1) + { + const monsters* atk = &menv[killer_index]; + + if (monster->attitude != atk->attitude && mons_self_destructs(atk)) + { + if (atk->attitude == ATT_FRIENDLY) + arena::faction_a.suicide_attack = true; + else if (atk->attitude == ATT_HOSTILE) + arena::faction_b.suicide_attack = true; + } + } } ///////////////////////////////////////////////////////////////////////////// -- cgit v1.2.3-54-g00ecf