Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

move the carryover gold handling and dialog to lua #7610

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

gfgtdf
Copy link
Contributor

@gfgtdf gfgtdf commented May 8, 2023

This is still a wip, in particular im not yet sure what exactly the api for replacing it should be

@gfgtdf gfgtdf marked this pull request as draft May 8, 2023 13:24
@github-actions github-actions bot added Lua API Issues with the Lua engine and API. Unit Tests Issues involving Wesnoth's unit test suite. labels May 8, 2023
@@ -0,0 +1,17 @@
#textdomain wesnoth-test
# This series of tests checks that scenarios are ending as appropriate.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment seems inaccurate

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@gfgtdf gfgtdf force-pushed the lua_carryover branch 4 times, most recently from 66f98fa to 2adfb8d Compare May 8, 2023 17:23
@@ -1704,6 +1704,7 @@ int game_lua_kernel::impl_current_get(lua_State *L)
return_int_attrib("turn", play_controller_.turn());
return_string_attrib("synced_state", synced_state());
return_bool_attrib("user_can_invoke_commands", !events::commands_disabled && gamedata().phase() == game_data::TURN_PLAYING);
return_bool_attrib("is_replaying", play_controller_.is_replay());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The convention for attributes of wesnoth.current is that reading it out makes sense as a phrase – "current map", "current schedule", "current event context", "current user can invoke commands", etc. This one doesn't fit that convention – "current is replaying" doesn't make sense.

Maybe user_is_replaying?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i can also move it somehere else, i wouldn't know where though. I'm not convinced that user_is_replayingis a better name

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm… wesnoth.scenario.is_replaying doesn't really make sense… maybe you could put it inwesnoth.interface as a function…

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still needs to be addressed.

@gfgtdf gfgtdf force-pushed the lua_carryover branch 2 times, most recently from 01171b9 to 0d6d6ce Compare May 9, 2023 02:52
@Slayer95
Copy link
Contributor

Slayer95 commented May 9, 2023

The default do_carryover_gold() function needs to be split in 4 functions:

  1. Calculation of gold bonus. It should return (*) a table that, for each side, contains:
  • A boolean signaling whether they get a bonus.
  • Total gold bonus.
  • Gold bonus per turn.
  1. Gold increase. It should accept the table from (1) and make it effective.
  2. Calculation of bonus message. It should accept the table from (1) (or a side subtable?), and return the customizable parts as a table.
  3. Display of bonus message. It should accept the table from (3) and show it.

Using events for carryover looks good. However, putting the entire do_carryover_gold() main routine as an event handler may not be that good (**). Instead, I wonder if it would be a palatable approach to fire events as the first instruction in (1), (2), (3), (4).

These events can then be handled by user-made code that mimicks the respective APIs of the default functions, and that calls wesnoth.cancel_action(). Then, if I am reading this correctly, the return value of fire() should be a tuple (***), and its second element should tell the main routine whether the event handlers called cancel_action.

(*) By return I mean setting these values as attributes in a public table or push them to the Lua stack. These side channels need to be used so that custom event handlers can actually set them.
(**) If the cancel_action approach is followed and the main routine were an event handler, then the main routine would seemingly share the same pump instance with its subevents, rendering the modularization useless.
(***) At least from the C++ side. That information doesn't seem to be pushed to the Lua stack at game_lua_kernel::intf_fire_event -but it should.

@Slayer95
Copy link
Contributor

Slayer95 commented May 9, 2023

Another event-based approach would rely on the other API mentioned in #7582 : aborting subsequent event handlers to the current event (maybe wesnoth.game_events.extinguish()). Then, it could be used for all of 1, 2, 3, 4, and even the main do_carryover_gold() routine itself were it also an event handler (as is in the current state of the PR.)

Either way, it seems the event system needs further improvements to be usable.

@gfgtdf
Copy link
Contributor Author

gfgtdf commented May 9, 2023

The default do_carryover_gold() function needs to be split in 4 functions ... wonder if it would be a palatable approach to fire events ...

