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

Add priority field to zones, use in loot sorting. #79353

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

Stu33
Copy link
Contributor

@Stu33 Stu33 commented Jan 26, 2025

Summary

Features "Add priority field to zones, use in loot sorting."

Purpose of change

Sometimes there are multiple zones that might be valid to place an item into when sorting the loot or placing NPC items. The game already has a priority ordering by zone type (custom filter > special cases > specific category > default) but it doesn't always do what the player would like, particularly if there are multiple custom loot zones with filters that match the item. Adding a priority field to zones that the player can edit allows them to get items to go where they want them.

In the future a priority field would be useful for other zone-based activities as well, for example specifying the order in which an NPC should try to complete construction blueprints.

Describe the solution

Add a priority attribute to zones, defaulting to 0. Display it in the zone manager UI and allow it to be set there. The priority may be set to any positive or negative value within the range of an integer.

Use this priority field to select which zone loot is moved to if more than one zone is a suitable target for a loot sorting activity. Zones with higher priority are considered first, even if they would have been disregarded in the previous system (e.g. if you have a priority 1 default loot zone then even weapons will go there rather than to a weapon loot zone with priority 0).

Because this is implemented by changing the zone_manager::get_near_zone_type_for_item method, it also affects placement of NPC items in shop restocking, trade and drops as the result of NPC missions, but unless the player or another PR deliberately changes zone priorities from the default this will have no visible effect.

Describe alternatives you've considered

None. In previous games I have either under-used zones or carefully set up custom filter zones to avoid having more than one possible destination for an item in loot sorting.

Testing

  • Loaded and saved a pre-existing game. Observed that "priority":0 is stored for each zone in zones.json. Edited the priority of some zones, saved game and observed correct priority values stored in zones.json. Played for a while and noticed nothing wrong.
  • Tested the specific reproduction case noted below.
  • Tested having an NPC sort loot for multiple other zone setups.
  • Checked that the existing unit tests in clzones_test.cpp and zones_custom_test.cpp continue to pass.
  • Added new tests - sets named zone_containment and zone_sorting_priority in clzones_test.cpp.

