-
Notifications
You must be signed in to change notification settings - Fork 77
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
Add support for campaign status #1681
base: master
Are you sure you want to change the base?
Conversation
Either I'm blind or the implementation is somewhere else? What is |
Edit: For roman-style campaigns it shows the "You have successfully completed chapter X." screen after ending the game. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome, the last bit for campaigns! Review inline.
General hint: Try to make best use of the type system. E.g. "unsigned char" is/should be a (text-)character (although only since C++11 introduced uint8_t
) And using this narrow width number-type as parameters likely introduces overhead (registers are wider so often need to be masked) so it is even faster to just use unsigned
there.
Similar for string
which should be text. It can be stored in the config as a string for brevity but converted during load/save to a more appropriate type, especially when (scoped) enums can be used.
In general I like the changes, thanks! :)
constexpr auto chapterDisabled = '0'; | ||
constexpr auto chapterEnabled = '1'; | ||
constexpr auto chapterCompleted = '2'; | ||
constexpr auto defaultChaptersEnabled = "1100000000"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What exactly does this mean? Can you add some description?
@@ -23,6 +24,7 @@ struct CampaignDescription | |||
std::string image; | |||
unsigned maxHumanPlayers = 0; | |||
std::string difficulty; | |||
std::string defaultChaptersEnabled; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a docstring what this is and how it should be interpreted? Maybe a string isn't the right type as it isn't exactly text. I guess it is a variable sized array of enum type represented as a string. So maybe an own type and corresponding lua loader is better.
std::vector<MissionStatus> ret(saveData.length()); | ||
for(auto i = 0u; i < saveData.length(); ++i) | ||
{ | ||
ret[i].playable = saveData[i] != CampaignSaveCodes::chapterDisabled; | ||
ret[i].conquered = saveData[i] == CampaignSaveCodes::chapterCompleted; | ||
} | ||
|
||
ret.resize(campaignDesc.getNumMaps()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd say it would be better: Either a range-based for and push_back
or use numMaps as the initial size and loop over rttr::Range(min(saveData.length(), ret.length())
|
||
struct CampaignDescription; | ||
|
||
bool isChapterEnabled(const CampaignDescription& campaignDesc, unsigned char chapter); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The argument isn't a char but a number:
bool isChapterEnabled(const CampaignDescription& campaignDesc, unsigned char chapter); | |
bool isChapterEnabled(const CampaignDescription& campaignDesc, unsigned chapter); |
Or uint8_t
although that is likely even slower so isn't really useful, is it?
namespace { | ||
auto getCampaignSaveData(const CampaignDescription& campaignDesc) | ||
{ | ||
auto& saveData = SETTINGS.campaigns.saveData; | ||
|
||
if(!saveData.count(campaignDesc.uid)) | ||
saveData[campaignDesc.uid] = campaignDesc.defaultChaptersEnabled; | ||
|
||
return saveData[campaignDesc.uid]; | ||
} | ||
} // namespace |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For a single function (or even just functions) static
is less clutter:
namespace { | |
auto getCampaignSaveData(const CampaignDescription& campaignDesc) | |
{ | |
auto& saveData = SETTINGS.campaigns.saveData; | |
if(!saveData.count(campaignDesc.uid)) | |
saveData[campaignDesc.uid] = campaignDesc.defaultChaptersEnabled; | |
return saveData[campaignDesc.uid]; | |
} | |
} // namespace | |
static auto getCampaignSaveData(const CampaignDescription& campaignDesc) | |
{ | |
auto& saveData = SETTINGS.campaigns.saveData; | |
if(!saveData.count(campaignDesc.uid)) | |
saveData[campaignDesc.uid] = campaignDesc.defaultChaptersEnabled; | |
return saveData[campaignDesc.uid]; | |
} |
Also do you intend to return a copy? It looks like it is supposed to be either a reference or a const reference
|
||
BOOST_FIXTURE_TEST_CASE(Chapters0and1AreEnabledByDefault, CampaignSaveDataFixture) | ||
{ | ||
saveData[uid] = CampaignSaveCodes::defaultChaptersEnabled; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So the default is to enable the first 2 chapters? Why that? Wouldn't (only) the first one be a more sensible default?
I'm also a bit confused as you seem to be using indices and 1-based values for chapters
Maybe stick to indices and use an optional instead of zero
BOOST_TEST_REQUIRE(isChapterEnabled(desc, 0) == true); | ||
BOOST_TEST_REQUIRE(isChapterEnabled(desc, 1) == false); | ||
BOOST_TEST_REQUIRE(isChapterEnabled(desc, 2) == false); | ||
BOOST_TEST_REQUIRE(isChapterEnabled(desc, 9) == false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should also include a change to saveData
to check that the default really is only a default and overwritten by an explicit value.
} | ||
|
||
CampaignDescription dsc; | ||
CampaignDataLoader loader{dsc, tmp}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why can't this just use desc
from the fixture?
executeLua("rttr:SetCampaignChapterCompleted('campaign_id', 0)"); // noop - chapters start from 1 | ||
executeLua("rttr:EnableCampaignChapter('campaign_id', 0)"); // noop - chapters start from 1 | ||
executeLua("rttr:EnableCampaignChapter('campaign_id', 2)"); // noop - already completed | ||
game.executeAICommands(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this line for?
@@ -12,6 +13,7 @@ | |||
CampaignDescription::CampaignDescription(const kaguya::LuaRef& table) | |||
{ | |||
CheckedLuaTable luaData(table); | |||
luaData.getOrThrow(uid, "uid"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For this you need to Increase CampaignDataLoader::GetVersion()
I'd try to make this backwards compatible: and make the uid optional. Or check the version here (again) and make sure the uid is empty for older versions and non-empty otherwise.
Then you can revert the changes to existing tests
Adds support for Roman-style (video) campaigns and the world campaign (video).
Fixed world campaign scripts to unlock the same continents as it was in S2.
Related to issues #1639 and #1177