1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Merge pull request #2887 from Laserlicht/campaign_improvement

campaign improvements
This commit is contained in:
Nordsoft91 2023-09-22 01:01:59 +02:00 committed by GitHub
commit ec582328b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 94 additions and 64 deletions

View File

@ -683,12 +683,19 @@ void CServerHandler::startCampaignScenario(std::shared_ptr<CampaignState> cs)
auto & epilogue = ourCampaign->scenario(*ourCampaign->lastScenario()).epilog;
auto finisher = [=]()
{
if(!ourCampaign->isCampaignFinished())
if(ourCampaign->campaignSet != "")
{
GH.windows().pushWindow(CMM);
GH.windows().pushWindow(CMM->menu);
CMM->openCampaignLobby(ourCampaign);
Settings entry = persistentStorage.write["completedCampaigns"][ourCampaign->getFilename()];
entry->Bool() = true;
}
GH.windows().pushWindow(CMM);
GH.windows().pushWindow(CMM->menu);
if(!ourCampaign->isCampaignFinished())
CMM->openCampaignLobby(ourCampaign);
else
CMM->openCampaignScreen(ourCampaign->campaignSet);
};
if(epilogue.hasPrologEpilog)
{

View File

@ -47,12 +47,12 @@
#include "../../lib/mapObjects/CGHeroInstance.h"
CCampaignScreen::CCampaignScreen(const JsonNode & config)
: CWindowObject(BORDERED)
CCampaignScreen::CCampaignScreen(const JsonNode & config, std::string name)
: CWindowObject(BORDERED), campaignSet(name)
{
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
for(const JsonNode & node : config["images"].Vector())
for(const JsonNode & node : config[name]["images"].Vector())
images.push_back(CMainMenu::createPicture(node));
if(!images.empty())
@ -63,14 +63,14 @@ CCampaignScreen::CCampaignScreen(const JsonNode & config)
pos = images[0]->pos; // fix height\width of this window
}
if(!config["exitbutton"].isNull())
if(!config[name]["exitbutton"].isNull())
{
buttonBack = createExitButton(config["exitbutton"]);
buttonBack = createExitButton(config[name]["exitbutton"]);
buttonBack->hoverable = true;
}
for(const JsonNode & node : config["items"].Vector())
campButtons.push_back(std::make_shared<CCampaignButton>(node));
for(const JsonNode & node : config[name]["items"].Vector())
campButtons.push_back(std::make_shared<CCampaignButton>(node, config, campaignSet));
}
void CCampaignScreen::activate()
@ -89,7 +89,8 @@ std::shared_ptr<CButton> CCampaignScreen::createExitButton(const JsonNode & butt
return std::make_shared<CButton>(Point((int)button["x"].Float(), (int)button["y"].Float()), AnimationPath::fromJson(button["name"]), help, [=](){ close();}, EShortcut::GLOBAL_CANCEL);
}
CCampaignScreen::CCampaignButton::CCampaignButton(const JsonNode & config)
CCampaignScreen::CCampaignButton::CCampaignButton(const JsonNode & config, const JsonNode & parentConfig, std::string campaignSet)
: campaignSet(campaignSet)
{
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
@ -101,11 +102,27 @@ CCampaignScreen::CCampaignButton::CCampaignButton(const JsonNode & config)
campFile = config["file"].String();
video = VideoPath::fromJson(config["video"]);
status = config["open"].Bool() ? CCampaignScreen::ENABLED : CCampaignScreen::DISABLED;
status = CCampaignScreen::ENABLED;
auto header = CampaignHandler::getHeader(campFile);
hoverText = header->getName();
if(persistentStorage["completedCampaigns"][header->getFilename()].Bool())
status = CCampaignScreen::COMPLETED;
for(const JsonNode & node : parentConfig[campaignSet]["items"].Vector())
{
for(const JsonNode & requirement : config["requires"].Vector())
{
if(node["id"].Integer() == requirement.Integer())
if(!persistentStorage["completedCampaigns"][node["file"].String()].Bool())
status = CCampaignScreen::DISABLED;
}
}
if(persistentStorage["unlockAllCampaigns"].Bool())
status = CCampaignScreen::ENABLED;
if(status != CCampaignScreen::DISABLED)
{
addUsedEvents(LCLICK | HOVER);
@ -134,7 +151,7 @@ void CCampaignScreen::CCampaignButton::show(Canvas & to)
void CCampaignScreen::CCampaignButton::clickReleased(const Point & cursorPosition)
{
CCS->videoh->close();
CMainMenu::openCampaignLobby(campFile);
CMainMenu::openCampaignLobby(campFile, campaignSet);
}
void CCampaignScreen::CCampaignButton::hover(bool on)

View File

@ -40,14 +40,18 @@ private:
VideoPath video; // the resource name of the video
std::string hoverText;
std::string campaignSet;
void clickReleased(const Point & cursorPosition) override;
void hover(bool on) override;
public:
CCampaignButton(const JsonNode & config);
CCampaignButton(const JsonNode & config, const JsonNode & parentConfig, std::string campaignSet);
void show(Canvas & to) override;
};
std::string campaignSet;
std::vector<std::shared_ptr<CCampaignButton>> campButtons;
std::vector<std::shared_ptr<CPicture>> images;
std::shared_ptr<CButton> buttonBack;
@ -55,9 +59,7 @@ private:
std::shared_ptr<CButton> createExitButton(const JsonNode & button);
public:
enum CampaignSet {ROE, AB, SOD, WOG};
CCampaignScreen(const JsonNode & config);
CCampaignScreen(const JsonNode & config, std::string campaignSet);
void activate() override;
};

