Skip to content

Commit d701a87

Browse files
authored
Merge pull request #82924 from Blueflowerss/isekai
dimensional travel (isekai the return)
2 parents 7423831 + 612d089 commit d701a87

26 files changed

+547
-261
lines changed

data/json/effects_on_condition/example_eocs.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,5 +518,31 @@
518518
{ "math": [ "ITEM_POWER_PERC = n_val('power_percentage')" ] },
519519
{ "u_message": "<global_val:ITEM_POWER> / <global_val:ITEM_POWER_MAX> (<global_val:ITEM_POWER_PERC>%)" }
520520
]
521+
},
522+
{
523+
"type": "effect_on_condition",
524+
"id": "EOC_dimension_swap_test",
525+
"//": "shifts the character to a new dimension",
526+
"global": true,
527+
"effect": [
528+
{
529+
"set_string_var": "",
530+
"string_input": {
531+
"title": { "str": "teleport to dimension named:" },
532+
"description": { "str": "'default' returns you to main dimension" },
533+
"width": 30
534+
},
535+
"target_var": { "u_val": "destination_dimension" }
536+
},
537+
{ "u_location_variable": { "u_val": "tele_test" }, "x_adjust": 0, "y_adjust": 0 },
538+
{
539+
"u_teleport": { "u_val": "tele_test" },
540+
"dimension_prefix": { "u_val": "destination_dimension" },
541+
"fail_message": "your body doesn't move",
542+
"success_message": "This place feels different."
543+
},
544+
{ "u_message": { "u_val": "destination_dimension" } },
545+
{ "if": { "u_in_dimension": "" }, "then": { "u_message": "home sweet home" } }
546+
]
521547
}
522548
]

doc/JSON/EFFECT_ON_CONDITION.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4299,6 +4299,7 @@ You or NPC is teleported to `target_var` coordinates
42994299
| "fail_message" | optional | string or [variable object](#variable-object) | message, that would be printed, if teleportation was failed, like if coordinates contained creature or impassable obstacle (like wall) |
43004300
| "force" | optional | boolean | default false; if true, teleportation can't fail - any creature, that stand on target coordinates, would be brutally telefragged, and if impassable obstacle occur, the closest point would be picked instead |
43014301
| "force_safe" | optional | boolean | default false; if true, teleportation cannot^(tm) fail. If there is a creature or obstacle at the target coordinate, the closest passable point within 5 horizontal tiles is picked instead. If there is no point, the creature remains where they are.
4302+
| "dimension_prefix" | optional | string | default ""; if a value is specified, will teleport the player to a dimension named after the prefix. Currently very WIP |
43024303

43034304
##### Valid talkers:
43044305

src/avatar.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,11 @@ void avatar::load_map_memory()
250250
player_map_memory->load( pos_abs() );
251251
}
252252

253+
void avatar::clear_map_memory()
254+
{
255+
player_map_memory->clear();
256+
}
257+
253258
void avatar::prepare_map_memory_region( const tripoint_abs_ms &p1, const tripoint_abs_ms &p2 )
254259
{
255260
player_map_memory->prepare_region( p1, p2 );

src/avatar.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ class avatar : public Character
9999
void deserialize( const JsonObject &data ) override;
100100
bool save_map_memory();
101101
void load_map_memory();
102+
void clear_map_memory();
102103

103104
// newcharacter.cpp
104105
bool create( character_type type, const std::string &tempname = "" );

src/condition.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,14 @@ conditional_t::func f_is_wearing( const JsonObject &jo, std::string_view member,
673673
};
674674
}
675675

676+
conditional_t::func f_in_dimension( const JsonObject &jo, std::string_view member )
677+
{
678+
str_or_var dimension_prefix = get_str_or_var( jo.get_member( member ), member, true );
679+
return [dimension_prefix]( const_dialogue const & d ) {
680+
return ( g->get_dimension_prefix() == dimension_prefix.evaluate( d ) );
681+
};
682+
}
683+
676684
conditional_t::func f_has_item( const JsonObject &jo, std::string_view member, bool is_npc )
677685
{
678686
str_or_var item_id = get_str_or_var( jo.get_member( member ), member, true );
@@ -2416,6 +2424,7 @@ parsers = {
24162424
{"u_has_part_temp", "npc_has_part_temp", jarg::member | jarg::array, &conditional_fun::f_has_part_temp },
24172425
{"u_is_wearing", "npc_is_wearing", jarg::member, &conditional_fun::f_is_wearing },
24182426
{"is_outside", jarg::member, &conditional_fun::f_tile_is_outside },
2427+
{"u_in_dimension", jarg::member, &conditional_fun::f_in_dimension },
24192428
{"u_has_item", "npc_has_item", jarg::member, &conditional_fun::f_has_item },
24202429
{"u_has_item_with_flag", "npc_has_item_with_flag", jarg::member, &conditional_fun::f_has_item_with_flag },
24212430
{"u_has_items", "npc_has_items", jarg::member, &conditional_fun::f_has_items },

src/do_turn.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,10 @@ bool do_turn()
482482
g->gamemode->per_turn();
483483
calendar::turn += 1_turns;
484484
}
485-
485+
//used for dimension swapping
486+
if( g->swapping_dimensions ) {
487+
g->swapping_dimensions = false;
488+
}
486489
play_music( music::get_music_id_string() );
487490

488491
// starting a new turn, clear out temperature cache

src/game.cpp

Lines changed: 103 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "game.h"
2+
#include "map_memory.h"
23

34
#include <algorithm>
45
#include <bitset>
@@ -3186,6 +3187,15 @@ void game::load_master()
31863187
} );
31873188
}
31883189

