diff --git a/data/core/_main.cfg b/data/core/_main.cfg index b5bfd270695..18ffefc113b 100644 --- a/data/core/_main.cfg +++ b/data/core/_main.cfg @@ -9,6 +9,7 @@ wesnoth.dofile 'lua/wml-tags.lua' wesnoth.dofile 'lua/feeding.lua' wesnoth.dofile 'lua/diversion.lua' wesnoth.dofile 'lua/stun.lua' +wesnoth.dofile 'lua/carryover_gold.lua' >> [/lua] diff --git a/data/lua/carryover_gold.lua b/data/lua/carryover_gold.lua new file mode 100644 index 00000000000..00b8683fd7f --- /dev/null +++ b/data/lua/carryover_gold.lua @@ -0,0 +1,147 @@ +local _ = wesnoth.textdomain "wesnoth" + +local function get_is_observer() + for _, side in ipairs(wesnoth.sides) do + if side.controller == "human" and side.is_local then + return false + end + end + return true +end + +local function get_num_persistent_teams() + local res = 0 + for _, side in ipairs(wesnoth.sides) do + if side.persistent then + res = res + 1 + end + end + return res +end + +local function get_num_villages() + return #(wesnoth.map.find{ gives_income = true }) +end + +local function half_signed_value(num) + return tostring(num) +end + +local function get_popup_text_basic() + + local is_observer = get_is_observer() + local is_victory = wesnoth.scenario.end_level_data.is_victory + + local report = "" + local title = "" + + if is_observer then + title = _("Scenario Report") + elseif is_victory then + title = _("Victory") + report = report .. "" .. _("You have emerged victorious!") .. "" + else + title = _("Defeat") + report = report .. _("You have been defeated!") + end + return title, report +end + +local function do_carryover_gold() + + local endlevel_data = wesnoth.scenario.end_level_data + local has_next_scenario = wesnoth.scenario.next ~= "" and wesnoth.scenario.next ~= "null" and endlevel_data.proceed_to_next_level + local is_victory = endlevel_data.is_victory + local is_observer = get_is_observer() + local is_replay = wesnoth.current.iser_is_replaying + local show_report = endlevel_data.carryover_report and (not is_observer) and (not is_replay) + + local num_villages = get_num_villages() + local turns_left = math.max(0, wesnoth.scenario.turns - wesnoth.current.turn) + local num_persistent_teams = get_num_persistent_teams() + + local title, report = get_popup_text_basic() + + if has_next_scenario then + for __, side in ipairs(wesnoth.sides) do + if (not side.persistent) or side.lost then + goto continue + end + local finishing_bonus_per_turn = num_villages * side.village_gold + side.base_income + local finishing_bonus = side.carryover_bonus * finishing_bonus_per_turn * turns_left + + side.carryover_gold = math.ceil((side.gold + finishing_bonus) * side.carryover_percentage / 100) + + local is_human = side.controller == "human" + if (not side.is_local) or (not is_human) then + goto continue + end + + if num_persistent_teams > 1 then + report = report .. "\n\n" .. side.side_name .. "" + end + + report = report .. "\n" .. _("Remaining gold: ") .. half_signed_value(side.gold) .. "" + + if side.carryover_bonus ~= 0 then + if turns_left > -1 then + report = report .. "\n\n" .. + _("Turns finished early: ") .. turns_left .. "\n" .. "" .. + _("Early finish bonus: ") .. finishing_bonus_per_turn .. _(" per turn") .. "\n" .. "" .. + _("Total bonus: ") .. finishing_bonus .. "\n" + end + + report = report .. "" .. _("Total gold: ") .. half_signed_value(side.gold + finishing_bonus) .. "" + end + + if side.gold > 0 then + report = report .. "\n" .. _("Carryover percentage: ") .. side.carryover_percentage .. "" + end + + if side.carryover_add then + report = report .. "\n\n" .. _("Bonus gold: ") .. half_signed_value(side.carryover_gold) .. "" + else + report = report .. "\n\n" .. _("Retained gold: ") .. half_signed_value(side.carryover_gold) .. "" + end + + local goldmsg = "" + -- Note that both strings are the same in English, but some languages will + -- want to translate them differently. + if side.carryover_add then + if side.carryover_gold > 0 then + goldmsg = _("You will start the next scenario with $gold on top of the defined minimum starting gold.", + "You will start the next scenario with $gold on top of the defined minimum starting gold.", side.carryover_gold) + + else + goldmsg = _("You will start the next scenario with the defined minimum starting gold.", + "You will start the next scenario with the defined minimum starting gold.", side.carryover_gold) + end + else + goldmsg = _( + "You will start the next scenario with $gold or its defined minimum starting gold, whichever is higher.", + "You will start the next scenario with $gold or its defined minimum starting gold, whichever is higher.", + side.carryover_gold) + end + + -- xgettext:no-c-format + report = report .. "\n" .. goldmsg:vformat{ gold = tostring(side.carryover_gold) } + + ::continue:: + end + end + + if show_report then + gui.show_popup(title, report) + end +end + + +wesnoth.game_events.add { + name = "scenario_end", + id = "carryover_gold", + first_time_only = false, + --priority = -1000, + action = function() + do_carryover_gold() + end +} diff --git a/projectfiles/CodeBlocks/tests.cbp b/projectfiles/CodeBlocks/tests.cbp index 7f8688bd8c4..c13f3e63a48 100644 --- a/projectfiles/CodeBlocks/tests.cbp +++ b/projectfiles/CodeBlocks/tests.cbp @@ -233,8 +233,6 @@ - - diff --git a/projectfiles/CodeBlocks/wesnoth.cbp b/projectfiles/CodeBlocks/wesnoth.cbp index 1646e265477..87963d90c77 100644 --- a/projectfiles/CodeBlocks/wesnoth.cbp +++ b/projectfiles/CodeBlocks/wesnoth.cbp @@ -231,8 +231,6 @@ - - diff --git a/projectfiles/Xcode/The Battle for Wesnoth.xcodeproj/project.pbxproj b/projectfiles/Xcode/The Battle for Wesnoth.xcodeproj/project.pbxproj index 87f5ca46721..2e419b2f269 100644 --- a/projectfiles/Xcode/The Battle for Wesnoth.xcodeproj/project.pbxproj +++ b/projectfiles/Xcode/The Battle for Wesnoth.xcodeproj/project.pbxproj @@ -661,7 +661,6 @@ 7FDF4E8D9C94E7DA8F41F7BB /* tod_new_schedule.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 5D46466DBCD81B13621C7342 /* tod_new_schedule.hpp */; }; 805143B8BABF92CA79BEC8F5 /* gui_test_dialog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7FBD4033B4B52E9424819B5F /* gui_test_dialog.cpp */; }; 80724CBB88A3B6C36D1E3199 /* spritesheet_generator.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3D284B9A81882806D8B25006 /* spritesheet_generator.hpp */; }; - 867141839BDB89BFE876E310 /* carryover_show_gold.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 09A440B1A671C45BE2924FB4 /* carryover_show_gold.cpp */; }; 87744447951D17AA38BE5F48 /* mp_report.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 58C649488B3014E6F7254B62 /* mp_report.cpp */; }; 8C704B6F99C824A4073EEBEE /* prompt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 67044415B63F5888193BD7A6 /* prompt.cpp */; }; 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; @@ -1128,7 +1127,6 @@ 9577DD332C1E1C150031135F /* team_shared_vision.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 9577DD322C1E1C150031135F /* team_shared_vision.hpp */; }; 9577DD352C1E1E1D0031135F /* wesnoth_epoch.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 9577DD342C1E1E1C0031135F /* wesnoth_epoch.hpp */; }; 9577DD3E2C1E2EC60031135F /* preferences_list.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 9577DD3D2C1E2EC60031135F /* preferences_list.hpp */; }; - 9577DD402C1E36170031135F /* carryover_show_gold.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 9577DD3F2C1E36170031135F /* carryover_show_gold.hpp */; }; 9577DD422C1E368B0031135F /* statistics_record.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 9577DD412C1E368B0031135F /* statistics_record.hpp */; }; 9577DD442C1E36D40031135F /* from_chars.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 9577DD432C1E36D40031135F /* from_chars.hpp */; }; 9577DD462C1E36E20031135F /* any.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 9577DD452C1E36E20031135F /* any.hpp */; }; @@ -1143,7 +1141,6 @@ 95EB8A55287A02EC00B09F95 /* top_level_drawable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95EB8A54287A02EC00B09F95 /* top_level_drawable.cpp */; }; 95EB8A58287B138700B09F95 /* draw_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95EB8A50287A02B800B09F95 /* draw_manager.cpp */; }; 95EB8A59287B139800B09F95 /* top_level_drawable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95EB8A54287A02EC00B09F95 /* top_level_drawable.cpp */; }; - 97714C7A9FF444E29DCEF0BA /* carryover_show_gold.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 09A440B1A671C45BE2924FB4 /* carryover_show_gold.cpp */; }; 99494BD0ABBAE79FB3814E00 /* charconv.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0CDC443798CB3254283483D0 /* charconv.cpp */; }; 9B4B41D29C90B05F03DE21B0 /* edit_pbl_translation.hpp in Headers */ = {isa = PBXBuildFile; fileRef = C679447D91FD3623CC852FF8 /* edit_pbl_translation.hpp */; }; 9C2743DE8100448B66F7E0AF /* combobox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 875E45698F8A8D5B750E7317 /* combobox.cpp */; }; @@ -1600,7 +1597,6 @@ 000000000000000000000010 /* network_download_file.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = network_download_file.hpp; sourceTree = ""; }; 00574699A982AA23F12B39E0 /* edit_pbl_translation.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = edit_pbl_translation.cpp; sourceTree = ""; }; 0110429EAA81AED07D53B749 /* gui_test_dialog.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = gui_test_dialog.hpp; sourceTree = ""; }; - 09A440B1A671C45BE2924FB4 /* carryover_show_gold.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = carryover_show_gold.cpp; sourceTree = ""; }; 0B0F48CE9CF65D9813BE6CDC /* multiline_text.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = multiline_text.cpp; sourceTree = ""; }; 0CDC443798CB3254283483D0 /* charconv.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = charconv.cpp; path = charconv.cpp; sourceTree = ""; }; 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; @@ -2435,7 +2431,6 @@ 9577DD322C1E1C150031135F /* team_shared_vision.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = team_shared_vision.hpp; sourceTree = ""; }; 9577DD342C1E1E1C0031135F /* wesnoth_epoch.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = wesnoth_epoch.hpp; sourceTree = ""; }; 9577DD3D2C1E2EC60031135F /* preferences_list.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = preferences_list.hpp; path = preferences/preferences_list.hpp; sourceTree = ""; }; - 9577DD3F2C1E36170031135F /* carryover_show_gold.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = carryover_show_gold.hpp; sourceTree = ""; }; 9577DD412C1E368B0031135F /* statistics_record.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = statistics_record.hpp; sourceTree = ""; }; 9577DD432C1E36D40031135F /* from_chars.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = from_chars.hpp; sourceTree = ""; }; 9577DD452C1E36E20031135F /* any.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = any.hpp; sourceTree = ""; }; @@ -3269,8 +3264,6 @@ 91B621A11B76A3CC00B00E0F /* build_info.cpp */, 91B621A31B76A5FA00B00E0F /* build_info.hpp */, 9577DD1A2C1E0AF40031135F /* campaign_type.hpp */, - 09A440B1A671C45BE2924FB4 /* carryover_show_gold.cpp */, - 9577DD3F2C1E36170031135F /* carryover_show_gold.hpp */, ECFB9FA7193BFAD900146ED0 /* carryover.cpp */, 91B621811B766F1900B00E0F /* carryover.hpp */, 918C8A161D05F9AA009744A0 /* chat_command_handler.cpp */, @@ -5233,7 +5226,6 @@ 3DED4C43AC1B737C15549CEC /* rich_label.hpp in Headers */, 9577DD292C1E0E530031135F /* sort_order.hpp in Headers */, 9C6342BC8A95B6D23D384486 /* gui_test_dialog.hpp in Headers */, - 9577DD402C1E36170031135F /* carryover_show_gold.hpp in Headers */, 80724CBB88A3B6C36D1E3199 /* spritesheet_generator.hpp in Headers */, 0DA840E1AD033775DD626F42 /* markup.hpp in Headers */, F7524948ADF9BC097E6D8DBC /* charconv.hpp in Headers */, @@ -5979,7 +5971,6 @@ 46F92E212174F6A400602C1C /* mp_change_control.cpp in Sources */, 36B146FAA79A55E9F43723B1 /* general.cpp in Sources */, 3C254DF5B7DF196F2041955F /* mp_report.cpp in Sources */, - 97714C7A9FF444E29DCEF0BA /* carryover_show_gold.cpp in Sources */, 6D574EACA3483ABEE72819F0 /* statistics_record.cpp in Sources */, 4E19429E82899A42A73BBE91 /* choose_addon.cpp in Sources */, 36D74F7F8D7655ACCABE562D /* edit_pbl.cpp in Sources */, @@ -6654,7 +6645,6 @@ 915C68EC1DF1DCB000594B07 /* color.cpp in Sources */, 4291489DA38012477DA3BA7C /* general.cpp in Sources */, 87744447951D17AA38BE5F48 /* mp_report.cpp in Sources */, - 867141839BDB89BFE876E310 /* carryover_show_gold.cpp in Sources */, 3E9A4297B4A2828C569C8927 /* statistics_record.cpp in Sources */, E79249078ACE777D1E219DED /* choose_addon.cpp in Sources */, 04C748F7835C62498D27442D /* edit_pbl.cpp in Sources */, diff --git a/source_lists/wesnoth b/source_lists/wesnoth index d51381d492c..ceefc09a774 100644 --- a/source_lists/wesnoth +++ b/source_lists/wesnoth @@ -61,7 +61,6 @@ animated.cpp attack_prediction.cpp build_info.cpp carryover.cpp -carryover_show_gold.cpp chat_command_handler.cpp chat_events.cpp chat_log.cpp diff --git a/src/carryover_show_gold.cpp b/src/carryover_show_gold.cpp deleted file mode 100644 index 28343a5f724..00000000000 --- a/src/carryover_show_gold.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/* - Copyright (C) 2003 - 2024 - by David White - Part of the Battle for Wesnoth Project https://www.wesnoth.org/ - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY. - - See the COPYING file for more details. -*/ - -#include "carryover_show_gold.hpp" - -#include "log.hpp" -#include "team.hpp" -#include "game_state.hpp" -#include "gettext.hpp" -#include "gui/dialogs/transient_message.hpp" -#include "formula/string_utils.hpp" -#include "map/map.hpp" -#include "serialization/markup.hpp" -#include - -static lg::log_domain log_engine("engine"); -#define LOG_NG LOG_STREAM(info, log_engine) -#define ERR_NG LOG_STREAM(err, log_engine) - - -void carryover_show_gold(game_state& state, bool hidden, bool is_observer, bool is_test) -{ - assert(state.end_level_data_); - game_board& board = state.board_; - const end_level_data& end_level = *state.end_level_data_; - const bool is_victory = end_level.is_victory; - // We need to write the carryover amount to the team that's why we need non const - std::vector& teams = board.teams(); - - // maybe this can be the case for scenario that only contain a story and end during the prestart event ? - if(teams.size() < 1) { - return; - } - - std::ostringstream report; - std::string title; - - - if(is_observer) { - title = _("Scenario Report"); - } else if(is_victory) { - title = _("Victory"); - report << markup::bold(_("You have emerged victorious!")); - } else { - title = _("Defeat"); - report << _("You have been defeated!"); - } - - const std::string& next_scenario = state.get_game_data()->next_scenario(); - const bool has_next_scenario = !next_scenario.empty() && next_scenario != "null"; - - int persistent_teams = 0; - for(const team& t : teams) { - if(t.persistent()) { - ++persistent_teams; - } - } - - if(persistent_teams > 0 && ((has_next_scenario && end_level.proceed_to_next_level) || is_test)) { - const gamemap& map = board.map(); - const tod_manager& tod = state.get_tod_man(); - - const int turns_left = std::max(0, tod.number_of_turns() - tod.turn()); - for(team& t : teams) { - if(!t.persistent() || t.lost()) { - continue; - } - - const int finishing_bonus_per_turn = map.villages().size() * t.village_gold() + t.base_income(); - const int finishing_bonus = t.carryover_bonus() * finishing_bonus_per_turn * turns_left; - - t.set_carryover_gold(div100rounded((t.gold() + finishing_bonus) * t.carryover_percentage())); - - if(!t.is_local_human()) { - continue; - } - - if(persistent_teams > 1) { - report << "\n\n" << markup::bold(t.side_name()); - } - - report << "\n" << markup::tag("small", _("Remaining gold: "), utils::half_signed_value(t.gold())); - - if(t.carryover_bonus() != 0) { - if(turns_left > -1) { - report << "\n\n" - << markup::bold(_("Turns finished early: "), turns_left) << "\n" - << markup::tag("small", - _("Early finish bonus: "), finishing_bonus_per_turn, _(" per turn"), "\n", - _("Total bonus: "), finishing_bonus, "\n"); - } - - report << markup::tag("small", _("Total gold: "), utils::half_signed_value(t.gold() + finishing_bonus)); - } - - if(t.gold() > 0) { - report << "\n" << markup::tag("small", _("Carryover percentage: "), t.carryover_percentage()); - } - - if(t.carryover_add()) { - report << "\n\n" << markup::tag("big", markup::bold(_("Bonus gold: "), utils::half_signed_value(t.carryover_gold()))); - } else { - report << "\n\n" << markup::tag("big", markup::bold(_("Retained gold: "), utils::half_signed_value(t.carryover_gold()))); - } - - std::string goldmsg; - utils::string_map symbols; - - symbols["gold"] = lexical_cast_default(t.carryover_gold()); - - // Note that both strings are the same in English, but some languages will - // want to translate them differently. - if(t.carryover_add()) { - if(t.carryover_gold() > 0) { - goldmsg = VNGETTEXT( - "You will start the next scenario with $gold on top of the defined minimum starting gold.", - "You will start the next scenario with $gold on top of the defined minimum starting gold.", - t.carryover_gold(), symbols - ); - - } else { - goldmsg = VNGETTEXT( - "You will start the next scenario with the defined minimum starting gold.", - "You will start the next scenario with the defined minimum starting gold.", - t.carryover_gold(), symbols - ); - } - } else { - goldmsg = VNGETTEXT( - "You will start the next scenario with $gold or its defined minimum starting gold, " - "whichever is higher.", - "You will start the next scenario with $gold or its defined minimum starting gold, " - "whichever is higher.", - t.carryover_gold(), symbols - ); - } - - // xgettext:no-c-format - report << "\n" << goldmsg; - } - } - - if(end_level.transient.carryover_report && !hidden) { - gui2::show_transient_message(title, report.str(), "", true); - } -} diff --git a/src/carryover_show_gold.hpp b/src/carryover_show_gold.hpp deleted file mode 100644 index 390ca3a7d1a..00000000000 --- a/src/carryover_show_gold.hpp +++ /dev/null @@ -1,19 +0,0 @@ -/* - Copyright (C) 2022 - 2024 - Part of the Battle for Wesnoth Project https://www.wesnoth.org/ - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY. - - See the COPYING file for more details. -*/ - -#pragma once -class game_state; -/// calculates the amount of gold carried over for each team, -/// stores the data in the team object and shows the carryover message -void carryover_show_gold(game_state& state, bool hidden, bool is_observer, bool is_test); diff --git a/src/playsingle_controller.cpp b/src/playsingle_controller.cpp index 4cc74bfa86b..922fa6aa35a 100644 --- a/src/playsingle_controller.cpp +++ b/src/playsingle_controller.cpp @@ -25,7 +25,6 @@ #include "ai/manager.hpp" #include "ai/testing.hpp" #include "display_chat_manager.hpp" -#include "carryover_show_gold.hpp" #include "formula/string_utils.hpp" #include "game_end_exceptions.hpp" #include "game_events/pump.hpp" @@ -410,8 +409,6 @@ void playsingle_controller::do_end_level() } persist_.end_transaction(); - carryover_show_gold(gamestate(), is_observer() || is_replay(), is_observer(), saved_game_.classification().is_test()); - } level_result::type playsingle_controller::play_scenario(const config& level)