View File

@ -349,9 +349,10 @@ void CMainMenu::openLobby(ESelectionScreen screenType, bool host, const std::vec
GH.windows().createAndPushWindow<CSimpleJoinScreen>(host);
}
void CMainMenu::openCampaignLobby(const std::string & campaignFileName)
void CMainMenu::openCampaignLobby(const std::string & campaignFileName, std::string campaignSet)
{
auto ourCampaign = CampaignHandler::getCampaign(campaignFileName);
ourCampaign->campaignSet = campaignSet;
openCampaignLobby(ourCampaign);
}
@ -367,7 +368,7 @@ void CMainMenu::openCampaignScreen(std::string name)
{
if(vstd::contains(CMainMenuConfig::get().getCampaigns().Struct(), name))
{
GH.windows().createAndPushWindow<CCampaignScreen>(CMainMenuConfig::get().getCampaigns()[name]);
GH.windows().createAndPushWindow<CCampaignScreen>(CMainMenuConfig::get().getCampaigns(), name);
return;
}
logGlobal->error("Unknown campaign set: %s", name);

View File

@ -149,7 +149,7 @@ public:
void onScreenResize() override;
void update() override;
static void openLobby(ESelectionScreen screenType, bool host, const std::vector<std::string> * names, ELoadMode loadMode);
static void openCampaignLobby(const std::string & campaignFileName);
static void openCampaignLobby(const std::string & campaignFileName, std::string campaignSet = "");
static void openCampaignLobby(std::shared_ptr<CampaignState> campaign);
static void startTutorial();
void openCampaignScreen(std::string name);

View File

@ -5,13 +5,13 @@
"exitbutton" : {"x": 658, "y": 482, "name":"CMPSCAN" },
"items":
[
{ "x":90, "y":72, "file":"DATA/GOOD1.H3C", "image":"CAMPGD1S", "video":"CGOOD1", "open": true },
{ "x":539, "y":72, "file":"DATA/EVIL1.H3C", "image":"CAMPEV1S", "video":"CEVIL1", "open": true },
{ "x":43, "y":245, "file":"DATA/GOOD2.H3C", "image":"CAMPGD2S", "video":"CGOOD2", "open": true },
{ "x":313, "y":244, "file":"DATA/NEUTRAL1.H3C", "image":"CAMPNEUS", "video":"CNEUTRAL", "open": true },
{ "x":586, "y":246, "file":"DATA/EVIL2.H3C", "image":"CAMPEV2S", "video":"CEVIL2", "open": true },
{ "x":34, "y":417, "file":"DATA/GOOD3.H3C", "image":"CAMPGD3S", "video":"CGOOD3", "open": true },
{ "x":404, "y":414, "file":"DATA/SECRET1.H3C", "image":"CAMPSCTS", "video":"CSECRET", "open": true }
{ "id": 1, "x":90, "y":72, "file":"DATA/GOOD1", "image":"CAMPGD1S", "video":"CGOOD1", "requires": [] },
{ "id": 2, "x":539, "y":72, "file":"DATA/EVIL1", "image":"CAMPEV1S", "video":"CEVIL1", "requires": [] },
{ "id": 3, "x":43, "y":245, "file":"DATA/GOOD2", "image":"CAMPGD2S", "video":"CGOOD2", "requires": [1, 2, 4] },
{ "id": 4, "x":313, "y":244, "file":"DATA/NEUTRAL1", "image":"CAMPNEUS", "video":"CNEUTRAL", "requires": [] },
{ "id": 5, "x":586, "y":246, "file":"DATA/EVIL2", "image":"CAMPEV2S", "video":"CEVIL2", "requires": [1, 2, 4] },
{ "id": 6, "x":34, "y":417, "file":"DATA/GOOD3", "image":"CAMPGD3S", "video":"CGOOD3", "requires": [3, 5] },
{ "id": 7, "x":404, "y":414, "file":"DATA/SECRET1", "image":"CAMPSCTS", "video":"CSECRET", "requires": [6] }
]
},
"ab" :
@ -25,12 +25,12 @@
"exitbutton" : {"x": 658, "y": 482, "name":"CMPSCAN" },
"items":
[
{ "x":90, "y":72, "file":"DATA/AB.H3C", "image":"CAMP1AB7", "video":"C1ab7", "open": true },
{ "x":539, "y":72, "file":"DATA/BLOOD.H3C", "image":"CAMP1DB2", "video":"C1db2", "open": true },
{ "x":43, "y":245, "file":"DATA/SLAYER.H3C", "image":"CAMP1DS1", "video":"C1ds1", "open": true },
{ "x":313, "y":244, "file":"DATA/FESTIVAL.H3C", "image":"CAMP1FL3", "video":"C1fl3", "open": true },
{ "x":586, "y":246, "file":"DATA/FIRE.H3C", "image":"CAMP1PF2", "video":"C1pf2", "open": true },
{ "x":34, "y":417, "file":"DATA/FOOL.H3C", "image":"CAMP1FW1", "video":"C1fw1", "open": true }
{ "id": 1, "x":90, "y":72, "file":"DATA/AB", "image":"CAMP1AB7", "video":"C1ab7", "requires": [] },
{ "id": 2, "x":539, "y":72, "file":"DATA/BLOOD", "image":"CAMP1DB2", "video":"C1db2", "requires": [] },
{ "id": 3, "x":43, "y":245, "file":"DATA/SLAYER", "image":"CAMP1DS1", "video":"C1ds1", "requires": [] },
{ "id": 4, "x":313, "y":244, "file":"DATA/FESTIVAL", "image":"CAMP1FL3", "video":"C1fl3", "requires": [] },
{ "id": 5, "x":586, "y":246, "file":"DATA/FIRE", "image":"CAMP1PF2", "video":"C1pf2", "requires": [] },
{ "id": 6, "x":34, "y":417, "file":"DATA/FOOL", "image":"CAMP1FW1", "video":"C1fw1", "requires": [1, 2, 3, 4, 5] }
]
},
"sod":
@ -39,26 +39,13 @@
"exitbutton" : {"x": 658, "y": 482, "name":"CMPSCAN" },
"items":
[
{ "x":90, "y":72, "file":"DATA/GEM.H3C", "image":"CAMPNB1", "video":"NEW", "open": true },
{ "x":539, "y":72, "file":"DATA/GELU.H3C", "image":"CAMPEL1", "video":"ELIXIR", "open": true },
{ "x":43, "y":245, "file":"DATA/CRAG.H3C", "image":"CAMPHS1", "video":"HACK", "open": true },
{ "x":313, "y":244, "file":"DATA/SANDRO.H3C", "image":"CAMPRN1", "video":"RISE", "open": true },
{ "x":586, "y":246, "file":"DATA/YOG.H3C", "image":"CAMPBB1", "video":"BIRTH", "open": true },
{ "x":34, "y":417, "file":"DATA/FINAL.H3C", "image":"CAMPUA1", "video":"UNHOLY", "open": true },
{ "x":404, "y":414, "file":"DATA/SECRET.H3C", "image":"CAMPSP1", "video":"SPECTRE", "open": true }
{ "id": 1, "x":90, "y":72, "file":"DATA/GEM", "image":"CAMPNB1", "video":"NEW", "requires": [] },
{ "id": 2, "x":539, "y":72, "file":"DATA/GELU", "image":"CAMPEL1", "video":"ELIXIR", "requires": [] },
{ "id": 3, "x":43, "y":245, "file":"DATA/CRAG", "image":"CAMPHS1", "video":"HACK", "requires": [] },
{ "id": 4, "x":313, "y":244, "file":"DATA/SANDRO", "image":"CAMPRN1", "video":"RISE", "requires": [1, 2, 3, 5] },
{ "id": 5, "x":586, "y":246, "file":"DATA/YOG", "image":"CAMPBB1", "video":"BIRTH", "requires": [] },
{ "id": 6, "x":34, "y":417, "file":"DATA/FINAL", "image":"CAMPUA1", "video":"UNHOLY", "requires": [4] },
{ "id": 7, "x":404, "y":414, "file":"DATA/SECRET", "image":"CAMPSP1", "video":"SPECTRE", "requires": [6] }
]
}
// "wog" :
// {
// /// wog campaigns, currently has no assigned button in campaign screen and thus unused
// "images" : [ {"x": 0, "y": 0, "name":"CAMPZALL"} ],
// "exitbutton" : {"x": 658, "y": 482, "name":"CMPSCAN", "hotkey" : 27},
// "items":
// [
// { "x":90, "y":72, "file":"DATA/ZC1.H3C", "image":"CAMPZ01", "open": true},
// { "x":539, "y":72, "file":"DATA/ZC2.H3C", "image":"CAMPZ02", "open": true},
// { "x":43, "y":245, "file":"DATA/ZC3.H3C", "image":"CAMPZ03", "open": true},
// { "x":311, "y":242, "file":"DATA/ZC4.H3C", "image":"CAMPZ04", "open": true}
// ]
// }
}

