From 2008b5680e8c5016f28a1b1954f19a4106d18a18 Mon Sep 17 00:00:00 2001 From: John Wildkins Date: Sun, 5 Nov 2023 01:07:36 -0500 Subject: [PATCH 1/2] Base: add support for blueprint-locked recipes --- Plugins/Public/base_plugin/BuildModule.cpp | 24 +++- Plugins/Public/base_plugin/FactoryModule.cpp | 7 +- Plugins/Public/base_plugin/Main.cpp | 19 ++- Plugins/Public/base_plugin/Main.h | 8 ++ Plugins/Public/base_plugin/PlayerBase.cpp | 12 ++ Plugins/Public/base_plugin/PlayerCommands.cpp | 115 ++++++++++++++++++ 6 files changed, 177 insertions(+), 8 deletions(-) diff --git a/Plugins/Public/base_plugin/BuildModule.cpp b/Plugins/Public/base_plugin/BuildModule.cpp index 451f62d56..91c5ea587 100644 --- a/Plugins/Public/base_plugin/BuildModule.cpp +++ b/Plugins/Public/base_plugin/BuildModule.cpp @@ -28,12 +28,20 @@ wstring BuildModule::GetInfo(bool xml) uint good = i->first; uint quantity = i->second; + if (!quantity) + { + continue; + } + const GoodInfo* gi = GoodList::find_by_id(good); if (gi) { info += L" - " + stows(itos(quantity)) + L"x " + HkGetWStringFromIDS(gi->iIDSName); - if (base->HasMarketItem(good) < quantity) - info += L" [Out of stock]"; + uint has_quantity = base->HasMarketItem(good); + if (has_quantity < quantity) + { + info += L" [Only " + UIntToPrettyStr(has_quantity) + L" units available]"; + } info += L""; } } @@ -57,12 +65,20 @@ wstring BuildModule::GetInfo(bool xml) uint good = i->first; uint quantity = i->second; + if (!quantity) + { + continue; + } + const GoodInfo* gi = GoodList::find_by_id(good); if (gi) { info += stows(itos(quantity)) + L"x" + HkGetWStringFromIDS(gi->iIDSName) + L" "; - if (base->HasMarketItem(good) < quantity) - info += L" [Out of stock]"; + uint has_quantity = base->HasMarketItem(good); + if (has_quantity < quantity) + { + info += L" [Only " + UIntToPrettyStr(has_quantity) + L" units available]"; + } } } if (active_recipe.credit_cost) diff --git a/Plugins/Public/base_plugin/FactoryModule.cpp b/Plugins/Public/base_plugin/FactoryModule.cpp index 165de5479..dd20cbf0f 100644 --- a/Plugins/Public/base_plugin/FactoryModule.cpp +++ b/Plugins/Public/base_plugin/FactoryModule.cpp @@ -80,10 +80,11 @@ wstring FactoryModule::GetInfo(bool xml) const GoodInfo* gi = GoodList::find_by_id(good); if (gi) { - info += openLine + L"- " + stows(itos(quantity)) + L"x " + HkGetWStringFromIDS(gi->iIDSName); - if (quantity > 0 && base->HasMarketItem(good) < active_recipe.cooking_rate) + info += openLine + L"- " + stows(itos(quantity)) + L"x " + HkGetWStringFromIDS(gi->iIDSName); + uint has_quantity = base->HasMarketItem(good); + if (has_quantity < quantity) { - info += L" [Out of stock]"; + info += L" [Only " + UIntToPrettyStr(has_quantity) + L" units available]"; } } } diff --git a/Plugins/Public/base_plugin/Main.cpp b/Plugins/Public/base_plugin/Main.cpp index 561cf0782..c22e93f87 100644 --- a/Plugins/Public/base_plugin/Main.cpp +++ b/Plugins/Public/base_plugin/Main.cpp @@ -75,6 +75,7 @@ PLUGIN_RETURNCODE returncode; /// Global recipe map unordered_map recipeMap; +unordered_map blueprintMap; /// Maps of shortcut numbers to recipes to construct item. unordered_map> recipeCraftTypeNumberMap; @@ -83,6 +84,7 @@ unordered_map> factoryNicknameToCraftTypeMap; unordered_map moduleNameRecipeMap; unordered_map> craftListNumberModuleMap; unordered_set buildingCraftLists; +unordered_map blueprintRecipeMap; void AddFactoryRecipeToMaps(const RECIPE& recipe); void AddModuleRecipeToMaps(const RECIPE& recipe, const vector craft_types, const wstring& build_type, uint recipe_number); @@ -838,6 +840,11 @@ void LoadSettingsActual() { recipe.reqlevel = ini.get_value_int(0); } + else if (ini.is_value("unlocked_by")) + { + recipe.unlocked_by = CreateID(ini.get_value_string(0)); + blueprintMap.insert(make_pair(recipe.unlocked_by, ini.get_value_string(0))); + } else if (ini.is_value("affiliation_bonus")) { recipe.affiliationBonus[MakeId(ini.get_value_string(0))] = ini.get_value_float(1); @@ -1462,6 +1469,12 @@ bool UserCmd_Process(uint client, const wstring &args) PlayerCommands::BaseFacMod(client, args); return true; } + else if (args.find(L"/unlock") == 0) + { + returncode = SKIPPLUGINS_NOFUNCTIONCALL; + PlayerCommands::UnlockRecipe(client, args); + return true; + } else if (args.find(L"/base defmod") == 0) { returncode = SKIPPLUGINS_NOFUNCTIONCALL; @@ -3227,7 +3240,11 @@ void AddFactoryRecipeToMaps(const RECIPE& recipe) wstring recipeNameKey = ToLower(recipe.infotext); recipeMap[recipe.nickname] = recipe; recipeCraftTypeNumberMap[recipe.craft_type][recipe.shortcut_number] = recipe; - recipeCraftTypeNameMap[recipe.craft_type][recipeNameKey] = recipe; + recipeCraftTypeNameMap[recipe.craft_type][recipeNameKey] = recipe; + if (recipe.unlocked_by) + { + blueprintRecipeMap[recipe.unlocked_by] = recipe; + } } void AddModuleRecipeToMaps(const RECIPE& recipe, const vector craft_types, const wstring& build_type, uint recipe_number) diff --git a/Plugins/Public/base_plugin/Main.h b/Plugins/Public/base_plugin/Main.h index 9e8cfef79..b40945390 100644 --- a/Plugins/Public/base_plugin/Main.h +++ b/Plugins/Public/base_plugin/Main.h @@ -44,6 +44,8 @@ struct RECIPE vector> catalyst_workforce; uint credit_cost = 0; uint reqlevel = 0; + uint unlocked_by = 0; + string unlocked_by_nickname = ""; unordered_map affiliationBonus; }; @@ -424,6 +426,9 @@ class PlayerBase bool isCrewSupplied; map reservedCatalystMap; + + // List of blueprints that have been used to unlock recipes on this base + unordered_set available_blueprints; // The state of the shield bool isShieldOn; @@ -565,6 +570,7 @@ namespace PlayerCommands void BaseBuildMod(uint client, const wstring& args); void BaseBuildModDestroy(uint client, const wstring& args); void BaseFacMod(uint client, const wstring& args); + void UnlockRecipe(uint client, const wstring& args); void PopulateHelpMenus(); void BaseShieldMod(uint client, const wstring& args); void Bank(uint client, const wstring& args); @@ -623,6 +629,7 @@ extern int set_plugin_debug; /// Global recipe map extern unordered_map recipeMap; +extern unordered_map blueprintMap; /// Maps of shortcut numbers to recipes to construct item. extern unordered_map> recipeCraftTypeNumberMap; extern unordered_map> recipeCraftTypeNameMap; @@ -630,6 +637,7 @@ extern unordered_map> factoryNicknameToCraftTypeMap; extern unordered_map moduleNameRecipeMap; extern unordered_map> craftListNumberModuleMap; extern unordered_set buildingCraftLists; +extern unordered_map blueprintRecipeMap; struct REPAIR_ITEM { diff --git a/Plugins/Public/base_plugin/PlayerBase.cpp b/Plugins/Public/base_plugin/PlayerBase.cpp index 4894faebc..62864b0c9 100644 --- a/Plugins/Public/base_plugin/PlayerBase.cpp +++ b/Plugins/Public/base_plugin/PlayerBase.cpp @@ -413,6 +413,10 @@ void PlayerBase::Load() } passwords.emplace_back(bp); } + else if (ini.is_value("blueprint")) + { + available_blueprints.insert(CreateID(ini.get_value_string(0))); + } else if (ini.is_value("crew_supplied")) { isCrewSupplied = ini.get_value_bool(0); @@ -541,6 +545,14 @@ void PlayerBase::Save() fprintf(file, "commodity = %u, %u, %f, %u, %u, %u\n", i.first, i.second.quantity, i.second.price, i.second.min_stock, i.second.max_stock, int(i.second.is_public)); } + for (auto i : available_blueprints) + { + auto blueprint = blueprintMap.find(i); + if (blueprint != blueprintMap.end()) + { + fprintf(file, "blueprint = %s\n", blueprint->second.c_str()); + } + } fprintf(file, "defensemode = %u\n", defense_mode); for(auto& i : ally_tags) diff --git a/Plugins/Public/base_plugin/PlayerCommands.cpp b/Plugins/Public/base_plugin/PlayerCommands.cpp index 4a0771543..56e0e5b11 100644 --- a/Plugins/Public/base_plugin/PlayerCommands.cpp +++ b/Plugins/Public/base_plugin/PlayerCommands.cpp @@ -129,6 +129,10 @@ namespace PlayerCommands currentString += stows(itos(recipe.second.shortcut_number)); currentString += L" = "; currentString += recipe.second.infotext.c_str(); + if (recipe.second.unlocked_by) + { + currentString += L" (req. blueprint)"; + } generatedHelpStringList.emplace_back(currentString.c_str()); } return generatedHelpStringList; @@ -1368,6 +1372,111 @@ namespace PlayerCommands PrintUserCmdText(client, L"type: '/craft start dockmodule 1' or '/craft start dockmodule Docking Module'"); } + void UnlockRecipe(uint client, const wstring& args) + { + PlayerBase* base = GetPlayerBaseForClient(client); + + if (!checkBaseAdminAccess(base, client)) + { + return; + } + + wstring& cmd = GetParam(args, ' ', 1); + int bp = ToInt(cmd); + bool foundRecipe = false; + + if (bp) + { + uint counter = 1; + for (auto& i : base->market_items) + { + if (!blueprintRecipeMap.count(i.first)) + { + continue; + } + + if (base->available_blueprints.count(i.first)) + { + continue; + } + + const GoodInfo* gi = GoodList::find_by_id(i.first); + if (!gi) + { + continue; + } + + if (counter != bp) + { + counter++; + continue; + } + + if (base->HasMarketItem(i.first)) + { + foundRecipe = true; + base->RemoveMarketGood(i.first, 1); + base->available_blueprints.insert(i.first); + PrintUserCmdText(client, L"Blueprint %ls applied.", HkGetWStringFromIDS(gi->iIDSName).c_str()); + break; + } + } + if (!foundRecipe) + { + PrintUserCmdText(client, L"Selection invalid, item ID not found."); + } + } + else if (cmd == L"list") + { + uint counter = 1; + PrintUserCmdText(client, L"Available blueprints:"); + for (auto& i : base->market_items) + { + if (!blueprintRecipeMap.count(i.first)) + { + continue; + } + + if (base->available_blueprints.count(i.first)) + { + continue; + } + + const GoodInfo* gi = GoodList::find_by_id(i.first); + if (!gi) + { + continue; + } + + if (!base->HasMarketItem(i.first)) + { + continue; + } + + PrintUserCmdText(client, L"%| %u. %ls", counter, HkGetWStringFromIDS(gi->iIDSName).c_str()); + counter++; + } + } + else if (cmd == L"known") + { + PrintUserCmdText(client, L"Researched blueprints:"); + for (auto& i : base->available_blueprints) + { + const GoodInfo* gi = GoodList::find_by_id(i); + PrintUserCmdText(client, L"| %ls", HkGetWStringFromIDS(gi->iIDSName).c_str()); + } + } + else + { + PrintUserCmdText(client, L"ERR Invalid parameters"); + PrintUserCmdText(client, L"/unlock [list|known|]"); + PrintUserCmdText(client, L"| list - show available blueprints to consume"); + PrintUserCmdText(client, L"| known - show blueprints already researched"); + PrintUserCmdText(client, L"| - consume a blueprint and unlock the related recipe"); + } + + } + void BaseFacMod(uint client, const wstring& args) { PlayerBase* base = GetPlayerBaseForClient(client); @@ -1456,6 +1565,12 @@ namespace PlayerCommands { PrintUserCmdText(client, L"ERR Invalid recipe selected, for a list of valid recipes in selected craft list, use '/craft list %ls'", craftList.c_str()); return; + } + else if (recipe && recipe->unlocked_by && !base->available_blueprints.count(recipe->unlocked_by)) + { + PrintUserCmdText(client, L"ERR Recipe not discovered, for a list of valid recipes in selected craft list, use '/craft list %ls'", craftList.c_str()); + PrintUserCmdText(client, L"For a list of unlocked blueprints, use '/unlock known'"); + return; } if (cmd == L"info") From e12765426651387a74450e891f7dee3d4f514f3c Mon Sep 17 00:00:00 2001 From: John Wildkins Date: Wed, 15 Nov 2023 20:23:59 -0500 Subject: [PATCH 2/2] be naive, save da world --- Plugins/Public/base_plugin/PlayerBase.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Plugins/Public/base_plugin/PlayerBase.cpp b/Plugins/Public/base_plugin/PlayerBase.cpp index 62864b0c9..7cc0f4e8d 100644 --- a/Plugins/Public/base_plugin/PlayerBase.cpp +++ b/Plugins/Public/base_plugin/PlayerBase.cpp @@ -547,11 +547,7 @@ void PlayerBase::Save() } for (auto i : available_blueprints) { - auto blueprint = blueprintMap.find(i); - if (blueprint != blueprintMap.end()) - { - fprintf(file, "blueprint = %s\n", blueprint->second.c_str()); - } + fprintf(file, "blueprint = %s\n", blueprintMap.at(i).c_str()); } fprintf(file, "defensemode = %u\n", defense_mode);