From dcf7801daff4c7c76e461c5ad08749394e64466b Mon Sep 17 00:00:00 2001 From: zelgadis Date: Sun, 16 Sep 2007 03:39:41 +0000 Subject: Add dump sections for branch/area details for turns and experience/kills, with the section names being turns_by_place and kills_by_place. Also includes a "visits" dump section (included in the "misc" section") a brief description of the number of branches/levels/areas/etc you visited. Breaks savefile compatibility. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@2102 c06c8d41-db1a-0410-9941-cceddc491573 --- crawl-ref/source/acr.cc | 64 ++++++++- crawl-ref/source/chardump.cc | 290 +++++++++++++++++++++++++++++++++++++---- crawl-ref/source/debug.cc | 4 +- crawl-ref/source/externs.h | 62 +++++++++ crawl-ref/source/files.cc | 37 +++++- crawl-ref/source/files.h | 6 +- crawl-ref/source/initfile.cc | 6 +- crawl-ref/source/makefile | 4 +- crawl-ref/source/makefile.unix | 8 +- crawl-ref/source/misc.cc | 11 +- crawl-ref/source/monstuff.cc | 56 ++++---- crawl-ref/source/player.cc | 242 +++++++++++++++++++++++++++++++++- crawl-ref/source/player.h | 4 +- crawl-ref/source/tags.cc | 95 +++++++++++++- 14 files changed, 810 insertions(+), 79 deletions(-) (limited to 'crawl-ref/source') diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc index 1fdb6f0b92..b5d585bc6b 100644 --- a/crawl-ref/source/acr.cc +++ b/crawl-ref/source/acr.cc @@ -1063,6 +1063,68 @@ static void input() } else viewwindow(true, false); + + if (you.num_turns != -1) + { + PlaceInfo& curr_PlaceInfo = you.get_place_info(); + PlaceInfo delta; + + delta.turns_total++; + delta.elapsed_total += you.time_taken; + + switch(you.running) + { + case RMODE_INTERLEVEL: + delta.turns_interlevel++; + delta.elapsed_interlevel += you.time_taken; + break; + + case RMODE_EXPLORE_GREEDY: + case RMODE_EXPLORE: + delta.turns_explore++; + delta.elapsed_explore += you.time_taken; + break; + + case RMODE_TRAVEL: + delta.turns_travel++; + delta.elapsed_travel += you.time_taken; + break; + + default: + // prev_was_rest is needed so that the turn in which + // a player is interrupted from resting is counted + // as a resting turn, rather than "other". + static bool prev_was_rest = false; + + if (!you.delay_queue.empty() && + you.delay_queue.front().type == DELAY_REST) + prev_was_rest = true; + + if (prev_was_rest) + { + delta.turns_resting++; + delta.elapsed_resting += you.time_taken; + + } + else + { + delta.turns_other++; + delta.elapsed_other += you.time_taken; + } + + if (you.delay_queue.empty() || + you.delay_queue.front().type != DELAY_REST) + prev_was_rest = false; + + break; + } + + you.global_info += delta; + you.global_info.assert_validity(); + + curr_PlaceInfo += delta; + curr_PlaceInfo.assert_validity(); + } } static bool toggle_flag( bool* flag, const char* flagname ) @@ -2957,7 +3019,7 @@ static bool initialise(void) load( you.entering_level? you.transit_stair : DNGN_STONE_STAIRS_DOWN_I, you.entering_level? LOAD_ENTER_LEVEL : newc ? LOAD_START_GAME : LOAD_RESTART_GAME, - true, -1, you.where_are_you ); + NUM_LEVEL_AREA_TYPES, -1, you.where_are_you ); #if DEBUG_DIAGNOSTICS // Debug compiles display a lot of "hidden" information, so we auto-wiz diff --git a/crawl-ref/source/chardump.cc b/crawl-ref/source/chardump.cc index d69ce9ce23..856d259935 100644 --- a/crawl-ref/source/chardump.cc +++ b/crawl-ref/source/chardump.cc @@ -73,7 +73,9 @@ static void sdump_religion(dump_params &); static void sdump_burden(dump_params &); static void sdump_hunger(dump_params &); static void sdump_transform(dump_params &); +static void sdump_visits(dump_params &); static void sdump_misc(dump_params &); +static void sdump_turns_by_place(dump_params &); static void sdump_notes(dump_params &); static void sdump_inventory(dump_params &); static void sdump_skills(dump_params &); @@ -81,6 +83,7 @@ static void sdump_spells(dump_params &); static void sdump_mutations(dump_params &); static void sdump_messages(dump_params &); static void sdump_screenshot(dump_params &); +static void sdump_kills_by_place(dump_params &); static void sdump_kills(dump_params &); static void sdump_newline(dump_params &); static void sdump_overview(dump_params &); @@ -115,33 +118,36 @@ struct dump_params }; static dump_section_handler dump_handlers[] = { - { "header", sdump_header }, - { "stats", sdump_stats }, - { "location", sdump_location }, - { "religion", sdump_religion }, - { "burden", sdump_burden }, - { "hunger", sdump_hunger }, - { "transform", sdump_transform }, - { "misc", sdump_misc }, - { "notes", sdump_notes }, - { "inventory", sdump_inventory }, - { "skills", sdump_skills }, - { "spells", sdump_spells }, - { "mutations", sdump_mutations }, - { "messages", sdump_messages }, - { "screenshot", sdump_screenshot }, - { "kills", sdump_kills }, - { "overview", sdump_overview }, - { "hiscore", sdump_hiscore }, + { "header", sdump_header }, + { "stats", sdump_stats }, + { "location", sdump_location }, + { "religion", sdump_religion }, + { "burden", sdump_burden }, + { "hunger", sdump_hunger }, + { "transform", sdump_transform }, + { "visits", sdump_visits }, + { "misc", sdump_misc }, + { "turns_by_place", sdump_turns_by_place}, + { "notes", sdump_notes }, + { "inventory", sdump_inventory }, + { "skills", sdump_skills }, + { "spells", sdump_spells }, + { "mutations", sdump_mutations }, + { "messages", sdump_messages }, + { "screenshot", sdump_screenshot }, + { "kills_by_place", sdump_kills_by_place}, + { "kills", sdump_kills }, + { "overview", sdump_overview }, + { "hiscore", sdump_hiscore }, // Conveniences for the .crawlrc artist. - { "", sdump_newline }, - { "-", sdump_separator }, + { "", sdump_newline }, + { "-", sdump_separator }, #ifdef CLUA_BINDINGS - { NULL, sdump_lua } + { NULL, sdump_lua } #else - { NULL, NULL } + { NULL, NULL } #endif }; @@ -267,6 +273,74 @@ static void sdump_transform(dump_params &par) } } +static void sdump_visits(dump_params &par) +{ + std::string &text(par.text); + + std::vector branches_visited = + you.get_all_place_info(true, true); + + PlaceInfo branches_total; + for (unsigned int i = 0; i < branches_visited.size(); i++) + branches_total += branches_visited[i]; + + text += make_stringf("You have visited %ld branch", + branches_visited.size()); + if (branches_visited.size() > 1) + text += "es"; + text += make_stringf(" of the dungeon, and seen %ld of its level", + branches_total.levels_seen); + if (branches_total.levels_seen > 1) + text += "s"; + text += ".\n"; + + PlaceInfo place_info = you.get_place_info(LEVEL_PANDEMONIUM); + if (place_info.num_visits > 0) + { + text += make_stringf("You have visited Pandemonium %ld time", + place_info.num_visits); + if (place_info.num_visits > 1) + text += "s"; + text += make_stringf(", and seen %ld of its levels.\n", + place_info.levels_seen); + if (place_info.levels_seen > 1) + text += "s"; + text += ".\n"; + } + + place_info = you.get_place_info(LEVEL_ABYSS); + if (place_info.num_visits > 0) + { + text += make_stringf("You have visited the Abyss %ld time", + place_info.num_visits); + if (place_info.num_visits > 1) + text += "s"; + text += ".\n"; + } + + place_info = you.get_place_info(LEVEL_LABYRINTH); + if (place_info.num_visits > 0) + { + text += make_stringf("You have visited %ld Labyrinth", + place_info.num_visits); + if (place_info.num_visits > 1) + text += "s"; + text += ".\n"; + } + + place_info = you.get_place_info(LEVEL_PORTAL_VAULT); + if (place_info.num_visits > 0) + { + text += make_stringf("You have visited %ld portal chamber", + place_info.num_visits); + if (place_info.num_visits > 1) + text += "s"; + text += " (including bazaars).\n"; + } + + text += "\n"; +} + static void sdump_misc(dump_params &par) { sdump_location(par); @@ -274,6 +348,82 @@ static void sdump_misc(dump_params &par) sdump_burden(par); sdump_hunger(par); sdump_transform(par); + sdump_visits(par); +} + +#define TO_PERCENT(x, y) (100.0 * ((float) (x)) / ((float) (y))) + +static std::string sdump_turns_place_info(PlaceInfo place_info, + std::string name = "") +{ + PlaceInfo gi = you.global_info; + std::string out; + + if (name == "") + name = place_info.short_name(); + + float a, b, c, d, e, f; + unsigned int non_interlevel = + place_info.turns_total - place_info.turns_interlevel; + unsigned int global_non_interlevel = + gi.turns_total - gi.turns_interlevel; + + + a = TO_PERCENT(place_info.turns_total, gi.turns_total); + b = TO_PERCENT(non_interlevel, global_non_interlevel); + c = TO_PERCENT(place_info.turns_interlevel, place_info.turns_total); + d = TO_PERCENT(place_info.turns_resting, non_interlevel); + e = TO_PERCENT(place_info.turns_explore, non_interlevel); + f = (float) non_interlevel / (float) place_info.levels_seen; + + out = + make_stringf("%14s | %5.1f | %5.1f | %5.1f | %5.1f | %5.1f | %13.1f\n", + name.c_str(), a, b, c , d, e, f); + + out = replace_all(out, " nan ", " N/A "); + + return out; +} + +static void sdump_turns_by_place(dump_params &par) +{ + std::string &text(par.text); + + std::vector all_visited = + you.get_all_place_info(true); + + text += +"Table legend:\n" +" A = Turns spent in this place as a percentage of turns spent in the\n" +" entire game.\n" +" B = Non-inter-level travel turns spent in this place as a perecentage of\n" +" non-inter-level travel turns spent in the entire game.\n" +" C = Inter-level travel turns spent in this place as a perecentage of\n" +" turns spent in this place.\n" +" D = Turns resting spent in this place as a percentage of non-inter-level\n" +" travel turns spent in this place.\n" +" E = Turns spent auto-exloring this place as a percentage of\n" +" non-inter-level travel turns spent in this place.\n" +" F = Non-inter-level travel turns spent in this place divided by the\n" +" number of levels of this place that you've seen.\n\n"; + + text += " "; + text += " A B C D E F\n"; + text += " "; + text += "+-------+-------+-------+-------+-------+----------------------\n"; + + text += sdump_turns_place_info(you.global_info, "Total"); + + for (unsigned int i = 0; i < all_visited.size(); i++) + { + PlaceInfo pi = all_visited[i]; + text += sdump_turns_place_info(pi); + } + + text += " "; + text += "+-------+-------+-------+-------+-------+----------------------\n"; + + text += "\n"; } static void sdump_newline(dump_params &par) @@ -819,6 +969,102 @@ static void sdump_kills(dump_params &par) par.text += you.kills->kill_info(); } +static std::string sdump_kills_place_info(PlaceInfo place_info, + std::string name = "") +{ + PlaceInfo gi = you.global_info; + std::string out; + + if (name == "") + name = place_info.short_name(); + + unsigned int global_total_kills = 0; + for (int i = 0; i < KC_NCATEGORIES; i++) + global_total_kills += you.global_info.mon_kill_num[i]; + + unsigned int total_kills = 0; + for (int i = 0; i < KC_NCATEGORIES; i++) + total_kills += place_info.mon_kill_num[i]; + + // Skip places where nothing was killed. + if (total_kills == 0) + return ""; + + float a, b, c, d, e, f, g; + + a = TO_PERCENT(total_kills, global_total_kills); + b = TO_PERCENT(place_info.mon_kill_num[KC_YOU], + you.global_info.mon_kill_num[KC_YOU]); + c = TO_PERCENT(place_info.mon_kill_num[KC_FRIENDLY], + you.global_info.mon_kill_num[KC_FRIENDLY]); + d = TO_PERCENT(place_info.mon_kill_num[KC_OTHER], + you.global_info.mon_kill_num[KC_OTHER]); + e = TO_PERCENT(place_info.mon_kill_exp, + you.global_info.mon_kill_exp); + f = TO_PERCENT(place_info.mon_kill_exp_avail, + you.global_info.mon_kill_exp_avail); + + g = (float) MAXIMUM(place_info.mon_kill_exp, + place_info.mon_kill_exp_avail) / + (float) place_info.levels_seen; + + out = + make_stringf("%14s | %5.1f | %5.1f | %5.1f | %5.1f | %5.1f |" + " %5.1f | %13.1f\n", + name.c_str(), a, b, c , d, e, f, g); + + out = replace_all(out, " nan ", " N/A "); + + return out; +} + +static void sdump_kills_by_place(dump_params &par) +{ + std::string &text(par.text); + + std::vector all_visited = + you.get_all_place_info(true); + + std::string result = ""; + + std::string header = +"Table legend:\n" +" A = Kills in this place as a percentage of kills in entire the game.\n" +" B = Kills by you in this place as a percentage of kills by you in\n" +" the entire game.\n" +" C = Kills by friends in this place as a percentage of kills by\n" +" friends in the entire game.\n" +" D = Other kills in this place as a percentage of other kills in the\n" +" entire game.\n" +" E = Character level experience gained in this place as a percentage of\n" +" character level experience gained in the entire game.\n" +" F = Skills experience gained in this place as a percentage of skills\n" +" experience gained in the entire game.\n" +" G = Experience gained in this place divided by the number of levels of\n" +" this place that you have seen.\n\n"; + + header += " "; + header += " A B C D E F G\n"; + header += " "; + header += "+-------+-------+-------+-------+-------+-------+--------------\n"; + + std::string footer = " "; + footer += "+-------+-------+-------+-------+-------+-------+--------------\n"; + + result += sdump_kills_place_info(you.global_info, "Total"); + + for (unsigned int i = 0; i < all_visited.size(); i++) + { + PlaceInfo pi = all_visited[i]; + result += sdump_kills_place_info(pi); + } + + if (result.length() > 0) + { + text += header + result + footer + "\n"; + } +} + static void sdump_overview(dump_params &par) { std::string overview = diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc index 2dc68b3471..b63df4d115 100644 --- a/crawl-ref/source/debug.cc +++ b/crawl-ref/source/debug.cc @@ -644,13 +644,13 @@ static void wizard_go_to_level(const level_pos &pos) const int old_level = you.your_level; const branch_type old_where = you.where_are_you; - const bool was_a_labyrinth = you.level_type == LEVEL_LABYRINTH; + const level_area_type old_level_type = you.level_type; you.level_type = LEVEL_DUNGEON; you.where_are_you = static_cast(pos.id.branch); you.your_level = abs_depth; - load(stair_taken, LOAD_ENTER_LEVEL, was_a_labyrinth, old_level, old_where); + load(stair_taken, LOAD_ENTER_LEVEL, old_level_type, old_level, old_where); save_game_state(); new_level(); viewwindow(1, true); diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h index 20bad76b20..3c59a1ece6 100644 --- a/crawl-ref/source/externs.h +++ b/crawl-ref/source/externs.h @@ -416,6 +416,50 @@ private: bool run_grids_changed() const; }; +class PlaceInfo +{ +public: + int level_type; + int branch; + + unsigned long num_visits; + unsigned long levels_seen; + + unsigned long mon_kill_exp; + unsigned long mon_kill_exp_avail; + unsigned long mon_kill_num[KC_NCATEGORIES]; + + long turns_total; + long turns_explore; + long turns_travel; + long turns_interlevel; + long turns_resting; + long turns_other; + + double elapsed_total; + double elapsed_explore; + double elapsed_travel; + double elapsed_interlevel; + double elapsed_resting; + double elapsed_other; + +public: + PlaceInfo(); + + bool is_global() const; + void make_global(); + + void assert_validity() const; + + const std::string short_name() const; + + const PlaceInfo &operator += (const PlaceInfo &other); + const PlaceInfo &operator -= (const PlaceInfo &other); + PlaceInfo operator + (const PlaceInfo &other) const; + PlaceInfo operator - (const PlaceInfo &other) const; +}; + + typedef std::vector delay_queue_type; class KillMaster; @@ -618,6 +662,12 @@ public: std::set uniq_map_tags; std::set uniq_map_names; + PlaceInfo global_info; + +protected: + FixedVector branch_info; + FixedVector non_branch_info; + public: player(); player(const player &other); @@ -743,6 +793,18 @@ public: bool wearing_light_armour(bool with_skill = false) const; void exercise(skill_type skill, int qty); int skill(skill_type skill, bool skill_bump = false) const; + + PlaceInfo& get_place_info() const ; // Current place info + PlaceInfo& get_place_info(branch_type branch, + level_area_type level_type2) const; + PlaceInfo& get_place_info(branch_type branch) const; + PlaceInfo& get_place_info(level_area_type level_type2) const; + + void set_place_info(PlaceInfo info); + // Returns copies of the PlaceInfo; modifying the vector won't + // modify the player object. + std::vector get_all_place_info(bool visited_only = false, + bool dungeon_only = false) const; }; extern player you; diff --git a/crawl-ref/source/files.cc b/crawl-ref/source/files.cc index 326d59706e..a96e9e507e 100644 --- a/crawl-ref/source/files.cc +++ b/crawl-ref/source/files.cc @@ -812,8 +812,10 @@ static void grab_followers() } } -bool load( dungeon_feature_type stair_taken, load_mode_type load_mode, - bool was_a_labyrinth, int old_level, branch_type old_branch ) + +bool load( dungeon_feature_type stair_taken, int load_mode, + level_area_type old_level_type, char old_level, + branch_type where_were_you2 ) { unwind_var stair( you.transit_stair, stair_taken, DNGN_UNSEEN); @@ -826,7 +828,7 @@ bool load( dungeon_feature_type stair_taken, load_mode_type load_mode, you.level_type, false ); - if (you.level_type == LEVEL_DUNGEON) + if (you.level_type == LEVEL_DUNGEON && old_level_type == LEVEL_DUNGEON) { if (tmp_file_pairs[you.your_level][you.where_are_you] == false) { @@ -853,10 +855,9 @@ bool load( dungeon_feature_type stair_taken, load_mode_type load_mode, { grab_followers(); - if (!was_a_labyrinth) - save_level( old_level, LEVEL_DUNGEON, old_branch ); - was_a_labyrinth = false; + if (old_level_type == LEVEL_DUNGEON) + save_level( old_level, LEVEL_DUNGEON, where_were_you2 ); } // Try to open level savefile. @@ -920,7 +921,7 @@ bool load( dungeon_feature_type stair_taken, load_mode_type load_mode, if (load_mode != LOAD_RESTART_GAME) { if (you.level_type != LEVEL_ABYSS) - place_player_on_stair(old_branch, stair_taken); + place_player_on_stair(where_were_you2, stair_taken); else you.moveto(45, 35); } @@ -989,6 +990,28 @@ bool load( dungeon_feature_type stair_taken, load_mode_type load_mode, setup_environment_effects(); + if (load_mode != LOAD_RESTART_GAME) + { + // Update PlaceInfo entries + PlaceInfo& curr_PlaceInfo = you.get_place_info(); + PlaceInfo delta; + + if (load_mode == LOAD_START_GAME || + (load_mode == LOAD_ENTER_LEVEL && + (where_were_you2 != you.where_are_you || + old_level_type != you.level_type))) + delta.num_visits++; + + if (just_created_level) + delta.levels_seen++; + + you.global_info += delta; + you.global_info.assert_validity(); + + curr_PlaceInfo += delta; + curr_PlaceInfo.assert_validity(); + } + return just_created_level; } // end load() diff --git a/crawl-ref/source/files.h b/crawl-ref/source/files.h index 32bdaf1728..9e996613dc 100644 --- a/crawl-ref/source/files.h +++ b/crawl-ref/source/files.h @@ -60,8 +60,10 @@ void check_newer(const std::string &target, const std::string &dependency, void (*action)()); -bool load( dungeon_feature_type stair_taken, load_mode_type load_mode, - bool was_a_labyrinth, int old_level, branch_type where_were_you2 ); + +bool load( dungeon_feature_type stair_taken, int load_mode, + level_area_type old_level_type, char old_level, + branch_type where_were_you2 ); // last updated 12may2000 {dlb} /* *********************************************************************** diff --git a/crawl-ref/source/initfile.cc b/crawl-ref/source/initfile.cc index 540b10742e..1b885bddfd 100644 --- a/crawl-ref/source/initfile.cc +++ b/crawl-ref/source/initfile.cc @@ -752,9 +752,9 @@ void game_options::reset_options() extra_levels.clear(); dump_order.clear(); - new_dump_fields("header,hiscore,stats,misc,inventory,skills," - "spells,overview,mutations,messages,screenshot," - "kills,notes"); + new_dump_fields("header,hiscore,stats,misc,turns_by_place,inventory," + "skills,spells,overview,mutations,messages,screenshot," + "kills_by_place,kills,notes"); hp_colour.clear(); hp_colour.push_back(std::pair(100, LIGHTGREY)); diff --git a/crawl-ref/source/makefile b/crawl-ref/source/makefile index 5709465ae3..b21a94dfc4 100644 --- a/crawl-ref/source/makefile +++ b/crawl-ref/source/makefile @@ -13,8 +13,8 @@ MAKEFILE = makefile.unix # cuts build time a lot on multi-cpu machines #OTHER=-j2 -all: - $(MAKE) $(OTHER) -f $(MAKEFILE) +all: wizard + @echo Built wizard binary profile: $(MAKE) $(OTHER) -f $(MAKEFILE) EXTRA_FLAGS='-pg' diff --git a/crawl-ref/source/makefile.unix b/crawl-ref/source/makefile.unix index f8211891d8..281ace7259 100644 --- a/crawl-ref/source/makefile.unix +++ b/crawl-ref/source/makefile.unix @@ -31,16 +31,16 @@ MCHMOD := 2755 MCHMOD_SAVEDIR := 775 # The user:group to install the game as. -INSTALL_UGRP := games:games +INSTALL_UGRP := matt:games -INSTALLDIR := /usr/games/crawl +INSTALLDIR := /usr/games/crawl-svn # If you're installing Crawl for multiple users, you *must* set this to a # valid path before building Crawl. This is not necessary if you are building # Crawl for a single user. -# SAVEDIR := /usr/games/crawl/saves/ -# DATADIR := /usr/games/crawl/data/ +# SAVEDIR := /usr/games/crawl-svn/saves/ +# DATADIR := /usr/games/crawl-svn/data/ LEX := flex YACC := bison -y diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc index 4b3a6a8f4a..30f2ed3627 100644 --- a/crawl-ref/source/misc.cc +++ b/crawl-ref/source/misc.cc @@ -460,8 +460,8 @@ void up_stairs(dungeon_feature_type force_stair) { dungeon_feature_type stair_find = force_stair? force_stair : grd[you.x_pos][you.y_pos]; - const branch_type old_where = you.where_are_you; - const bool was_a_labyrinth = you.level_type != LEVEL_DUNGEON; + const branch_type old_where = you.where_are_you; + const level_area_type old_level_type = you.level_type; if (stair_find == DNGN_ENTER_SHOP) { @@ -597,7 +597,7 @@ void up_stairs(dungeon_feature_type force_stair) else climb_message(stair_find, true); - load(stair_taken, LOAD_ENTER_LEVEL, was_a_labyrinth, old_level, old_where); + load(stair_taken, LOAD_ENTER_LEVEL, old_level_type, old_level, old_where); you.turn_is_over = true; @@ -672,8 +672,7 @@ void up_stairs(dungeon_feature_type force_stair) void down_stairs( int old_level, dungeon_feature_type force_stair ) { int i; - const level_area_type old_level_type = you.level_type; - const bool was_a_labyrinth = you.level_type != LEVEL_DUNGEON; + const level_area_type old_level_type = you.level_type; const dungeon_feature_type stair_find = force_stair? force_stair : grd[you.x_pos][you.y_pos]; @@ -915,7 +914,7 @@ void down_stairs( int old_level, dungeon_feature_type force_stair ) } const bool newlevel = - load(stair_taken, LOAD_ENTER_LEVEL, was_a_labyrinth, + load(stair_taken, LOAD_ENTER_LEVEL, old_level_type, old_level, old_where); if (newlevel) diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc index 35e369c353..61200ea0b6 100644 --- a/crawl-ref/source/monstuff.cc +++ b/crawl-ref/source/monstuff.cc @@ -364,12 +364,16 @@ static void check_kill_milestone(const monsters *mons, #endif // DGL_MILESTONES static void give_adjusted_experience(monsters *monster, killer_type killer, - bool pet_kill) + bool pet_kill, unsigned int *exp_gain, + unsigned int *avail_gain) { - if (YOU_KILL(killer)) - gain_exp( exper_value( monster ) ); + if (testbits(monster->flags, MF_CREATED_FRIENDLY)) + ; // No experience if monster was created friendly + else if (YOU_KILL(killer)) + gain_exp( exper_value( monster ), exp_gain, avail_gain ); else if (pet_kill) - gain_exp( exper_value( monster ) / 2 + 1 ); + gain_exp( exper_value( monster ) / 2 + 1, + exp_gain, avail_gain ); } static bool is_pet_kill(killer_type killer, int i) @@ -477,9 +481,6 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent) simple_monster_message( monster, " dissipates!", MSGCH_MONSTER_DAMAGE, MDAM_DEAD ); - if (!testbits(monster->flags, MF_CREATED_FRIENDLY)) - give_adjusted_experience(monster, killer, pet_kill); - if (monster->type == MONS_FIRE_VORTEX) place_cloud(CLOUD_FIRE, monster->x, monster->y, 2 + random2(4), monster->kill_alignment()); @@ -492,9 +493,6 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent) monster, " vapourises!", MSGCH_MONSTER_DAMAGE, MDAM_DEAD ); - if (!testbits(monster->flags, MF_CREATED_FRIENDLY)) - give_adjusted_experience(monster, killer, pet_kill); - place_cloud(CLOUD_COLD, monster->x, monster->y, 2 + random2(4), monster->kill_alignment()); } @@ -514,10 +512,6 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent) place_cloud( random_smoke_type(), monster->x, monster->y, 1 + random2(3), monster->kill_alignment() ); - - - if (!testbits(monster->flags, MF_CREATED_FRIENDLY)) - give_adjusted_experience(monster, killer, pet_kill); } else { @@ -537,15 +531,8 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent) monster->name(DESC_NOCAP_THE).c_str()); } - if (!created_friendly) - { - gain_exp(exper_value( monster )); - } - else - { - if (death_message) - mpr("That felt strangely unrewarding."); - } + if (created_friendly && death_message) + mpr("That felt strangely unrewarding."); // killing triggers tutorial lesson tutorial_inspect_kill(); @@ -642,7 +629,6 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent) { bool notice = false; const bool anon = (i == ANON_FRIENDLY_MONSTER); - gain_exp(exper_value( monster ) / 2 + 1); const mon_holy_type targ_holy = mons_holiness(monster), attacker_holy = anon? MH_NATURAL : mons_holiness(&menv[i]); @@ -806,6 +792,28 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent) { you.kills->record_kill(monster, killer, pet_kill); + kill_category kc = + (killer == KILL_YOU || killer == KILL_YOU_MISSILE) ? KC_YOU : + (pet_kill)? KC_FRIENDLY : + KC_OTHER; + + unsigned int exp_gain = 0, avail_gain = 0; + give_adjusted_experience(monster, killer, pet_kill, + &exp_gain, &avail_gain); + + PlaceInfo& curr_PlaceInfo = you.get_place_info(); + PlaceInfo delta; + + delta.mon_kill_num[kc]++; + delta.mon_kill_exp += exp_gain; + delta.mon_kill_exp_avail += avail_gain; + + you.global_info += delta; + you.global_info.assert_validity(); + + curr_PlaceInfo += delta; + curr_PlaceInfo.assert_validity(); + if (monster->has_ench(ENCH_ABJ)) { if (mons_weight(mons_species(monster->type))) diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc index 6ac2ef50c9..49c0b2abc4 100644 --- a/crawl-ref/source/player.cc +++ b/crawl-ref/source/player.cc @@ -32,6 +32,7 @@ #include "externs.h" +#include "branch.h" #include "clua.h" #include "delay.h" #include "dgnevent.h" @@ -2444,11 +2445,15 @@ void forget_map(unsigned char chance_forgotten) } } // end forget_map() -void gain_exp( unsigned int exp_gained ) +void gain_exp( unsigned int exp_gained, unsigned int* actual_gain, + unsigned int* actual_avail_gain) { if (player_equip_ego_type( EQ_BODY_ARMOUR, SPARM_ARCHMAGI )) exp_gained = div_rand_round( exp_gained, 4 ); + unsigned long old_exp = you.experience; + int old_avail = you.exp_available; + #if DEBUG_DIAGNOSTICS mprf(MSGCH_DIAGNOSTICS, "gain_exp: %d", exp_gained ); #endif @@ -2468,6 +2473,12 @@ void gain_exp( unsigned int exp_gained ) // become useful for a longer time if (Options.tutorial_left && you.experience_level == 7) tutorial_finished(); + + if (actual_gain != NULL) + *actual_gain = you.experience - old_exp; + + if (actual_avail_gain != NULL) + *actual_avail_gain = you.exp_available - old_avail; } // end gain_exp() void level_change(bool skip_ability_increase) @@ -5064,6 +5075,23 @@ void player::init() duration.init(0); exp_available = 25; + + global_info.make_global(); + global_info.assert_validity(); + + for (int i = 0; i < NUM_BRANCHES; i++) + { + branch_info[i].level_type = LEVEL_DUNGEON; + branch_info[i].branch = i; + branch_info[i].assert_validity(); + } + + for (int i = 0; i < (NUM_LEVEL_AREA_TYPES - 1); i++) + { + non_branch_info[i].level_type = i + 1; + non_branch_info[i].branch = -1; + non_branch_info[i].assert_validity(); + } } player::~player() @@ -5777,3 +5805,215 @@ void player::moveto(const coord_def &c) if (real_move) dungeon_events.fire_position_event(DET_PLAYER_MOVED, c); } + +//////////////////////////////////////////////////////////////////////////// + +PlaceInfo::PlaceInfo() + : level_type(-2), branch(-2), num_visits(0), + levels_seen(0), mon_kill_exp(0), mon_kill_exp_avail(0), + turns_total(0), turns_explore(0), turns_travel(0), turns_interlevel(0), + turns_resting(0), turns_other(0), elapsed_total(0.0), + elapsed_explore(0.0), elapsed_travel(0.0), elapsed_interlevel(0.0), + elapsed_resting(0.0), elapsed_other(0.0) +{ + for (int i = 0; i < KC_NCATEGORIES; i++) + mon_kill_num[i] = 0; +} + +bool PlaceInfo::is_global() const +{ + return (level_type == -1 && branch == -1); +} + +void PlaceInfo::make_global() +{ + level_type = -1; + branch = -1; +} + +void PlaceInfo::assert_validity() const +{ + // Check that level_type and branch match up + ASSERT(is_global() || + (level_type == LEVEL_DUNGEON && branch >= BRANCH_MAIN_DUNGEON && + branch < NUM_BRANCHES) || + (level_type > LEVEL_DUNGEON && level_type < NUM_LEVEL_AREA_TYPES && + branch == -1)); + + // Can't have visited a place without seeing any of its levels, and + // visa versa + ASSERT((num_visits == 0 && levels_seen == 0) || + (num_visits > 0 && levels_seen > 0)); + + if (level_type == LEVEL_LABYRINTH || level_type == LEVEL_ABYSS) + ASSERT(num_visits == levels_seen); + else if (level_type == LEVEL_PANDEMONIUM) + ASSERT(num_visits <= levels_seen); + else if (level_type == LEVEL_DUNGEON && branches[branch].depth > 0) + ASSERT(levels_seen <= (unsigned long) branches[branch].depth); + + ASSERT(turns_total == (turns_explore + turns_travel + turns_interlevel + + turns_resting + turns_other)); + + ASSERT(elapsed_total == (elapsed_explore + elapsed_travel + + elapsed_interlevel + elapsed_resting + + elapsed_other)); +} + +const std::string PlaceInfo::short_name() const +{ + if (level_type == LEVEL_DUNGEON) + return branches[branch].shortname; + else + { + switch (level_type) + { + case LEVEL_ABYSS: + return "Abyss"; + + case LEVEL_PANDEMONIUM: + return "Pandemonium"; + + case LEVEL_LABYRINTH: + return "Labyrinth"; + + default: + return "Bug"; + } + } +} + +const PlaceInfo &PlaceInfo::operator += (const PlaceInfo &other) +{ + num_visits += other.num_visits; + levels_seen += other.levels_seen; + + mon_kill_exp += other.mon_kill_exp; + mon_kill_exp_avail += other.mon_kill_exp_avail; + + for (int i = 0; i < KC_NCATEGORIES; i++) + mon_kill_num[i] += other.mon_kill_num[i]; + + turns_total += other.turns_total; + turns_explore += other.turns_explore; + turns_travel += other.turns_travel; + turns_interlevel += other.turns_interlevel; + turns_resting += other.turns_resting; + turns_other += other.turns_other; + + elapsed_total += other.elapsed_total; + elapsed_explore += other.elapsed_explore; + elapsed_travel += other.elapsed_travel; + elapsed_interlevel += other.elapsed_interlevel; + elapsed_resting += other.elapsed_resting; + elapsed_other += other.elapsed_other; + + return (*this); +} + +const PlaceInfo &PlaceInfo::operator -= (const PlaceInfo &other) +{ + num_visits -= other.num_visits; + levels_seen -= other.levels_seen; + + mon_kill_exp -= other.mon_kill_exp; + mon_kill_exp_avail -= other.mon_kill_exp_avail; + + for (int i = 0; i < KC_NCATEGORIES; i++) + mon_kill_num[i] -= other.mon_kill_num[i]; + + turns_total -= other.turns_total; + turns_explore -= other.turns_explore; + turns_travel -= other.turns_travel; + turns_interlevel -= other.turns_interlevel; + turns_resting -= other.turns_resting; + turns_other -= other.turns_other; + + elapsed_total -= other.elapsed_total; + elapsed_explore -= other.elapsed_explore; + elapsed_travel -= other.elapsed_travel; + elapsed_interlevel -= other.elapsed_interlevel; + elapsed_resting -= other.elapsed_resting; + elapsed_other -= other.elapsed_other; + + return (*this); +} + +PlaceInfo PlaceInfo::operator + (const PlaceInfo &other) const +{ + PlaceInfo copy = *this; + copy += other; + return copy; +} + +PlaceInfo PlaceInfo::operator - (const PlaceInfo &other) const +{ + PlaceInfo copy = *this; + copy -= other; + return copy; +} + + +PlaceInfo& player::get_place_info() const +{ + return get_place_info(where_are_you, level_type); +} + +PlaceInfo& player::get_place_info(branch_type branch) const +{ + return get_place_info(branch, LEVEL_DUNGEON); +} + +PlaceInfo& player::get_place_info(level_area_type level_type2) const +{ + return get_place_info(NUM_BRANCHES, level_type2); +} + +PlaceInfo& player::get_place_info(branch_type branch, + level_area_type level_type2) const +{ + ASSERT((level_type2 == LEVEL_DUNGEON && branch >= BRANCH_MAIN_DUNGEON && + branch < NUM_BRANCHES) || + (level_type2 > LEVEL_DUNGEON && level_type < NUM_LEVEL_AREA_TYPES)); + + if (level_type2 == LEVEL_DUNGEON) + return (PlaceInfo&) branch_info[branch]; + else + return (PlaceInfo&) non_branch_info[level_type2 - 1]; +} + +void player::set_place_info(PlaceInfo place_info) +{ + place_info.assert_validity(); + + if (place_info.is_global()) + global_info = place_info; + else if (place_info.level_type == LEVEL_DUNGEON) + branch_info[place_info.branch] = place_info; + else + non_branch_info[place_info.level_type - 1] = place_info; +} + +std::vector player::get_all_place_info(bool visited_only, + bool dungeon_only) const +{ + std::vector list; + + for (int i = 0; i < NUM_BRANCHES; i++) + { + if ((visited_only && branch_info[i].num_visits == 0) || + (dungeon_only && branch_info[i].level_type != LEVEL_DUNGEON)) + continue; + list.push_back(branch_info[i]); + } + + for (int i = 0; i < (NUM_LEVEL_AREA_TYPES - 1); i++) + { + if ((visited_only && non_branch_info[i].num_visits == 0) || + (dungeon_only && non_branch_info[i].level_type != LEVEL_DUNGEON)) + continue; + list.push_back(non_branch_info[i]); + } + + return list; +} diff --git a/crawl-ref/source/player.h b/crawl-ref/source/player.h index 1bc1bf72bc..8f4f0e897f 100644 --- a/crawl-ref/source/player.h +++ b/crawl-ref/source/player.h @@ -282,8 +282,8 @@ void forget_map(unsigned char chance_forgotten); /* *********************************************************************** * called from: acr - fight * *********************************************************************** */ -void gain_exp(unsigned int exp_gained); - +void gain_exp(unsigned int exp_gained, unsigned int* actual_gain = NULL, + unsigned int* actual_avail_gain = NULL); // last updated 17dec2000 {gdl} /* *********************************************************************** diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc index 057682d004..b2a5a78100 100644 --- a/crawl-ref/source/tags.cc +++ b/crawl-ref/source/tags.cc @@ -13,7 +13,7 @@ /* ------------------------- how tags work ---------------------------------- -1. Tag types are enumerated in enum.h, from TAG_VERSION (more a placeholder +1. Tag types are enumerated in tags.h, from TAG_VERSION (more a placeholder than anything else, it is not actually saved as a tag) to TAG_XXX. NUM_TAGS is equal to the actual number of defined tags. @@ -978,6 +978,35 @@ static void tag_construct_you_items(struct tagHeader &th) marshallBoolean(th, does_unrandart_exist(j)); } +static void marshallPlaceInfo(struct tagHeader &th, PlaceInfo place_info) +{ + marshallLong(th, place_info.level_type); + marshallLong(th, place_info.branch); + + marshallLong(th, place_info.num_visits); + marshallLong(th, place_info.levels_seen); + + marshallLong(th, place_info.mon_kill_exp); + marshallLong(th, place_info.mon_kill_exp_avail); + + for (int i = 0; i < KC_NCATEGORIES; i++) + marshallLong(th, place_info.mon_kill_num[i]); + + marshallLong(th, place_info.turns_total); + marshallLong(th, place_info.turns_explore); + marshallLong(th, place_info.turns_travel); + marshallLong(th, place_info.turns_interlevel); + marshallLong(th, place_info.turns_resting); + marshallLong(th, place_info.turns_other); + + marshallFloat(th, place_info.elapsed_total); + marshallFloat(th, place_info.elapsed_explore); + marshallFloat(th, place_info.elapsed_travel); + marshallFloat(th, place_info.elapsed_interlevel); + marshallFloat(th, place_info.elapsed_resting); + marshallFloat(th, place_info.elapsed_other); +} + static void tag_construct_you_dungeon(struct tagHeader &th) { int i,j; @@ -1006,6 +1035,14 @@ static void tag_construct_you_dungeon(struct tagHeader &th) marshallMap(th, portals_present, marshall_level_pos, marshall_as_long); + marshallPlaceInfo(th, you.global_info); + std::vector list = you.get_all_place_info(); + // How many different places we have info on? + marshallShort(th, list.size()); + + for (unsigned int k = 0; k < list.size(); k++) + marshallPlaceInfo(th, list[k]); + marshall_iterator(th, you.uniq_map_tags.begin(), you.uniq_map_tags.end(), marshallString); marshall_iterator(th, you.uniq_map_names.begin(), you.uniq_map_names.end(), @@ -1315,12 +1352,47 @@ static void tag_read_you_items(struct tagHeader &th, char minorVersion) set_unrandart_exist(j, 0); } +static PlaceInfo unmarshallPlaceInfo(struct tagHeader &th) +{ + PlaceInfo place_info; + + place_info.level_type = (int) unmarshallLong(th); + place_info.branch = (int) unmarshallLong(th); + + place_info.num_visits = (unsigned long) unmarshallLong(th); + place_info.levels_seen = (unsigned long) unmarshallLong(th); + + place_info.mon_kill_exp = (unsigned long) unmarshallLong(th); + place_info.mon_kill_exp_avail = (unsigned long) unmarshallLong(th); + + for (int i = 0; i < KC_NCATEGORIES; i++) + place_info.mon_kill_num[i] = (unsigned long) unmarshallLong(th); + + place_info.turns_total = unmarshallLong(th); + place_info.turns_explore = unmarshallLong(th); + place_info.turns_travel = unmarshallLong(th); + place_info.turns_interlevel = unmarshallLong(th); + place_info.turns_resting = unmarshallLong(th); + place_info.turns_other = unmarshallLong(th); + + place_info.elapsed_total = (double) unmarshallFloat(th); + place_info.elapsed_explore = (double) unmarshallFloat(th); + place_info.elapsed_travel = (double) unmarshallFloat(th); + place_info.elapsed_interlevel = (double) unmarshallFloat(th); + place_info.elapsed_resting = (double) unmarshallFloat(th); + place_info.elapsed_other = (double) unmarshallFloat(th); + + return place_info; +} + static void tag_read_you_dungeon(struct tagHeader &th) { - int i,j; - int count_c; + int i,j; + int count_c; short count_s; + unsigned short count_p; + // how many unique creatures? count_c = unmarshallShort(th); you.unique_creatures.init(false); @@ -1354,6 +1426,23 @@ static void tag_read_you_dungeon(struct tagHeader &th) unmarshallMap(th, portals_present, unmarshall_level_pos, unmarshall_long_as); + PlaceInfo place_info = unmarshallPlaceInfo(th); + ASSERT(place_info.is_global()); + you.set_place_info(place_info); + + std::vector list = you.get_all_place_info(); + count_p = (unsigned short) unmarshallShort(th); + // Use "<=" so that adding more branches or non-dungeon places + // won't break save-file compatibility. + ASSERT(count_p <= list.size()); + + for (i = 0; i < count_p; i++) + { + place_info = unmarshallPlaceInfo(th); + ASSERT(!place_info.is_global()); + you.set_place_info(place_info); + } + typedef std::set string_set; typedef std::pair ssipair; unmarshall_container(th, you.uniq_map_tags, -- cgit v1.2.3-54-g00ecf