View File

@ -45,7 +45,7 @@ void MainWindow::load()
QDir::addSearchPath("icons", pathToQString(VCMIDirs::get().userDataPath() / "launcher" / "icons"));
#endif
settings.init();
settings.init("config/settings.json", "vcmi:settings");
}
void MainWindow::computeSidePanelSizes()

View File

@ -17,6 +17,7 @@
VCMI_LIB_NAMESPACE_BEGIN
SettingsStorage settings;
SettingsStorage persistentStorage;
template<typename Accessor>
SettingsStorage::NodeAccessor<Accessor>::NodeAccessor(SettingsStorage & _parent, std::vector<std::string> _path):
@ -53,18 +54,24 @@ SettingsStorage::SettingsStorage():
{
}
void SettingsStorage::init()
void SettingsStorage::init(const std::string & dataFilename, const std::string & schema)
{
JsonPath confName = JsonPath::builtin("config/settings.json");
this->dataFilename = dataFilename;
this->schema = schema;
JsonPath confName = JsonPath::builtin(dataFilename);
JsonUtils::assembleFromFiles(confName.getOriginalName()).swap(config);
// Probably new install. Create config file to save settings to
if (!CResourceHandler::get("local")->existsResource(confName))
CResourceHandler::get("local")->createResource("config/settings.json");
CResourceHandler::get("local")->createResource(dataFilename);
JsonUtils::maximize(config, "vcmi:settings");
JsonUtils::validate(config, "vcmi:settings", "settings");
if(!schema.empty())
{
JsonUtils::maximize(config, schema);
JsonUtils::validate(config, schema, "settings");
}
}
void SettingsStorage::invalidateNode(const std::vector<std::string> &changedPath)
@ -74,9 +81,10 @@ void SettingsStorage::invalidateNode(const std::vector<std::string> &changedPath
JsonNode savedConf = config;
savedConf.Struct().erase("session");
JsonUtils::minimize(savedConf, "vcmi:settings");
if(!schema.empty())
JsonUtils::minimize(savedConf, schema);
std::fstream file(CResourceHandler::get()->getResourceName(JsonPath::builtin("config/settings.json"))->c_str(), std::ofstream::out | std::ofstream::trunc);
std::fstream file(CResourceHandler::get()->getResourceName(JsonPath::builtin(dataFilename))->c_str(), std::ofstream::out | std::ofstream::trunc);
file << savedConf.toJson();
}