While i agree that parts of the code could be designed to be a bit more reusable, i also don't think its worth to write a event based framework here, in particular if it makes it harder for the main usecase i had in mind when writing this, which are campaigns that want to completely replace the carryover gold mechanic, (no gold carried over at all, and probably reward quick finishes in another way (maybe items or free exp), or campaigns that have a score system)

@Slayer95
Copy link
Contributor

Slayer95 commented May 9, 2023

don't think its worth to write a event based framework here

Understandable.

Not sure what sort of API you have in mind. However, a baseline approach could be to make do_carryover_gold() call scenario.do_carryover_gold if defined, else
do_carryover_gold_default().

@gfgtdf
Copy link
Contributor Author

gfgtdf commented May 9, 2023

That similar to what i had in mind, i'm just unsure whether to put it, also i'm wondering whether i should make the helper functions available too, on the one hand i think they could be helpful, on he other hand making it an api would restrict us when changing their bahaviour in the future.

id = "carryover_gold",
first_time_only = false,
--priority = -1000,
action = function()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just action = do_carryover_gold should suffice, right?

Copy link
Contributor Author

@gfgtdf gfgtdf May 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i was considering making the variable do_carryover_gold non local (not sure where to put it yet), so that it could be replaced by umc. That's why i added this indirection

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm… someone wanting to replace it entirely could just unregister this event. I guess what you say makes sense if they want to mildly alter the behaviour, maybe…

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm i also wasn't sure how cleanly unregistering an event handler that was set in preload (and by preload i also mean toplevel lua) works, but i guess you just have to unregister them at preload aswell.

@gfgtdf
Copy link
Contributor Author

gfgtdf commented May 10, 2023

So i split the function into smaller parts, since the parts are then kinda public api, we now have to worry about making them pretty.

@@ -0,0 +1,11 @@
carryover = wesnoth.require("carryover_gold.lua")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be local.

@@ -47,83 +52,108 @@ local function get_popup_text_basic()
return title, report
end

local function do_carryover_gold()
--- Calculates the amount of carryover gold.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make these documentation comments conform to the format of the documentation comments in other modules, for example location_set or functional. That means using @param and @return annotations in addition to 3 dashes for the brief description as you've done here.

return #(wesnoth.map.find{ gives_income = true })
end

local function half_signed_value(num)
--- Like tostring(num) but uses a prettier minus sign, to be used in the UI.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is clearly not true, it's just returning tostring(num) directly.

Also, even if it were changed to be true, this seems like something that probably belongs in either the mathx or stringx module, not in here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tbh i don't even know why it's called that i just copied the name from the c++ function, but yeah the implementation is not there yet, idk whether it'd be really useful another places or whether other places usually want to use the normal minus sign.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's a C++ function, we could just make this a thin wrapper around the C++ function. We should at least consider changing the name though, as it doesn't make sense to me.

I also think it should return a t_string, rather than a regular Lua string.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still applies now.


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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a normal string, not a plural.

I know it's copying the C++, it's a bug there too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you think so?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh right now i see it

@github-actions github-actions bot removed the Unit Tests Issues involving Wesnoth's unit test suite. label Sep 4, 2023
The idea is to make it easier for umc devs to implement
their own carryover / early finish bonus mechanics. Maybe
we can also make use of it in Worls Conquest.
And use it in carryover_gold.lua
@github-actions github-actions bot added the Campaign WC The mainline World Conquest campaign label Feb 21, 2024
this way the functions can easily be reused for alternative
carryover implementations.
We now use a modified default carryover calculation,
the main advantage is it now uses the normal carryover
message on endlevel.
@gfgtdf gfgtdf marked this pull request as ready for review February 23, 2024 00:55
@gfgtdf
Copy link
Contributor Author

gfgtdf commented Feb 23, 2024

Now that 1.18 is branched of i'll probably merge this the next days


--- Returns true iff there is not a single side that is controlled by the local human player.
---@return boolean
function carryover.get_is_observer()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like something that should be moved into wesnoth.interface.

end

--- Show names when thre are multiple persistent teams.
---@return integer
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment explaining the return value, like this:

---@return integer #the number of things

Or change the main comment to include this information. (Speaking of which, the main comment seems to be incorrect.)

--- Calculates the amount of carryover gold.
---@param side side
---@param turns_left integer
---@return number (finishing_bonus), number (finishing_bonus_per_turn)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to explain multiple return values, each one needs to be on its own line.

