Building list filtering/sorting

AIAndy

Deity
Joined
Jun 8, 2011
Messages
3,428
This mod has a LOT of different buildings which is really overwhelming for new players and even experienced ones have difficulty finding the right building they want to build.
Better usability here adds more to the mod than new mechanics.

On Python UI side several buttons need to be placed above the building selection. Some which are on/off and allow to select filters and some for sorting of which only one can be active.
The main interface file is already ugly enough so I would suggest moving the filtering and sorting to the DLL, interfaced by a method call on the city class which passes filter and sort requests.
 
Sounds right to me...

I had a bit of a goal to put some buttons together for this sort of thing already. I'm just a little stuck working with the unfamiliar Gimp is all.
 
The Python UI currently sorts so that will need to be removed.

For units I would suggest the following filters on top of the build/can't build one
  • missionaries
  • CEOs and Guildsmen
  • Heroes
  • Non combat (grouped by type with sort order of some type)
  • Combat (grouped by type with sort order of some type)
  • Combat - land
  • Combat - sea
  • Combat - air

The last three may not be needed at all.
 
The Python UI currently sorts so that will need to be removed.
That part will need to be rewritten anyway to call the respective DLL functions.
I am currently tending towards storing the filter/sort state and the build lists resulting from it in a subobject of the city class.

For buildings the filters could be:
  • Hide buildable
  • Hide unbuildable
  • Hide National Wonder
  • Hide World Wonder
  • Hide Normal Buildings
  • Show only science contributing
  • Show only food contributing
  • Show only culture contributing
  • Show only gold contributing
  • Show only production contributing
  • Show only happiness contributing
  • Show only health contributing
  • Hide unhappiness contributing
  • Hide unhealthiness contributing
  • Show only military buildings (xp contributing, military production increasing)

Then sorted by actual science, food, culture, gold, production, happiness, health, building cost.
 
I have thought some more about it and here is the plan for the interface:
There will be some enums exposed to Python:
UnitFilterTypes
BuildingFilterTypes
UnitSortTypes
BuildingSortTypes
UnitGroupTypes
BuildingGroupTypes

Then some methods on the city class:
setUnitListFilter(UnitFilterType, bool) - Activates/deactivates a specific filter for this city
getUnitListFilter(UnitFilterType) returns bool - Returns if the specific filter is active for this city
setUnitListSorting(UnitSortType) - Sets the sorting for this city
getUnitListSorting() returns UnitSortType - Returns the active sorting for this city
setUnitListGrouping(UnitGroupType) - Sets the grouping for this city
getUnitListGrouping() returns UnitGroupType - Get the grouping for this city
getUnitListGroupNum() returns int - Returns the number of groups for this city
getUnitListNumByGroup(int) returns int - Returns the number of unit types in the passed group num
getUnitListType(int group, int pos) returns UnitType - Returns the unit type at position in group

The same for buildings.
 
That part will need to be rewritten anyway to call the respective DLL functions.
I am currently tending towards storing the filter/sort state and the build lists resulting from it in a subobject of the city class.

For buildings the filters could be:
  • Hide buildable
  • Hide unbuildable
  • Hide National Wonder
  • Hide World Wonder
  • Hide Normal Buildings
  • Show only science contributing
  • Show only food contributing
  • Show only culture contributing
  • Show only gold contributing
  • Show only production contributing
  • Show only happiness contributing
  • Show only health contributing
  • Hide unhappiness contributing
  • Hide unhealthiness contributing
  • Show only military buildings (xp contributing, military production increasing)

Then sorted by actual science, food, culture, gold, production, happiness, health, building cost.

You forgot:
  • Espionage
  • Culture
  • City defense (can lump city adjacent damage mods into this category too)
 
In the DLL the plan is to have a CvBuildingList class that has:
  • A city pointer storing the city to which it belongs
  • An array of bools storing the current setting for each filter type
  • The current sorting type
  • The current grouping type
  • A cached array of groups with an array of building types in each group
  • A bool that states if the cached list is valid

Filters are represented by a class derived from a base filter class which mainly has a method that given a city and a building type returns if it should be in the list or filtered out.
Groupings are represented in the same way but the method returns an int that should be the same for all buildings belonging to the same category and the order of the ints should represent the ordering of the groups.
Sortings are represented in the same way but the method sorts the given buildings vector.

The same for unit types.

Each city object has an instance of the two classes as a member.
 
Rather than establishing all these filters on a button basis then, wouldn't it be better to just give a filter drop box selection?

I also think Hide unbuildable, being an option in Bug under the C2C section already could have some consequences. I usually set it to Hide Unbuildable and Hide Replaceable already - We must be careful not to conflict with those options or to just write them into these city filters.

It would also be nice to make sure that whatever you leave a city filtering for is what you get when you go into another city until you change the filter again... I can see how it could get annoying having to select the filter every time but it still needs to be fluid.
 
Rather than establishing all these filters on a button basis then, wouldn't it be better to just give a filter drop box selection?

I also think Hide unbuildable, being an option in Bug under the C2C section already could have some consequences. I usually set it to Hide Unbuildable and Hide Replaceable already - We must be careful not to conflict with those options or to just write them into these city filters.

It would also be nice to make sure that whatever you leave a city filtering for is what you get when you go into another city until you change the filter again... I can see how it could get annoying having to select the filter every time but it still needs to be fluid.
The idea is to replace the options Bug has because the same filters are better applied on a case by case basis instead of once in a separate menu.

For filters you want buttons because often you don't want only one filter active but multiple and each of them are either on or off which does not suit a drop box. On the other hand for grouping and sorting a drop box would work well. I'll leave that to whoever adds the UI elements in Python.

The filter settings will be saved. The question is if it is better to save them by city or by player. Currently I tend to save them by city if you select an individual city and by player if you select multiple at once. That way the city which you use to build science buildings in will keep its science filter settings even when you use different filters for different cities.
 
I can see why and agree on both of your first points completely. Thanks for helping me see what you've got in mind and why there.

As for the settings... I'd like some of them saved by player because a lot of it is a matter of preference and some by city because while I may adjust the filters as I go through a city's development cycles, It would be good to be able to see what the last filter set was when I enter the city. Make sense? Is that possible to separate out?
 
The idea is to replace the options Bug has because the same filters are better applied on a case by case basis instead of once in a separate menu.

For filters you want buttons because often you don't want only one filter active but multiple and each of them are either on or off which does not suit a drop box. On the other hand for grouping and sorting a drop box would work well. I'll leave that to whoever adds the UI elements in Python.

The filter settings will be saved. The question is if it is better to save them by city or by player. Currently I tend to save them by city if you select an individual city and by player if you select multiple at once. That way the city which you use to build science buildings in will keep its science filter settings even when you use different filters for different cities.

We have both national and city options for worker actions available. I only use the national. I expect the same will be the case with building lists I am interested in.

I have given up trying to specialise cities in C2C. There is just no point as far as I can see with the combination of population requirements, cultural buildings available and heroes. This means I build almost every building in almost every city and don't worry about mounted units at all!
 
  • Show only science contributing
  • Show only food contributing
  • Show only culture contributing
  • Show only gold contributing
  • Show only production contributing
  • Show only happiness contributing
  • Show only health contributing
  • Hide unhappiness contributing
  • Hide unhealthiness contributing
  • Show only military buildings (xp contributing, military production increasing)

These seems the most logical when you want to find the building that gives the most of a particular stat.
 
I just committed the DLL part of the changes for building filtering, grouping and sorting.

These are the implemented filters:
Code:
enum BuildingFilterTypes
{
	NO_BUILDING_FILTER = -1,

	BUILDING_FILTER_HIDE_BUILDABLE,
	BUILDING_FILTER_HIDE_UNBUILDABLE,
	BUILDING_FILTER_HIDE_GREAT_WONDER,
	BUILDING_FILTER_HIDE_NATIONAL_WONDER,
	BUILDING_FILTER_HIDE_NORMAL,
	BUILDING_FILTER_SHOW_SCIENCE,
	BUILDING_FILTER_SHOW_FOOD,
	BUILDING_FILTER_SHOW_CULTURE,
	BUILDING_FILTER_SHOW_ESPIONAGE,
	BUILDING_FILTER_SHOW_GOLD,
	BUILDING_FILTER_SHOW_PRODUCTION,
	BUILDING_FILTER_SHOW_HAPPINESS,
	BUILDING_FILTER_SHOW_HEALTH,
	BUILDING_FILTER_SHOW_MILITARY,
	BUILDING_FILTER_SHOW_CITY_DEFENSE,
	BUILDING_FILTER_HIDE_UNHAPPINESS,
	BUILDING_FILTER_HIDE_UNHEALTHINESS
};