View File

@ -35,6 +35,9 @@ class DLL_LINKAGE SettingsStorage
std::set<SettingsListener*> listeners;
JsonNode config;
std::string dataFilename;
std::string schema;
JsonNode & getNode(const std::vector<std::string> & path);
// Calls all required listeners
@ -45,7 +48,7 @@ class DLL_LINKAGE SettingsStorage
public:
// Initialize config structure
SettingsStorage();
void init();
void init(const std::string & dataFilename, const std::string & schema);
// Get write access to config node at path
const NodeAccessor<Settings> write;
@ -113,5 +116,6 @@ public:
};
extern DLL_LINKAGE SettingsStorage settings;
extern DLL_LINKAGE SettingsStorage persistentStorage;
VCMI_LIB_NAMESPACE_END

View File

@ -52,7 +52,8 @@ DLL_LINKAGE void preinitDLL(CConsoleHandler * Console, bool onlyEssential, bool
console = Console;
VLC = new LibClasses();
VLC->loadFilesystem(extractArchives);
settings.init();
settings.init("config/settings.json", "vcmi:settings");
persistentStorage.init("config/persistentStorage.json", "");
VLC->loadModFilesystem(onlyEssential);
}

View File

@ -293,6 +293,8 @@ public:
static JsonNode crossoverSerialize(CGHeroInstance * hero);
static CGHeroInstance * crossoverDeserialize(const JsonNode & node, CMap * map);
std::string campaignSet;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<Campaign&>(*this);
@ -302,6 +304,7 @@ public:
h & mapsConquered;
h & currentMap;
h & chosenCampaignBonuses;
h & campaignSet;
}
};