Suggested change
---@return number (finishing_bonus), number (finishing_bonus_per_turn)
---@return number #total finishing bonus
---@return number #finishing bonus per turn

return finishing_bonus, finishing_bonus_per_turn
end

---@return boolean
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment, either with # at the end of this line or with --- on a separate line above, that explains what get_report_visible does.

function carryover.get_report_visible()
local is_observer = carryover.get_is_observer()
local is_replay = wesnoth.current.is_replaying
--return true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably needs to be deleted.

return wesnoth.scenario.end_level_data.carryover_report and (not is_observer) and (not is_replay)
end

--- Whether to show the sides names in the scenario end report.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
--- Whether to show the sides names in the scenario end report.
--- Whether to show the sides' names in the scenario end report.



--- returns a stub to show in the scenario end dialog.
---@return string (title), string (report)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
---@return string (title), string (report)
---@return string #title
---@return string #report


-- returns the first part of the carryover mesage, explain remaining gold
---@param side side
---@param info table
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please specify the format of this table.

There are two ways to do this. You can do it inline like this:

{field1: type, field2: type}

Or on the lines above you can add a block of comments like this:

---@class some_descriptive_name_for_the_table
---@field field1 type explanation of this field
---@field field2 type explanation of this field

If there's no obvious name for the type, remaining_gold_options or remaining_gold_info should be fine.

Or, if this is no longer used, then it could also be removed. (Though maybe the point is that the function could be overridden with one that does use it?)

end

---@param side side
---@param info table
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please specify the format of this table too. It looks like it has 3 optional fields? See my previous comment for how. Also, add a comment explaining what the function does.

end

---@param side side
---@param info table
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please specify the format of this table. Also, add a comment explaining what the function does.

return title, report
end

-- returns the first part of the carryover mesage, explain remaining gold
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment isn't descriptive enough. "explain remaining gold" isn't an explanation, it's just restating the function name.

end

---@param side side
---@param info table
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please specify the format of this table. Also, add a comment explaining what the function does.

end
--- returns the last part of the gold report for a single side, describing how much gold is added in the next scenario.
---@param side side
---@param info table
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please specify the format of this table. Also, add a line break before this comment block.

side.carryover_gold)
end

-- xgettext:no-c-format
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this actually needed? Does it even do anything?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pretty sure i coped it from the c++ code so not sure

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If that's the case, remove it. xgetext is the tool we use to gather translatable strings from C++ files, but it's not used on Lua files.


--- returns the default gold report for a single side.
---@param side side
---@param info table
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please specify the format of this table. Also, the comment could be improved.

return report
end

---@return boolean
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment indicating what this function does. I realize it may seem obvious from the name, but I'd like to make it explicit too.

end

---@return table
function carryover.turns_left()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This says it returns a table but it actually returns an integer.

return math.max(0, wesnoth.scenario.turns - wesnoth.current.turn)
end

--- sets the sides carryover gold and returns information that is used in the report message
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
--- sets the sides carryover gold and returns information that is used in the report message
--- sets the side's carryover gold and returns information that is used in the report message


--- sets the sides carryover gold and returns information that is used in the report message
---@param side side
---@return table
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please specify the format of this table.

}
end

function carryover.do_carryover_gold()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this function undocumented?

@@ -394,7 +394,7 @@ void playsingle_controller::do_end_level()
}

persist_.end_transaction();
carryover_show_gold(gamestate(), is_observer() || is_replay(), is_observer(), saved_game_.classification().is_test());
// carryover_show_gold(gamestate(), is_observer() || is_replay(), is_observer(), saved_game_.classification().is_test());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please delete.

@CelticMinstrel
Copy link
Member

carryover_show_gold.?pp have nothing left in them now, so please delete them. I realize that means editing the Xcode project file, but it's honestly not that hard to remove a file from it – just delete all lines mentioning the file.

Please fix at least everything I mentioned that's not related to documentation before merging. I'd prefer you to fix all the documentation issues too, though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Campaign WC The mainline World Conquest campaign Lua API Issues with the Lua engine and API.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants