[WoF] Avoid code duplication and fix a non-translatable string (#8384)

Instead of copy-pasting the multiplayer turns over advantage function, just use that function directly.

This required making some changes to the function to better support this specific use-case,
but I think it's still better than copy-pasting it.

I split the primary functionality out into two separate pieces – calculation and display.
Thus, the main function is technically unchanged, while WoF can avoid the weird things it does
and just calculate and display how it wants.

This fixes #8368.
This commit is contained in:
Celtic Minstrel 2024-02-16 09:38:45 -05:00 committed by GitHub
parent 0e99d4b38b
commit 8d30761ca8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 84 additions and 125 deletions

View file

@ -1,79 +0,0 @@
-- from multiplayer/eras.lua, slightly modified for use in a campaign and to return a result
local function determine_advantage()
local _ = wesnoth.textdomain "wesnoth-multiplayer"
local function all_sides()
local function f(s, i)
i = i + 1
local t = wesnoth.sides[i]
return t and i, t
end
return f, nil, 0
end
local income_factor = 5
local winning_sides = {}
local total_score = -1
local side_comparison = ""
local winners_color = "#000000"
for side, team in all_sides() do
if not team.__cfg.hidden then
local side_color = wesnoth.colors[team.color].pango_color
if # wesnoth.units.find_on_map( { side = side } ) == 0 then
-- po: In the end-of-match summary, a side which has no units left and therefore lost. In English the loss is shown by displaying it with the text struck through.
local side_text = _ "<span strikethrough='true' foreground='$side_color'>Side $side_number</span>: Has lost all units"
-- The double new-line here is to balance with the other sides getting a line for "Grand total"
side_comparison = side_comparison .. side_text:vformat{side_color = side_color, side_number = side} .. "\n\n"
else
local income = team.total_income * income_factor
local units = 0
-- Calc the total unit-score here
for i, unit in ipairs( wesnoth.units.find_on_map { side = side } ) do
if not unit.__cfg.canrecruit then
wml.fire("unit_worth", { id = unit.id })
units = units + wml.variables["unit_worth"]
end
end
-- Up to here
local total = units + team.gold + income
-- po: In the end-of-match summary, any side that still has units left
local side_text = _ "<span foreground='$side_color'>Side $side_number</span>: Income score = $income Unit score = $units Gold = $gold\nGrand total: <b>$total</b>"
side_comparison = side_comparison .. side_text:vformat{side_color = side_color, side_number = side, income = income, units = units, gold = team.gold, total = total} .. "\n"
if total > total_score then
winners_color = side_color
winning_sides = {side}
total_score = total
elseif total == total_score then
table.insert(winning_sides, side)
end
end
end
end
local result = nil
if #winning_sides == 1 then
-- po: In the end-of-match summary, there's a single side that's won.
local comparison_text = _ "<span foreground='$side_color'>Side $side_number</span> has the advantage."
side_comparison = side_comparison .. "\n" .. comparison_text:vformat{side_number = winning_sides[1], side_color = winners_color}
result = winning_sides[1]
else -- #winning_sides == 2, a tie (or both sides have no units or a negative score which should be impossible here)
-- po: In the end-of-match summary, there's a two-way tie (this is only used for exactly two winning teams)
local comparison_text = _ "Sides $side_number and $other_side_number are tied."
side_comparison = side_comparison .. "\n" .. comparison_text:vformat{side_number = winning_sides[1], other_side_number = winning_sides[2]}
result = "tie"
end
if dialog_type == "turnsover" then
-- po: "Turns Over", meaning "turn limit reached" is the title of the end-of-match summary dialog
local a, b = gui.show_popup(_ "dialog^Turns Over", side_comparison)
else
local a, b = gui.show_popup(_ "dialog^Advantage", side_comparison)
end
return result
end
arg={...}
-- There need to be two different dialog titles, but the title is not passed directly as a string because it wouldn't be translatable in that case.
dialog_type=arg[1]
return determine_advantage()

View file

@ -362,7 +362,14 @@ You shall learn a pivotal lesson in humility!"
image="icons/advantage.png"
[command]
[lua]
code = << wml.variables["result"] = wesnoth.dofile("campaigns/Winds_of_Fate/lua/lua.lua", "advantage") >>
code = <<
local eras = wesnoth.require("multiplayer/eras.lua")
local winning_sides, scores = eras.calc_turns_over_advantage()
eras.show_turns_over_advantage(winning_sides, scores, (...).title)
>>
[args]
title=_ "dialog^Advantage"
[/args]
[/lua]
[/command]
[/set_menu_item]
@ -380,33 +387,21 @@ You shall learn a pivotal lesson in humility!"
first_time_only=no
# Determine which side has the advantage.
[lua]
code = << wml.variables["result"] = wesnoth.dofile("campaigns/Winds_of_Fate/lua/lua.lua", "turnsover") >>
code = <<
local eras = wesnoth.require("multiplayer/eras.lua")
local winning_sides, scores = eras.calc_turns_over_advantage()
eras.show_turns_over_advantage(winning_sides, scores)
if #winning_sides == 1 then
if winning_sides[1] == 1 then
wml.fire.endlevel{result = 'victory'}
elseif winning_sides[1] == 2 then
wml.fire.endlevel{result = 'defeat'}
end
elseif #winning_sides == 2 then
wml.fire.modify_turns{add = 2}
end
>>
[/lua]
[switch]
variable=result
[case]
value=1
[endlevel]
result=victory
[/endlevel]
[/case]
[case]
value=2
[endlevel]
result=defeat
[/endlevel]
[/case]
[case]
value=tie
[modify_turns]
add=2
[/modify_turns]
[/case]
[else]
# Error, do nothing and end in defeat.
[/else]
[/switch]
{CLEAR_VARIABLE result}
[/event]
[event]

View file

@ -21,7 +21,7 @@ res.quick_4mp_leaders = function(args)
end
end
res.turns_over_advantage = function()
function res.turns_over_advantage()
local show_turns_over_advantage = wml.variables["show_turns_over_advantage"]
if show_turns_over_advantage == nil then
show_turns_over_advantage = wesnoth.scenario.mp_settings and (wesnoth.scenario.mp_settings.mp_campaign == "")
@ -29,7 +29,23 @@ res.turns_over_advantage = function()
if not show_turns_over_advantage then
return
end
local _ = wesnoth.textdomain "wesnoth-multiplayer"
local winning_sides, side_results = res.calc_turns_over_advantage()
res.show_turns_over_advantage(winning_sides, side_results)
end
---@class side_result
---@field income integer
---@field num_units integer
---@field gold integer
---@field total integer
---@alias sides_score_table table<integer, side_result|false>
---Calculate the turns over advantage.
---@param income_factor? integer Indicates how important income is in the calculation.
---@return integer[]
---@return sides_score_table
function res.calc_turns_over_advantage(income_factor)
local function all_sides()
local function f(s, i)
i = i + 1
@ -39,37 +55,36 @@ res.turns_over_advantage = function()
return f, nil, 0
end
local income_factor = 5
income_factor = income_factor or 5
local winning_sides = {}
local total_score = -1
local side_comparison = ""
local winners_color = "#000000"
---@type sides_score_table
local side_outcomes = {}
for side, team in all_sides() do
if not team.__cfg.hidden then
local side_color = wesnoth.colors[team.color].pango_color
if # wesnoth.units.find_on_map( { side = side } ) == 0 then
-- po: In the end-of-match summary, a side which has no units left and therefore lost. In English the loss is shown by displaying it with the text struck through.
local side_text = _ "<span strikethrough='true' foreground='$side_color'>Side $side_number</span>: Has lost all units"
-- The double new-line here is to balance with the other sides getting a line for "Grand total"
side_comparison = side_comparison .. side_text:vformat{side_color = side_color, side_number = side} .. "\n\n"
side_outcomes[side] = false
else
local income = team.total_income * income_factor
local units = 0
-- Calc the total unit-score here
for i, unit in ipairs( wesnoth.units.find_on_map { side = side } ) do
if not unit.__cfg.canrecruit then
wml.fire("unit_worth", { id = unit.id })
units = units + wml.variables["unit_worth"]
wml.fire.unit_worth{ id = unit.id }
units = units + wml.variables.unit_worth
end
end
-- Up to here
local total = units + team.gold + income
-- po: In the end-of-match summary, any side that still has units left
local side_text = _ "<span foreground='$side_color'>Side $side_number</span>: Income score = $income Unit score = $units Gold = $gold\nGrand total: <b>$total</b>"
side_comparison = side_comparison .. side_text:vformat{side_color = side_color, side_number = side, income = income, units = units, gold = team.gold, total = total} .. "\n"
side_outcomes[side] = {
income = income,
num_units = units,
gold = team.gold,
total = total
}
if total > total_score then
winners_color = side_color
winning_sides = {side}
total_score = total
elseif total == total_score then
@ -79,10 +94,38 @@ res.turns_over_advantage = function()
end
end
return winning_sides, side_outcomes
end
---Show the turns over advantage popup.
---@param winning_sides integer[] The list of sides who tied for first place
---@param side_results sides_score_table The table of each side's score calculations
---@param title? tstring The title to display in the popup
function res.show_turns_over_advantage(winning_sides, side_results, title)
local _ = wesnoth.textdomain "wesnoth-multiplayer"
---@type tstring
local side_comparison = ""
for side = 1, #wesnoth.sides do
local outcome = side_results[side]
local side_color = wesnoth.colors[wesnoth.sides[side].color].pango_color
if outcome == false then
-- po: In the end-of-match summary, a side which has no units left and therefore lost. In English the loss is shown by displaying it with the text struck through.
local side_text = _ "<span strikethrough='true' foreground='$side_color'>Side $side_number</span>: Has lost all units"
-- The double new-line here is to balance with the other sides getting a line for "Grand total"
side_comparison = side_comparison .. side_text:vformat{side_color = side_color, side_number = side} .. "\n\n"
elseif outcome ~= nil then
-- po: In the end-of-match summary, any side that still has units left
local side_text = _ "<span foreground='$side_color'>Side $side_number</span>: Income score = $income Unit score = $units Gold = $gold\nGrand total: <b>$total</b>"
side_comparison = side_comparison .. side_text:vformat{side_color = side_color, side_number = side, income = outcome.income, units = outcome.num_units, gold = outcome.gold, total = outcome.total} .. "\n"
end
end
if #winning_sides == 1 then
local side = winning_sides[1]
local side_color = wesnoth.colors[wesnoth.sides[side].color].pango_color
-- po: In the end-of-match summary, there's a single side that's won.
local comparison_text = _ "<span foreground='$side_color'>Side $side_number</span> has the advantage."
side_comparison = side_comparison .. "\n" .. comparison_text:vformat{side_number = winning_sides[1], side_color = winners_color}
side_comparison = side_comparison .. "\n" .. comparison_text:vformat{side_number = winning_sides[1], side_color = side_color}
elseif #winning_sides == 2 then
-- po: In the end-of-match summary, there's a two-way tie (this is only used for exactly two winning teams)
-- Separated from the three-or-more text in case a language differentiates "two sides" vs "three sides".
@ -95,8 +138,8 @@ res.turns_over_advantage = function()
side_comparison = side_comparison .. "\n" .. comparison_text:vformat{winners = winners}
end
-- if #winning_sides==0, then every side either has no units or has a negative score
-- po: "Turns Over", meaning "turn limit reached" is the title of the end-of-match summary dialog
local a, b = gui.show_popup(_ "dialog^Turns Over", side_comparison)
title = title or _ "dialog^Turns Over"
gui.show_popup(title, side_comparison)
end
return res