Before the change campaign bonus selection screen had inconsistent
overflow behaviour for difficulty selection:
```
0 1 2 3 4 | available buttons: '-' to decrease
^ | '+' to increase
```
Before the change:
1. If we click '+' 5 times we will end up on difficulty=4 (ok, saturated).
2. If we click '-' 5 times we will end up on difficulty=1 (unexpected, wrap around).
After the change:
1. If we click '+' 5 times we will end up on difficulty=4 (saturated).
2. If we click '-' 5 times we will end up on difficulty=0 (saturated).
The inconsistency happens because `difficulty` variable has `ui8` type
and server uses `difficulty = vstd::abetween(difficulty, 0, 4)` to
implement the saturation.
For large positive values saturation works as expected:
vstd::abetween(difficulty=5, 0, 4) -> 4
For small values it does not:
vstd::abetween(difficulty=-1, 0, 4) -> 4
The change makes client to avoid using negative values.
Noticed use of uninitialized value when built vcmi with -fsanitize=undefined:
```
Established connection with
VCMI 0.99 b310f2e61e (server).
UUID: bab9a90d-7416-4566-8817-e367ffcac7c1
../vcmi-9999/client/lobby/SelectionTab.cpp:138:16:
runtime error: load of value 32717, which is not a valid value for type 'ESortBy'
/usr/lib/gcc/x86_64-pc-linux-gnu/12.0.0/include/g++-v12/tuple:190:4:
runtime error: load of value 32717, which is not a valid value for type 'ESortBy'
/usr/lib/gcc/x86_64-pc-linux-gnu/12.0.0/include/g++-v12/tuple:190:4:
runtime error: load of value 32717, which is not a valid value for type 'ESortBy'
```
Here (before the change) `SelectionTab()` used `generalSortingBy` before
first use:
```
SelectionTab::SelectionTab(ESelectionScreen Type) {
...
if(tabType != ESelectionScreen::campaignList)
{
...
ESortBy criteria = (ESortBy)i;
if(criteria == _name)
criteria = generalSortingBy;
buttonsSortBy.push_back(... std::bind(&SelectionTab::sortBy, this, criteria)));
...
}
...
switch(tabType)
{
case ESelectionScreen::newGame:
generalSortingBy = ESortBy::_name;
....
```
The change moves `generalSortingBy` initialization before first use.
Signed-off-by: Sergei Trofimovich <slyfox@gentoo.org>
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
Disabled the following (for MSVC only) that couldn't (or shouldn't) be fixed.
4003: not enough actual parameters for macro 'identifier'
4250: 'class1' : inherits 'class2::member' via dominance
4251: 'type' : class 'type1' needs to have dll-interface to be used by clients of class 'type2'
4275: non dll-interface class 'type1' used as base for dll-interface class 'type2'
Replaced const TBonusListPtr with TConstBonusListPtr where necessary
Replaced const std::shared_ptr<T> with std::shared_ptr<const T> where necessary.
Removed superfluous use of const.
Replaced const std::shared_ptr<T> with const std::shared_ptr<T> & in function parameters and ranged for-loops.
Scenario: In LoadGame Lobby screen, the difficulty toggle group is showing multiple choices, but actually only one valid is working.
The reason is, in the Lobby screen Initialization code will set the difficulty = 0, and each time the player changes a map in the selection, the toggle group control is not resetting the difficulty buttons to disabled state.
How fix:
Add a new method to ToggleGroup class: setSelectedOnly, which will disable all other buttons and then set the selected button.
Note:
During the game loading time, the client is loading the map, and send a NetPack to server: LobbySetMap, and send a NetPack to Interface: LobbyUpdateState.
In the LobbyUpdateState it sets the map difficulty.
On Android calling `SDL_RenderSetLogicalSize` with dimensions having a different aspect ratio than the screen will cause letterboxing with blinking garbage data in that areas (instead of having black bars). This is annoying and makes the game really hard to play.
This change will make sure that on Android `SDL_RenderSetLogicalSize` will always be called with dimensions where the aspect ratio is the same as the screen to make sure there is no letterboxing.
The only problem with this is that during drawing the adventure map nothing will clear out the areas that would have been letterboxes, so there is an added explicit clear screen command for `totalRedraw()`.
The changes are only applied to Android builds in order not to affect PC builds - but some changes, especially clearing the screen could be easily added to the PC builds as well
When winning the campaign there is a lock that waits for the old server to stop before allowing to continue with restarting the server. While the lock was released on PC builds as the server runs differently on Android this was missed making campaigns always hang the app when you win.
This change adds a new native method that can be called from the Android app to signal that the server has stopped, so the client can continue with requesting a new server and showing the new campaign scenatio screen.
Note: this change alone doesn't fix the bug but it's required for a fix on vcmi-android's side. It doesn't break anything and can be merged before the vcmi-android changes