diff --git a/doc/PACKS.md b/doc/PACKS.md index 24631a5c..891016d2 100644 --- a/doc/PACKS.md +++ b/doc/PACKS.md @@ -329,6 +329,7 @@ Locations define drops on maps, rules to have them accessible as well as the loo { "name": "Area name", "short_name": "Area", // shorter version of name. currently unused + "access_resolver": "$func", // optional method to resolve access. overrides access_rules "access_rules": [ ",", ",", @@ -399,6 +400,11 @@ Locations define drops on maps, rules to have them accessible as well as the loo Each `map_location` is a square on the map and shows a popup with individual chests. **Rules:** +If access_resolver if provided or inherited for a section and starts with `$`, access_rules are ignored and the +provided global Lua function is called for each section instead of resolving access_rules. Useful for pure Lua logic. +The Lua function has to return one of AccessibilityLevel values. +If access_resolver is `""` (default), access_rules are resolved internally as described below. + Rules starting with `$` will call the lua function with that name, `@/
` will use the result of a different access rule, other rules will just look at items' `code` (runs ProviderCountForCode(rule)). For `$` rules, arguments can be supplied with `|`. `$test|a|b` will call `test("a","b")`. diff --git a/schema/packs/locations.json b/schema/packs/locations.json index 91f4e9b8..3c520c3a 100644 --- a/schema/packs/locations.json +++ b/schema/packs/locations.json @@ -37,6 +37,10 @@ "description": "Short version of name. Currently unused.", "type": "string" }, + "access_resolver": { + "description": "Optional method to resolve access. Use \"$func\" to call a Lua function with Section as argument that returns an AccessibilityLevel.", + "type": "string" + }, "access_rules": { "example": [ "rule1,rule2", @@ -146,6 +150,10 @@ "description": "Short version of name. Currently unused.", "type": "string" }, + "access_resolver": { + "description": "Optional method to resolve access for each section. Use \"$func\" to call a Lua function with Section as argument that returns an AccessibilityLevel. This value is inherited by children, empty string resets to default behavior.", + "type": "string" + }, "access_rules": { "example": [ "rule1,rule2", diff --git a/schema/packs/strict/locations.json b/schema/packs/strict/locations.json index 13693701..f5f64bdf 100644 --- a/schema/packs/strict/locations.json +++ b/schema/packs/strict/locations.json @@ -36,6 +36,10 @@ "description": "Short version of name. Currently unused.", "type": "string" }, + "access_resolver": { + "description": "Optional method to resolve access. Use \"$func\" to call a Lua function with Section as argument that returns an AccessibilityLevel.", + "type": "string" + }, "access_rules": { "example": [ "rule1,rule2", @@ -128,6 +132,10 @@ "description": "Short version of name. Currently unused.", "type": "string" }, + "access_resolver": { + "description": "Optional method to resolve access for each section. Use \"$func\" to call a Lua function with Section as argument that returns an AccessibilityLevel. This value is inherited by children, empty string resets to default behavior.", + "type": "string" + }, "access_rules": { "example": [ "rule1,rule2", diff --git a/src/core/location.cpp b/src/core/location.cpp index 23dc5099..75d0e1de 100644 --- a/src/core/location.cpp +++ b/src/core/location.cpp @@ -113,14 +113,14 @@ static bool parseRule(const json& v, std::list& rule, } -std::list Location::FromJSON(json& j, const std::list& parentLookup, const std::list< std::list >& prevAccessRules, const std::list< std::list >& prevVisibilityRules, const std::string& parentName, const std::string& closedImgR, const std::string& openedImgR, const std::string& overlayBackgroundR) +std::list Location::FromJSON(json& j, const std::list& parentLookup, const std::string& prevAccessResolver, const std::list< std::list >& prevAccessRules, const std::list< std::list >& prevVisibilityRules, const std::string& parentName, const std::string& closedImgR, const std::string& openedImgR, const std::string& overlayBackgroundR) { // TODO: sine we store all intermediate locations now, we could pass a parent to FromJSON instead of all arguments std::list locs; if (j.type() == json::value_t::array) { for (auto& v : j) { - for (auto& loc : FromJSON(v, parentLookup, prevAccessRules, prevVisibilityRules, parentName, closedImgR, openedImgR, overlayBackgroundR)) { + for (auto& loc : FromJSON(v, parentLookup, prevAccessResolver, prevAccessRules, prevVisibilityRules, parentName, closedImgR, openedImgR, overlayBackgroundR)) { locs.push_back(std::move(loc)); // TODO: move constructor } } @@ -159,9 +159,12 @@ std::list Location::FromJSON(json& j, const std::list& paren } } + const auto& parentAccesResolver = parentLocation ? parentLocation->getAccessResolver() : prevAccessResolver; const auto& parentAccessRules = parentLocation ? parentLocation->getAccessRules() : prevAccessRules; const auto& parentVisibilityRules = parentLocation ? parentLocation->getVisibilityRules() : prevVisibilityRules; + std::string accessResolver = to_string(j, "access_resolver", parentAccesResolver); + std::list< std::list > accessRules; if (j["access_rules"].is_array() && !j["access_rules"].empty()) { // TODO: merge code with Section's access rules @@ -220,6 +223,7 @@ std::list Location::FromJSON(json& j, const std::list& paren loc._name = name; loc._parentName = parentName; loc._id = loc._parentName.empty() ? loc._name : (loc._parentName + "/" + loc._name); + loc._accessResolver = accessResolver; loc._accessRules = accessRules; loc._visibilityRules = visibilityRules; if (j["map_locations"].is_array()) { @@ -239,7 +243,7 @@ std::list Location::FromJSON(json& j, const std::list& paren fprintf(stderr, "Location: bad section\n"); continue; } - loc._sections.push_back(LocationSection::FromJSON(v, loc._id, accessRules, visibilityRules, closedImg, openedImg, overlayBackground)); + loc._sections.push_back(LocationSection::FromJSON(v, loc._id, accessResolver, accessRules, visibilityRules, closedImg, openedImg, overlayBackground)); } } else if (!j["sections"].is_null()) { fprintf(stderr, "Location: invalid sections\n"); @@ -249,7 +253,7 @@ std::list Location::FromJSON(json& j, const std::list& paren if (j["children"].type() == json::value_t::array) { std::string fullname = parentName.empty() ? name : (parentName + "/" + name); - for (auto& loc : Location::FromJSON(j["children"], parentLookup, accessRules, visibilityRules, fullname, closedImg, openedImg, overlayBackground)) { + for (auto& loc : Location::FromJSON(j["children"], parentLookup, accessResolver, accessRules, visibilityRules, fullname, closedImg, openedImg, overlayBackground)) { locs.push_back(std::move(loc)); } } else if (j["children"].type() != json::value_t::null) { @@ -300,7 +304,7 @@ Location::MapLocation Location::MapLocation::FromJSON(json& j) } -LocationSection LocationSection::FromJSON(json& j, const std::string parentId, const std::list< std::list >& parentAccessRules, const std::list< std::list >& parentVisibilityRules, const std::string& closedImg, const std::string& openedImg, const std::string& overlayBackground) +LocationSection LocationSection::FromJSON(json& j, const std::string parentId, const std::string& parentAccessResolver, const std::list< std::list >& parentAccessRules, const std::list< std::list >& parentVisibilityRules, const std::string& closedImg, const std::string& openedImg, const std::string& overlayBackground) { // TODO: pass inherited values as parent instead LocationSection sec; @@ -316,6 +320,7 @@ LocationSection LocationSection::FromJSON(json& j, const std::string parentId, c sec._itemCount = sec._hostedItems.empty() && sec._ref.empty() ? 1 : 0; sec._itemCount = to_int(j["item_count"], sec._itemCount); bool nonEmpty = sec._itemCount > 0 || !sec._hostedItems.empty(); + sec._accessResolver = to_string(j, "access_resolver", parentAccessResolver); if (j["access_rules"].is_array() && !j["access_rules"].empty()) { // TODO: merge code with Location's access rules diff --git a/src/core/location.h b/src/core/location.h index b1dabd35..72003d3f 100644 --- a/src/core/location.h +++ b/src/core/location.h @@ -23,6 +23,7 @@ class LocationSection final : public LuaInterface { public: static LocationSection FromJSON(nlohmann::json& j, const std::string parentId, + const std::string& parentAccessResolver="", const std::list< std::list >& parentAccessRules={}, const std::list< std::list >& parentVisibilityRules={}, const std::string& closedImg="", const std::string& openedImg="", @@ -37,6 +38,7 @@ class LocationSection final : public LuaInterface { int _itemCount=0; int _itemCleared=0; std::list _hostedItems; + std::string _accessResolver; std::list< std::list > _accessRules; std::list< std::list > _visibilityRules; std::string _overlayBackground; @@ -44,6 +46,7 @@ class LocationSection final : public LuaInterface { public: // getters const std::string& getName() const { return _name; } + const std::string& getAccessResolver() const { return _accessResolver; } const std::list< std::list > getAccessRules() const { return _accessRules; } const std::list< std::list > getVisibilityRules() const { return _visibilityRules; } int getItemCount() const { return _itemCount; } @@ -95,6 +98,7 @@ class Location final : public LuaInterface { static std::list FromJSON(nlohmann::json& j, const std::list& parentLookup, + const std::string& parentAccessResolver="", const std::list< std::list >& parentAccessRules={}, const std::list< std::list >& parentVisibilityRules={}, const std::string& parentName="", const std::string& closedImg="", @@ -106,6 +110,7 @@ class Location final : public LuaInterface { std::string _id; std::list _mapLocations; std::list _sections; + std::string _accessResolver; // this is only used if referenced through @-RUles std::list< std::list > _accessRules; // this is only used if referenced through @-Rules std::list< std::list > _visibilityRules; public: @@ -115,6 +120,7 @@ class Location final : public LuaInterface { const std::list& getMapLocations() const { return _mapLocations; } std::list& getSections() { return _sections; } const std::list& getSections() const { return _sections; } + const std::string& getAccessResolver() const { return _accessResolver; } std::list< std::list >& getAccessRules() { return _accessRules; } const std::list< std::list >& getAccessRules() const { return _accessRules; } std::list< std::list >& getVisibilityRules() { return _visibilityRules; }