3190+
bool game::load_dimension_data()
3191+
{
3192+
const cata_path datafile = PATH_INFO::current_dimension_save_path() / SAVE_DIMENSION_DATA;
3193+
// If dimension_data.gsav doesn't exist, return false
3194+
return read_from_file_optional( datafile, [this, &datafile]( std::istream & is ) {
3195+
unserialize_dimension_data( datafile, is );
3196+
} );
3197+
}
3198+
31893199
bool game::load( const std::string &world )
31903200
{
31913201
world_generator->init();
@@ -3229,6 +3239,13 @@ bool game::load( const save_t &name )
32293239
load_master();
32303240
}
32313241
},
3242+
{
3243+
_( "Dimension data" ), [&]()
3244+
{
3245+
// Load up dimension specific data (ie; weather, overmapstate)
3246+
load_dimension_data();
3247+
}
3248+
},
32323249
{
32333250
_( "Character save" ), [&]()
32343251
{
@@ -3471,7 +3488,14 @@ bool game::save_factions_missions_npcs()
34713488
serialize_master( fout );
34723489
}, _( "factions data" ) );
34733490
}
3474-
3491+
//Saves per-dimension data like Weather and overmapbuffer state
3492+
bool game::save_dimension_data()
3493+
{
3494+
cata_path data_file = PATH_INFO::current_dimension_save_path() / SAVE_DIMENSION_DATA;
3495+
return write_to_file( data_file, [&]( std::ostream & fout ) {
3496+
serialize_dimension_data( fout );
3497+
}, _( "dimension data" ) );
3498+
}
34753499
bool game::save_maps()
34763500
{
34773501
map &here = get_map();
@@ -3641,6 +3665,7 @@ bool game::save()
36413665
if( !save_player_data() ||
36423666
!save_achievements() ||
36433667
!save_factions_missions_npcs() ||
3668+
!save_dimension_data() ||
36443669
!save_maps() ||
36453670
!get_auto_pickup().save_character() ||
36463671
!get_auto_notes_settings().save( true ) ||
@@ -5698,7 +5723,7 @@ bool game::revive_corpse( const tripoint_bub_ms &p, item &it, int radius )
56985723
}
56995724
// If this is not here, the game may attempt to spawn a monster before the map exists,
57005725
// leading to it querying for furniture, and crashing.
5701-
if( g->new_game ) {
5726+
if( g->new_game || g->swapping_dimensions ) {
57025727
return false;
57035728
}
57045729
if( it.has_flag( flag_FIELD_DRESS ) || it.has_flag( flag_FIELD_DRESS_FAILED ) ||
@@ -11480,7 +11505,7 @@ void game::place_player_overmap( const tripoint_abs_omt &om_dest, bool move_play
1148011505
here.spawn_monsters( true ); // Static monsters
1148111506
update_overmap_seen();
1148211507
// update weather now as it could be different on the new location
11483-
weather.nextweather = calendar::turn;
11508+
weather.set_nextweather( calendar::turn );
1148411509
if( move_player ) {
1148511510
place_player( player_pos );
1148611511
}
@@ -12711,6 +12736,67 @@ void game::vertical_move( int movez, bool force, bool peeking )
1271112736
cata_event_dispatch::avatar_moves( old_abs_pos, u, here );
1271212737
}
1271312738

12739+
bool game::travel_to_dimension( const std::string &new_prefix )
12740+
{
12741+
map &here = get_map();
12742+
avatar &player = get_avatar();
12743+
unload_npcs();
12744+
save_dimension_data();
12745+
for( monster &critter : all_monsters() ) {
12746+
despawn_monster( critter );
12747+
}
12748+
if( player.in_vehicle ) {
12749+
here.unboard_vehicle( player.pos_bub() );
12750+
}
12751+
// Make sure we don't mess up savedata if for some reason maps can't be saved
12752+
if( !save_maps() ) {
12753+
return false;
12754+
}
12755+
player.save_map_memory();
12756+
for( int z = -OVERMAP_DEPTH; z <= OVERMAP_HEIGHT; z++ ) {
12757+
here.clear_vehicle_list( z );
12758+
}
12759+
here.rebuild_vehicle_level_caches();
12760+
// Inputting an empty string to the text input EOC fails
12761+
// so i'm using 'default' as empty/main dimension
12762+
if( new_prefix != "default" ) {
12763+
dimension_prefix = new_prefix;
12764+
} else {
12765+
dimension_prefix.clear();
12766+
}
12767+
// Load in data specific to the dimension (like weather)
12768+
//if( !load_dimension_data() ) {
12769+
// dimension data file not found/created yet
12770+
/* handle weather instance switching when I have dimensions with different region settings,
12771+
right now they're all the same and it's hard to tell if it's working or not. */
12772+
// weather.set_nextweather( calendar::turn );
12773+
//}
12774+
// Clear the immediate game area around the player
12775+
MAPBUFFER.clear();
12776+
// hack to prevent crashes from temperature checks
12777+
// This returns to false in 'on_turn()' so it should be fine?
12778+
swapping_dimensions = true;
12779+
// Clear the overmap
12780+
overmap_buffer.clear();
12781+
// load/create new overmap
12782+
overmap_buffer.get( point_abs_om{} );
12783+
// clear map memory from the previous dimension
12784+
player.clear_map_memory();
12785+
// Load map memory in new dimension, if there is any
12786+
player.load_map_memory();
12787+
// Loads submaps and invalidate related caches
12788+
here.load( tripoint_abs_sm( here.get_abs_sub() ), false );
12789+
12790+
here.invalidate_visibility_cache();
12791+
//without this vehicles only load in after walking around a bit
12792+
here.reset_vehicles_sm_pos();
12793+
load_npcs();
12794+
// Handle static monsters
12795+
here.spawn_monsters( true, true );
12796+
update_overmap_seen();
12797+
return true;
12798+
}
12799+
1271412800
void game::start_hauling( const tripoint_bub_ms &pos )
1271512801
{
1271612802
map &here = get_map();
@@ -13690,6 +13776,20 @@ cata_path PATH_INFO::world_base_save_path()
1369013776
return world_generator->active_world->folder_path();
1369113777
}
1369213778

13779+
cata_path PATH_INFO::current_dimension_save_path()
13780+
{
13781+
std::string dimension_prefix = g->get_dimension_prefix();
13782+
if( !dimension_prefix.empty() ) {
13783+
return PATH_INFO::world_base_save_path() / "dimensions" / dimension_prefix;
13784+
}
13785+
return PATH_INFO::world_base_save_path();
13786+
}
13787+
13788+
cata_path PATH_INFO::current_dimension_player_save_path()
13789+
{
13790+
return PATH_INFO::current_dimension_save_path() / base64_encode( get_avatar().get_save_id() );
13791+
}
13792+
1369313793
void game::shift_destination_preview( const point_rel_ms &delta )
1369413794
{
1369513795
for( tripoint_bub_ms &p : destination_preview ) {

src/game.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,8 @@ class game
241241
void serialize_json( std::ostream &fout ); // for save
242242
void unserialize( std::istream &fin, const cata_path &path ); // for load
243243
void unserialize( std::string fin ); // for load
244+
void unserialize_dimension_data( const cata_path &file_name, std::istream &fin ); // for load
245+
void unserialize_dimension_data( const JsonValue &jv ); // for load
244246
void unserialize_master( const cata_path &file_name, std::istream &fin ); // for load
245247
void unserialize_master( const JsonValue &jv ); // for load
246248
private:
@@ -326,6 +328,20 @@ class game
326328
*/
327329
void vertical_move( int z, bool force, bool peeking = false );
328330
void start_hauling( const tripoint_bub_ms &pos );
331+
332+
/**
333+
* Moves the player to an alternate dimension.
334+
* The prefix identifies the dimension and its properties.
335+
*/
336+
bool travel_to_dimension( const std::string &prefix );
337+
/**
338+
* Retrieve the identifier of the current dimension.
339+
* TODO: this should be a dereferencable id that gives properties of the dimension.
340+
*/
341+
std::string get_dimension_prefix() {
342+
return dimension_prefix;
343+
}
344+
329345
/** Returns the other end of the stairs (if any). May query, affect u etc.
330346
* @param pos Disable queries and msgs if not the same position as player.
331347
*/
@@ -897,7 +913,10 @@ class game
897913
//private save functions.
898914
// returns false if saving failed for whatever reason
899915
bool save_factions_missions_npcs();
916+
bool save_dimension_data();
917+
bool load_dimension_data();
900918
void reset_npc_dispositions();
919+
void serialize_dimension_data( std::ostream &fout );
901920
void serialize_master( std::ostream &fout );
902921
// returns false if saving failed for whatever reason
903922
bool save_maps();
@@ -1350,6 +1369,13 @@ class game
13501369
bool can_pulp_corpse( const Character &you, const mtype &corpse_mtype );
13511370
bool can_pulp_corpse( const pulp_data &pd );
13521371
bool can_pulp_acid_corpse( const Character &you, const mtype &corpse_mtype );
1372+
1373+
//currently used as a hacky workaround for dimension swapping
1374+
bool swapping_dimensions = false; // NOLINT (cata-serialize)
1375+
private:
1376+
// Stores the currently occupoed dimension.
1377+
// TODO: should be an id instead of a string.
1378+
std::string dimension_prefix;
13531379
};
13541380

13551381
// Returns temperature modifier from direct heat radiation of nearby sources

src/item.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13594,7 +13594,7 @@ bool item::process_temperature_rot( float insulation, const tripoint_bub_ms &pos
1359413594

1359513595
units::temperature_delta temp_mod;
1359613596
// Toilets and vending machines will try to get the heat radiation and convection during mapgen and segfault.
13597-
if( !g->new_game ) {
13597+
if( !g->new_game && !g->swapping_dimensions ) {
1359813598
temp_mod = get_heat_radiation( pos );
1359913599
temp_mod += get_convection_temperature( pos );
1360013600
temp_mod += here.get_temperature_mod( pos );

src/main.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@
6060
#include "type_id.h"
6161
#include "ui_manager.h"
6262
#include "cata_imgui.h"
63+
#if defined(MACOSX) || defined(__CYGWIN__)
64+
# include <unistd.h> // getpid()
65+
#endif
6366

6467
#if defined(EMSCRIPTEN)
6568
#include <emscripten.h>

0 commit comments

Comments
 (0)