The grouping methods:
Code:
enum BuildingGroupingTypes
{
	NO_BUILDING_GROUPING = -1,

	BUILDING_GROUPING_SINGLE, // only one group
	BUILDING_GROUPING_WONDER_TYPE, // group by normal building, national wonder, team wonder, world wonder
	BUILDING_GROUPING_DOMAIN // group by military, city defense, other
};

The sorting methods:
Code:
enum BuildingSortTypes
{
	NO_BUILDING_SORT = -1,

	BUILDING_SORT_NAME,
	BUILDING_SORT_COST,
	BUILDING_SORT_SCIENCE,
	BUILDING_SORT_CULTURE,
	BUILDING_SORT_ESPIONAGE,
	BUILDING_SORT_GOLD,
	BUILDING_SORT_FOOD,
	BUILDING_SORT_PRODUCTION,
	BUILDING_SORT_HAPPINESS,
	BUILDING_SORT_HEALTH
};

The interface for city and player objects:
Code:
	void setBuildingListInvalid();
	bool getBuildingListFilterActive(BuildingFilterTypes eFilter);
	void setBuildingListFilterActive(BuildingFilterTypes eFilter, bool bActive);
	BuildingGroupingTypes getBuildingListGrouping();
	void setBuildingListGrouping(BuildingGroupingTypes eGrouping);
	BuildingSortTypes getBuildingListSorting();
	void setBuildingListSorting(BuildingSortTypes eSorting);
	int getBuildingListGroupNum();
	int getBuildingListNumInGroup(int iGroup);
	BuildingTypes getBuildingListType(int iGroup, int iPos);

Both the interfaces and the enums are exposed to Python.
You set the filters active that you want and can read the current state of the filters. Same for grouping and sorting, but only one is active for those at a time.
Then you read the result with the botton three methods (there are a number of groups and each group contains a number of buildings).

The next step is that someone adds some buttons to the Python UI.
 
Added widget type WidgetTypes.WIDGET_BUILDING_FILTER which given to a button toggles the filter type given in data1.
Some bugs are also fixed but there remains one in the sorting that I am not sure what the reason is yet so I deactivated the sorting for now.

I implemented some test buttons which you can see if you rename CvMainInterface_TestFilters.py to CvMainInterface.py
 
@AIAndy:

Your new code does not load saved games correctly. Instantiation of the building list for a city screws up when the city is read from the save file (run it DEBUG and asserts light up). I'm trying to fix it, and will push to SVN when I have done...

Edit - fixed
 
@AIAndy:

Your new code does not load saved games correctly. Instantiation of the building list for a city screws up when the city is read from the save file (run it DEBUG and asserts light up). I'm trying to fix it, and will push to SVN when I have done...

Edit - fixed
Thanks.
 
I have added some buttons and drop down menus to the main interface now.
That still needs proper buttons for all the filters. Many don't even have any yet although I am not entirely sure where to put them in the interface anyway. The buttons also don't show if they are activated or not currently.

I finally found the problem in the sorting code. That was a nasty one to find. STL Sort does not pass the comparison object by reference but instead copies it on each of its many calls to subfunctions and as I had never intended this object to be copied the first time one of the comparison objects was destroyed it also destroyed the subobjects and the access to their virtual methods got invalid.
Fixed with a wrapper class that is passed to sort.
 
Some more filter buttons added. I am really missing good button graphics though. Anyone up to making some?
 
Wow, great job, much appreciated!

I have 2 issues, though:

- The "hide unconstructable building" setting doesn´t work ("hide untrainable units" is fine).
- When I selected a unit the view automatically jumps to buildings. When I selected a building or a wonder then the views stays there (as it did in the past).
 
Wow, great job, much appreciated!

I have 2 issues, though:

- The "hide unconstructable building" setting doesn´t work ("hide untrainable units" is fine).
The leftmost of the filter buttons has that functionality now. I could change it to use the BUG setting as default.
- When I selected a unit the view automatically jumps to buildings. When I selected a building or a wonder then the views stays there (as it did in the past).
There are three buttons to the right of the unit/building list (they are not new but default BtS buttons). They govern what the list jumps to. Using the filters, sorting or grouping for buildings automatically switches to the building focus (otherwise it would always switch to the top with the default of unit focus).
I will change it so selecting a unit for training changes the focus to units.
 
Top Bottom