Skip to content

Commit

Permalink
Allow free selection of cataclysm and game start dates in new charact…
Browse files Browse the repository at this point in the history
…er menu (CleverRaven#67772)

* Added UI element to select and return time point

+ utilized it in debug menu

* Reworked scenario calendar

- removed `random` calendar entries from scenarion definitions
- allowed free selection of cataclysm and game start dates in new character menu
- updated UI in new character menu
- fixed start date related tests
- updated docs
  • Loading branch information
ZhilkinSerg authored Aug 20, 2023
1 parent f3e6c7b commit 7f91d0c
Show file tree
Hide file tree
Showing 15 changed files with 322 additions and 663 deletions.
24 changes: 12 additions & 12 deletions data/json/scenarios.json
Original file line number Diff line number Diff line change
Expand Up @@ -521,8 +521,8 @@
"start_name": "Outside Town",
"surround_groups": [ [ "GROUP_BLACK_ROAD", 70.0 ] ],
"flags": [ "LONE_START" ],
"start_of_cataclysm": { "hour": 0, "day": 60, "season": "spring", "year": 1 },
"start_of_game": { "hour": "random", "day": "random", "season": "winter", "year": 1 },
"start_of_cataclysm": { "hour": 0, "day": 61, "season": "spring", "year": 1 },
"start_of_game": { "hour": 8, "day": 1, "season": "winter", "year": 1 },
"add_professions": true,
"professions": [ "sheltered_survivor", "sheltered_militia", "winter_scavenger", "winter_army" ],
"requirement": "achievement_survive_91_days"
Expand All @@ -547,8 +547,8 @@
],
"start_name": "Outside Town",
"flags": [ "LONE_START" ],
"start_of_cataclysm": { "hour": 0, "day": 60, "season": "spring", "year": 1 },
"start_of_game": { "hour": "random", "day": "random", "season": "summer", "year": 2 },
"start_of_cataclysm": { "hour": 0, "day": 61, "season": "spring", "year": 1 },
"start_of_game": { "hour": 8, "day": 1, "season": "summer", "year": 2 },
"add_professions": true,
"professions": [ "sheltered_survivor", "sheltered_militia", "winter_scavenger", "winter_army" ],
"requirement": "achievement_survive_91_days"
Expand All @@ -561,8 +561,8 @@
"description": "It's been a year since the apocalypse, and winter is fast approaching. You and your company have managed to gather up enough supplies to finally settle down somewhere, away from the death and destruction. Life has been hard for you, but in your heart you still hold a vision of a bright future lying ahead.",
"start_name": "Old Evac Shelter",
"allowed_locs": [ "sloc_shelter_a", "sloc_shelter_b", "sloc_shelter_c" ],
"start_of_cataclysm": { "hour": 0, "day": 60, "season": "spring", "year": 1 },
"start_of_game": { "hour": "random", "day": "random", "season": "autumn", "year": 2 },
"start_of_cataclysm": { "hour": 0, "day": 61, "season": "spring", "year": 1 },
"start_of_game": { "hour": 8, "day": 1, "season": "autumn", "year": 2 },
"add_professions": true,
"professions": [ "sheltered_survivor", "sheltered_militia", "winter_scavenger", "winter_army" ],
"requirement": "achievement_survive_91_days",
Expand All @@ -578,8 +578,8 @@
"allowed_locs": [ "sloc_lmoe_empty", "sloc_shelter_a", "sloc_shelter_b", "sloc_shelter_c" ],
"start_name": "Enclosed Shelter",
"flags": [ "LONE_START" ],
"start_of_cataclysm": { "hour": 0, "day": 60, "season": "spring", "year": 1 },
"start_of_game": { "hour": "random", "day": "random", "season": "winter", "year": 1 },
"start_of_cataclysm": { "hour": 0, "day": 61, "season": "spring", "year": 1 },
"start_of_game": { "hour": 8, "day": 1, "season": "winter", "year": 1 },
"professions": [ "sheltered_militia", "sheltered_survivor", "unemployed" ]
},
{
Expand Down Expand Up @@ -652,8 +652,8 @@
"requirement": "achievement_reach_mi-Go_encampment",
"reveal_locale": false,
"flags": [ "LONE_START", "CHALLENGE" ],
"start_of_cataclysm": { "hour": 0, "day": 60, "season": "spring", "year": 1 },
"start_of_game": { "hour": "random", "day": "random", "season": "winter", "year": 1 }
"start_of_cataclysm": { "hour": 0, "day": 61, "season": "spring", "year": 1 },
"start_of_game": { "hour": 8, "day": 1, "season": "winter", "year": 1 }
},
{
"type": "scenario",
Expand Down Expand Up @@ -1102,8 +1102,8 @@
"description": "You were camping in the wild to let things back home cool off. One night strange noises closed in on you and you were attacked. You managed to get away but can feel things moving in the dark.",
"id": "camp_attack_start",
"points": 0,
"start_of_cataclysm": { "hour": 0, "day": 60, "season": "spring", "year": 1 },
"start_of_game": { "hour": 1, "day": 60, "season": "spring", "year": 1 },
"start_of_cataclysm": { "hour": 0, "day": 61, "season": "spring", "year": 1 },
"start_of_game": { "hour": 1, "day": 61, "season": "spring", "year": 1 },
"start_name": "Wilderness",
"eoc": [ "scenario_surrounded_zombie_heavy" ],
"allowed_locs": [
Expand Down
6 changes: 4 additions & 2 deletions data/mods/Standard_Combat_Tests/modinfo.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
"professions": [ "sct_mid" ],
"map_extra": "mx_sct_mid",
"flags": [ "CITY_START", "LONE_START" ],
"start_of_game": { "hour": 8, "day": 45, "season": "summer" }
"start_of_cataclysm": { "hour": 0, "day": 61, "season": "spring", "year": 1 },
"start_of_game": { "hour": 8, "day": 45, "season": "summer", "year": 1 }
},
{
"type": "scenario",
Expand All @@ -50,7 +51,8 @@
"professions": [ "sct_late" ],
"map_extra": "mx_sct_late",
"flags": [ "CITY_START", "LONE_START" ],
"start_of_game": { "hour": 8, "day": 45, "season": "autumn" }
"start_of_cataclysm": { "hour": 0, "day": 61, "season": "spring", "year": 1 },
"start_of_game": { "hour": 8, "day": 45, "season": "autumn", "year": 1 }
},
{
"id": "mx_sct_day1",
Expand Down
48 changes: 5 additions & 43 deletions data/mods/TEST_DATA/scenarios.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
"allowed_locs": [ "sloc_shelter_a", "sloc_shelter_b", "sloc_shelter_c" ],
"start_name": "Evac Shelter",
"flags": [ "CITY_START" ],
"start_of_cataclysm": { "year": 1, "season": "spring", "day": 60, "hour": 0 },
"start_of_game": { "year": 4, "season": "summer", "day": 7, "hour": 18 }
"start_of_game": { "hour": 18, "day": 7, "season": "summer", "year": 4 }
},
{
"type": "scenario",
Expand All @@ -20,8 +19,7 @@
"allowed_locs": [ "sloc_shelter_a", "sloc_shelter_b", "sloc_shelter_c" ],
"start_name": "Evac Shelter",
"flags": [ "CITY_START" ],
"start_of_cataclysm": { "year": 1, "season": "spring", "day": 60, "hour": 0 },
"start_of_game": { "year": -1, "season": "spring", "day": 8, "hour": 3 }
"start_of_game": { "hour": 3, "day": 8, "season": "spring", "year": -1 }
},
{
"type": "scenario",
Expand All @@ -32,7 +30,7 @@
"allowed_locs": [ "sloc_shelter_a", "sloc_shelter_b", "sloc_shelter_c" ],
"start_name": "Evac Shelter",
"flags": [ "CITY_START" ],
"start_of_cataclysm": { "year": 7, "season": "autumn", "day": 9, "hour": 1 }
"start_of_cataclysm": { "hour": 1, "day": 9, "season": "autumn", "year": 7 }
},
{
"type": "scenario",
Expand All @@ -43,43 +41,7 @@
"allowed_locs": [ "sloc_shelter_a", "sloc_shelter_b", "sloc_shelter_c" ],
"start_name": "Evac Shelter",
"flags": [ "CITY_START" ],
"start_of_cataclysm": { "year": 6, "season": "winter", "day": 4, "hour": 6 },
"start_of_game": { "year": 9, "season": "autumn", "day": 19, "hour": 13 }
},
{
"type": "scenario",
"id": "test_random_hour",
"name": "Test random hour",
"points": 0,
"description": "Test starting on random hour.",
"allowed_locs": [ "sloc_shelter_a", "sloc_shelter_b", "sloc_shelter_c" ],
"start_name": "Evac Shelter",
"flags": [ "CITY_START" ],
"start_of_cataclysm": { "day": 60, "season": "spring", "year": 1, "hour": 0 },
"start_of_game": { "day": 0, "year": 1, "hour": "random", "season": "summer" }
},
{
"type": "scenario",
"id": "test_random_day",
"name": "Test random day",
"points": 0,
"description": "Test starting on random day.",
"allowed_locs": [ "sloc_shelter_a", "sloc_shelter_b", "sloc_shelter_c" ],
"start_name": "Evac Shelter",
"flags": [ "CITY_START" ],
"start_of_cataclysm": { "day": 60, "season": "spring", "year": 1, "hour": 0 },
"start_of_game": { "day": "random", "season": "summer", "year": 1, "hour": 8 }
},
{
"type": "scenario",
"id": "test_random_year",
"name": "Test random year",
"points": 0,
"description": "Test starting on random year.",
"allowed_locs": [ "sloc_shelter_a", "sloc_shelter_b", "sloc_shelter_c" ],
"start_name": "Evac Shelter",
"flags": [ "CITY_START" ],
"start_of_cataclysm": { "day": 60, "season": "spring", "year": 1, "hour": 0 },
"start_of_game": { "year": "random", "day": 60, "season": "summer", "hour": 8 }
"start_of_cataclysm": { "hour": 6, "day": 4, "season": "winter", "year": 6 },
"start_of_game": { "hour": 13, "day": 19, "season": "autumn", "year": 9 }
}
]
6 changes: 3 additions & 3 deletions data/mods/innawood/scenarios.json
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,8 @@
"start_name": "Outside Town",
"surround_groups": [ [ "GROUP_BLACK_ROAD", 70.0 ] ],
"flags": [ "LONE_START" ],
"start_of_cataclysm": { "hour": 0, "day": 60, "season": "spring", "year": 1 },
"start_of_game": { "day": "random", "hour": "random", "season": "winter", "year": 1 },
"start_of_cataclysm": { "hour": 0, "day": 61, "season": "spring", "year": 1 },
"start_of_game": { "hour": 8, "day": 1, "season": "winter", "year": 1 },
"professions": [
"svictim",
"naked",
Expand Down Expand Up @@ -302,7 +302,7 @@
"allowed_locs": [ "sloc_field", "sloc_forest", "sloc_desert_island", "sloc_river" ],
"start_name": "Outside Town",
"flags": [ "LONE_START" ],
"start_of_cataclysm": { "hour": 0, "day": 60, "season": "spring", "year": 1 },
"start_of_cataclysm": { "hour": 0, "day": 61, "season": "spring", "year": 1 },
"start_of_game": { "hour": 8, "day": 1, "season": "summer", "year": 2 },
"professions": [
"svictim",
Expand Down
52 changes: 33 additions & 19 deletions data/raw/keybindings.json
Original file line number Diff line number Diff line change
Expand Up @@ -1526,6 +1526,27 @@
{ "input_method": "keyboard_code", "key": "8", "mod": [ "shift" ] }
]
},
{
"type": "keybinding",
"id": "CHANGE_START_OF_CATACLYSM",
"category": "NEW_CHAR_DESCRIPTION",
"name": "Change cataclysm start date",
"bindings": [ { "input_method": "keyboard_char", "key": "%" }, { "input_method": "keyboard_code", "key": "5", "mod": [ "shift" ] } ]
},
{
"type": "keybinding",
"id": "CHANGE_START_OF_GAME",
"category": "NEW_CHAR_DESCRIPTION",
"name": "Change game start date",
"bindings": [ { "input_method": "keyboard_char", "key": "^" }, { "input_method": "keyboard_code", "key": "6", "mod": [ "shift" ] } ]
},
{
"type": "keybinding",
"id": "RESET_CALENDAR",
"category": "NEW_CHAR_DESCRIPTION",
"name": "Reset scenario calendar",
"bindings": [ { "input_method": "keyboard_char", "key": "$" }, { "input_method": "keyboard_code", "key": "4", "mod": [ "shift" ] } ]
},
{
"type": "keybinding",
"id": "CHOOSE_CITY",
Expand Down Expand Up @@ -1579,38 +1600,31 @@
},
{
"type": "keybinding",
"id": "RANDOMIZE_SCENARIO_START_OF_CATACLYSM",
"category": "NEW_CHAR_SCENARIOS",
"name": "Randomize cataclysm start date (if supported by scenario)",
"bindings": [ { "input_method": "keyboard_char", "key": "^" }, { "input_method": "keyboard_code", "key": "6", "mod": [ "shift" ] } ]
},
{
"type": "keybinding",
"id": "RANDOMIZE_SCENARIO_START_OF_GAME",
"id": "SORT",
"category": "NEW_CHAR_SCENARIOS",
"name": "Randomize game start date (if supported by scenario)",
"bindings": [ { "input_method": "keyboard_char", "key": "&" }, { "input_method": "keyboard_code", "key": "7", "mod": [ "shift" ] } ]
"name": "Toggle sorting order",
"bindings": [ { "input_method": "keyboard_any", "key": "s" } ]
},
{
"type": "keybinding",
"id": "RESET_SCENARIO_START_OF_CATACLYSM",
"id": "CHANGE_START_OF_CATACLYSM",
"category": "NEW_CHAR_SCENARIOS",
"name": "Reset cataclysm start date",
"bindings": [ { "input_method": "keyboard_char", "key": "$" }, { "input_method": "keyboard_code", "key": "4", "mod": [ "shift" ] } ]
"name": "Change cataclysm start date",
"bindings": [ { "input_method": "keyboard_char", "key": "%" }, { "input_method": "keyboard_code", "key": "5", "mod": [ "shift" ] } ]
},
{
"type": "keybinding",
"id": "RESET_SCENARIO_START_OF_GAME",
"id": "CHANGE_START_OF_GAME",
"category": "NEW_CHAR_SCENARIOS",
"name": "Reset game start date",
"bindings": [ { "input_method": "keyboard_char", "key": "%" }, { "input_method": "keyboard_code", "key": "5", "mod": [ "shift" ] } ]
"name": "Change game start date",
"bindings": [ { "input_method": "keyboard_char", "key": "^" }, { "input_method": "keyboard_code", "key": "6", "mod": [ "shift" ] } ]
},
{
"type": "keybinding",
"id": "SORT",
"id": "RESET_CALENDAR",
"category": "NEW_CHAR_SCENARIOS",
"name": "Toggle sorting order",
"bindings": [ { "input_method": "keyboard_any", "key": "s" } ]
"name": "Reset scenario calendar",
"bindings": [ { "input_method": "keyboard_char", "key": "$" }, { "input_method": "keyboard_code", "key": "4", "mod": [ "shift" ] } ]
},
{
"type": "keybinding",
Expand Down
26 changes: 13 additions & 13 deletions doc/JSON_INFO.md
Original file line number Diff line number Diff line change
Expand Up @@ -5330,36 +5330,36 @@ A list of mission ids that will be started and assigned to the player at the sta
## `start_of_cataclysm`
(optional, object with optional members "hour", "day", "season" and "year")

Allows customization of cataclysm start date. If `start_of_cataclysm` is not set the corresponding default values are used instead - 0 hour, 60 day (which is day 61), Spring season, 1 year. By default this date be randomized in new character creation screen.
Allows customization of cataclysm start date. If `start_of_cataclysm` is not set the corresponding default values are used instead - `Year 1, Spring, Day 61, 00:00:00`. Can be changed in new character creation screen.

```C++
"start_of_cataclysm": { "hour": "random", "day": 10, "season": "winter", "year": 1 }
"start_of_cataclysm": { "hour": 7, "day": 10, "season": "winter", "year": 1 }
```
Identifier | Description
--- | ---
`hour` | (optional, integer or `random` string) Hour of the day. Default value is 0. String `random` randomizes 0-23.
`day` | (optional, integer or `random` string) Day of the season. Default value is 60 (which is day 61). String `random` randomizes 0-season length.
`season` | (optional, integer or `random` string) Season of the year. Default value is `spring`. String `random` randomizes to one of 4 season.
`year` | (optional, integer or `random` string) Year. Default value is 1. String `random` randomizes 1-11.
`hour` | (optional, integer) Hour of the day. Default value is 0.
`day` | (optional, integer) Day of the season. Default value is 61.
`season` | (optional, integer) Season of the year. Default value is `spring`.
`year` | (optional, integer) Year. Default value is 1.
## `start_of_game`
(optional, object with optional members "hour", "day", "season" and "year")
Allows customization of game start date. If `start_of_game` is not set the corresponding default values are used instead - random hour (0-23), 60 day (which is day 61), Spring season, 1 year. By default hour part of this date can be randomized in new character creation screen.
Allows customization of game start date. If `start_of_game` is not set the corresponding default values are used instead - `Year 1, Spring, Day 61, 08:00:00`. Can be changed in new character creation screen.
If the scenario game start date is before the scenario cataclysm start date then the scenario game start would be automatically set to scenario cataclysm start date.
**Attention**: Game start date is automatically adjusted, so it is not before the cataclysm start date.
```C++
"start_of_game": { "hour": "random", "day": "random", "season": "winter", "year": 2 }
"start_of_game": { "hour": 8, "day": 16, "season": "winter", "year": 2 }
```

Identifier | Description
--- | ---
`hour` | (optional, integer or `random` string) Hour of the day. Default value is 8. String `random` randomizes 0-23.
`day` | (optional, integer or `random` string) Day of the season. Default value is 60 (which is day 61). String `random` randomizes 0-season length.
`season` | (optional, integer or `random` string) Season of the year. Default value is `spring`. String `random` randomizes to one of 4 season.
`year` | (optional, integer or `random` string) Year. Default value is 1. String `random` randomizes 1-11.
`hour` | (optional, integer) Hour of the day. Default value is 8.
`day` | (optional, integer) Day of the season. Default value is 61.
`season` | (optional, integer) Season of the year. Default value is `spring`.
`year` | (optional, integer) Year. Default value is 1.

# Starting locations

Expand Down
80 changes: 80 additions & 0 deletions src/calendar_ui.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#include "calendar_ui.h"

#include "string_formatter.h"
#include "string_input_popup.h"
#include "ui.h"
#include "ui_manager.h"

time_point calendar_ui::select_time_point( time_point initial_value, std::string_view title )
{
time_point return_value = initial_value;
auto set_turn = [&]( const int initial, const time_duration & factor, const char *const msg ) {
string_input_popup pop;
const int new_value = pop
.title( msg )
.width( 20 )
.text( std::to_string( initial ) )
.only_digits( true )
.query_int();
if( pop.canceled() ) {
return;
}
const time_duration offset = ( new_value - initial ) * factor;
// Arbitrary maximal value.
const time_point max = calendar::turn_zero + time_duration::from_turns(
std::numeric_limits<int>::max() / 2 );
return_value = std::max( std::min( max, return_value + offset ), calendar::turn_zero );
};

uilist smenu;
static const auto years = []( const time_point & p ) {
return static_cast<int>( ( p - calendar::turn_zero ) / calendar::year_length() );
};
do {
const int iSel = smenu.ret;
smenu.reset();
smenu.title = title;
smenu.text += string_format( "Old date: %1$s\nNew date: %2$s",
colorize( to_string( initial_value ), c_light_red ),
colorize( to_string( return_value ), c_light_cyan ) );
smenu.desc_enabled = true;
smenu.footer_text = string_format( _( "Press <color_light_green>%s</color> when done" ),
input_context( smenu.input_category ).get_desc( "UILIST.QUIT" ) );
smenu.addentry( 0, true, 'y', "%s: %d", _( "year" ), years( return_value ) + 1 );
smenu.addentry( 1, !calendar::eternal_season(), 's', "%s: %d",
_( "season" ), static_cast<int>( season_of_year( return_value ) ) );
smenu.addentry( 2, true, 'd', "%s: %d", _( "day" ), day_of_season<int>( return_value ) + 1 );
smenu.addentry( 3, true, 'h', "%s: %d", _( "hour" ), hour_of_day<int>( return_value ) );
smenu.addentry( 4, true, 'm', "%s: %d", _( "minute" ), minute_of_hour<int>( return_value ) );
smenu.addentry( 5, true, 't', "%s: %d", _( "turn" ),
to_turns<int>( return_value - calendar::turn_zero ) );
smenu.selected = iSel;
smenu.query();

switch( smenu.ret ) {
case 0:
set_turn( years( return_value ) + 1, calendar::year_length(), _( "Set year to?" ) );
break;
case 1:
set_turn( static_cast<int>( season_of_year( return_value ) ), calendar::season_length(),
_( "Set season to? (0 = spring)" ) );
break;
case 2:
set_turn( day_of_season<int>( return_value ) + 1, 1_days, _( "Set days to?" ) );
break;
case 3:
set_turn( hour_of_day<int>( return_value ), 1_hours, _( "Set hour to?" ) );
break;
case 4:
set_turn( minute_of_hour<int>( return_value ), 1_minutes, _( "Set minute to?" ) );
break;
case 5:
set_turn( to_turns<int>( return_value - calendar::turn_zero ), 1_turns,
string_format( _( "Set turn to? (One day is %i turns)" ), to_turns<int>( 1_days ) ).c_str() );
break;
default:
break;
}
} while( smenu.ret != UILIST_CANCEL );
return return_value;
}
Loading

0 comments on commit 7f91d0c

Please sign in to comment.