One quick and easy case to demonstrate this, using this zipped save:
repro.zip

  • Existing behaviour:
    1. Load the saved game from the attached zip in the latest experimental build without this PR (ignore the unrelated warning message - it's a save from a slightly older build of the game).
    2. Ask the NPC standing next to you to sort the loot, then wait around until they're done.
    3. See that all of the emergency jackets and emergency blankets have been moved to the custom loot zone with filter "emergency", and nothing has gone in to the zone with filter "emergency blanket". Nothing has gone to the Default zone.
  • To test that priorities work:
    1. Load the save from the attached zip with this PR's changes applied.
    2. Open the zone manager, select the custom loot zone with filter "emergency blanket" and change its priority to 1 (or higher) using the new UI.
    3. Ask the NPC standing next to you to sort the loot, then wait around until they're done.
    4. See that the emergency blankets have moved to the "emergency blanket" zone, and emergency jackets have still gone to the "emergency" zone.
  • To test that negative priorities are treated as lower priority than the default:
    1. Load the save from the attached zip with this PR's changes applied.
    2. Select the custom loot zone with filter "emergency" and change its priority to -1 (or lower).
    3. Ask the NPC standing next to you to sort the loot, then wait around until they're done.
    4. See that the emergency blankets have moved to the "emergency blanket" zone, and emergency jackets have now gone to the Default zone.

Additional context

Examples of the changed zone manager:
zone_manager_example_1
zone_manager_example_2

New option to set priority in the zone editing menu:
zone_manager_edit_zone_ui

Popup to set the priority:
zone_manager_set_priority_dialog

Stu33 added 5 commits January 20, 2025 16:08
…placing loot. Update existing zone selection tests and add new ones to test the new functionality.
… one call to reduce repetition. Used this only in code already touched and tested by this PR for now.
@github-actions github-actions bot added NPC / Factions NPCs, AI, Speech, Factions, Ownership Code: Tests Measurement, self-control, statistics, balancing. [C++] Changes (can be) made in C++. Previously named `Code` <Enhancement / Feature> New features, or enhancements on existing new contributor labels Jan 26, 2025
@andrei8l
Copy link
Contributor

Why do you need a separate field for priority when you already have order in the list? Just make zones closer to the top take precedence, which IIRC is already the case within a type.

@Stu33
Copy link
Contributor Author

Stu33 commented Jan 26, 2025

Why do you need a separate field for priority when you already have order in the list? Just make zones closer to the top take precedence, which IIRC is already the case within a type.

To me the priority and positioning in the display are different concepts. I like to order the zones for display within the zone manager by world position so that I can find them more easily. I often have a daft number of zones.

But I'd be happy to drop the new field and just use order in the list instead if that's the consensus.

@Termineitor244
Copy link
Contributor

I'm in favor of separating zone order and priority, when I make the zones for my base I make them and organize them in order with their distance from one another, so that I can easily locate them.

@github-actions github-actions bot added json-styled JSON lint passed, label assigned by github actions astyled astyled PR, label is assigned by github actions labels Jan 27, 2025
@o175
Copy link
Contributor

o175 commented Jan 27, 2025

@Stu33 What do you think about viewing \ or even editing priorities from the main zone manager table?

@GuardianDll
Copy link
Member

Please resolve clang tidy errors

@Stu33
Copy link
Contributor Author

Stu33 commented Jan 27, 2025 via email

@GuardianDll
Copy link
Member

I personally think you may be better with moving zone stuff to imgui, it sound like having proper mouse and better UI would benefit it, and make your further work much easier

@GuardianDll
Copy link
Member

Was the issues raised in #35782 resolved?

@Stu33
Copy link
Contributor Author

Stu33 commented Jan 27, 2025 via email

@Stu33
Copy link
Contributor Author

Stu33 commented Jan 27, 2025 via email

@GuardianDll
Copy link
Member

Sure, i just point out that it would be easier for you to start with imgui and then expand it than the other way around; no issues finishing this and another PRs of yours before doing UI

@github-actions github-actions bot added the BasicBuildPassed This PR builds correctly, label assigned by github actions label Jan 27, 2025
@Stu33 Stu33 marked this pull request as draft January 27, 2025 20:48
@Stu33
Copy link
Contributor Author

Stu33 commented Jan 28, 2025

(TLDR; skip to the numbered list below and express a preference please?)

I can see a few ways to proceed. I wonder what anyone thinks is best? Given Kevin's comments on #35782, perhaps Kevin or someone else more familiar than me with plans to use zones in faction camps and other NPC activities could comment?

This change affects only the users of the zone_manager::get_near_zone_type_for_item() method, but like I said in the description that does include loot placement from NPC missions and trader goods placement as well as loot sorting activities.

The implementation before this PR did a search through LOOT_CUSTOM zones, then all LOOT_ITEM_GROUP zones, returning as soon as it found a matching zone within range. If none of those matched it would determine which zone types could match the item and search for near points in the caches for those zone types and matching faction in a specific priority order. Note at this point it just finds the best zone type ID, not the best point; the loot sorting activity then calls zone_manager::get_near to get the std::unordered_set of all points of a matching zone type within range, so there is no kind of priority applied between zones of the same type unless by accident of the implementation of std::unordered_set on a given platform. It's also going to do the exhaustive search through custom and item group zones even if the correct match ends up being a firewood zone, weapon zone or whatever.

My initial implementation instead did an exhaustive search through all zones, quickly skipping any that don't have a matching faction, are disabled or are lower priority than the best seen so far. Then it checked whether the zone's bounding rectangle was within range and whether the zone was a suitable destination. It does need to iterate through all zones rather than returning as soon as a match is found. I've done my best to keep that quick, but if there are large numbers of zones that are not custom or item group ones then it probably will be slower than the pre-existing code. Having determined the best zone ID and priority, it then calls an overload of zone_manager::get_near to make another search through all the zones and calculate covered point sets; I think this second call could be mostly optimised away by making the first search optionally collect covered points as it searches, or it could make some use of the point caches, but I didn't do that yet.

Possible solutions to allow this PR to proceed without hurting other uses of zones:

  1. Apply priority only to custom and item group zones, which the pre-existing code iterates exhaustively anyway.
  2. Restrict priority to a small range of values, and use those as part of the zone cache key alongside the currently used faction and zone ID.
  3. Separately cache priority ordered lists of the zones with priority greater and less than the default, and only exhaustively search the higher priority zones before using the pre-existing method for the default priority zones (then search less than default priority only if no default priority zone matches).
  4. Any other suggestions?

Presumably the non-default priority zones will just be user-added zones, so there won't be many of them. This means most of the extra caches in solution 2 and the priority ordered lists in 3 will be small. Option 1 is a much smaller change to the pre-existing code and I think is still better than having no priority control.

If nobody else has an opinion I'll go ahead and implement option 3 from that list. I think this will have minimal impact on existing uses that stick to default zone priority while allowing maximum flexibility for zones the player configures. But please tell me if you think differently or if this PR won't be accepted regardless of any of those choices.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
astyled astyled PR, label is assigned by github actions BasicBuildPassed This PR builds correctly, label assigned by github actions [C++] Changes (can be) made in C++. Previously named `Code` Code: Tests Measurement, self-control, statistics, balancing. <Enhancement / Feature> New features, or enhancements on existing json-styled JSON lint passed, label assigned by github actions new contributor NPC / Factions NPCs, AI, Speech, Factions, Ownership
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants