generic goto_level, implements backtracking

This commit is contained in:
Llywelwyn 2023-08-13 09:21:07 +01:00
parent 25befa9343
commit dab0683ffd
6 changed files with 44 additions and 29 deletions

View file

@ -62,6 +62,7 @@ pub enum RunState {
SaveGame,
GameOver,
NextLevel,
PreviousLevel,
HelpScreen,
MagicMapReveal { row: i32, cursed: bool },
MapGeneration,
@ -76,12 +77,12 @@ pub struct State {
}
impl State {
fn generate_world_map(&mut self, new_id: i32) {
fn generate_world_map(&mut self, new_id: i32, offset: i32) {
// Visualisation stuff
self.mapgen_index = 0;
self.mapgen_timer = 0.0;
self.mapgen_history.clear();
let map_building_info = map::level_transition(&mut self.ecs, new_id);
let map_building_info = map::level_transition(&mut self.ecs, new_id, offset);
if let Some(history) = map_building_info {
self.mapgen_history = history;
}
@ -178,7 +179,7 @@ impl State {
return to_delete;
}
fn goto_next_level(&mut self) {
fn goto_level(&mut self, offset: i32) {
// Delete entities that aren't player/player's equipment
let to_delete = self.entities_to_remove_on_level_change();
for target in to_delete {
@ -192,21 +193,9 @@ impl State {
current_id = worldmap_resource.id;
}
gamelog::record_event("descended", 1);
self.generate_world_map(current_id + 1);
// Notify player, restore health up to a point.
let player_entity = self.ecs.fetch::<Entity>();
gamelog::Logger::new()
.append("Taking a short rest, you manage to")
.colour((0, 255, 0))
.append_n("recover some of your strength")
.period()
.log();
let mut pools = self.ecs.write_storage::<Pools>();
let stats = pools.get_mut(*player_entity);
if let Some(stats) = stats {
stats.hit_points.current = i32::max(stats.hit_points.current, stats.hit_points.max / 2);
}
self.generate_world_map(current_id + offset, offset);
let mapname = self.ecs.fetch::<Map>().name.clone();
gamelog::Logger::new().append("You head to").npc_name_n(mapname).period().log();
}
fn game_over_cleanup(&mut self) {
@ -227,7 +216,7 @@ impl State {
}
// Replace map list
self.ecs.insert(map::dungeon::MasterDungeonMap::new());
self.generate_world_map(1);
self.generate_world_map(1, 0);
gamelog::setup_log();
gamelog::record_event("player_level", 1);
@ -408,7 +397,12 @@ impl GameState for State {
}
}
RunState::NextLevel => {
self.goto_next_level();
self.goto_level(1);
self.mapgen_next_state = Some(RunState::PreRun);
new_runstate = RunState::MapGeneration;
}
RunState::PreviousLevel => {
self.goto_level(-1);
self.mapgen_next_state = Some(RunState::PreRun);
new_runstate = RunState::MapGeneration;
}
@ -589,7 +583,7 @@ fn main() -> rltk::BError {
gamelog::setup_log();
gamelog::record_event("player_level", 1);
gs.generate_world_map(1);
gs.generate_world_map(1, 0);
rltk::main_loop(context, gs)
}

View file

@ -31,12 +31,12 @@ impl MasterDungeonMap {
}
}
pub fn level_transition(ecs: &mut World, new_id: i32) -> Option<Vec<Map>> {
pub fn level_transition(ecs: &mut World, new_id: i32, offset: i32) -> Option<Vec<Map>> {
// Obtain master
let dungeon_master = ecs.read_resource::<MasterDungeonMap>();
if dungeon_master.get_map(new_id).is_some() {
std::mem::drop(dungeon_master);
transition_to_existing_map(ecs, new_id);
transition_to_existing_map(ecs, new_id, offset);
return None;
} else {
std::mem::drop(dungeon_master);
@ -44,7 +44,7 @@ pub fn level_transition(ecs: &mut World, new_id: i32) -> Option<Vec<Map>> {
}
}
fn transition_to_existing_map(ecs: &mut World, new_id: i32) {
fn transition_to_existing_map(ecs: &mut World, new_id: i32, offset: i32) {
let dungeon_master = ecs.read_resource::<MasterDungeonMap>();
// Unwrapping here panics if new_id isn't present. But this should
// never be called without new_id being present by level_transition.
@ -53,8 +53,9 @@ fn transition_to_existing_map(ecs: &mut World, new_id: i32) {
let player_entity = ecs.fetch::<Entity>();
// Find down stairs, place player
let w = map.width;
let stair_type = if offset < 0 { TileType::DownStair } else { TileType::UpStair };
for (idx, tt) in map.tiles.iter().enumerate() {
if *tt == TileType::DownStair {
if *tt == stair_type {
let mut player_position = ecs.write_resource::<Point>();
*player_position = Point::new(idx as i32 % w, idx as i32 / w);
let mut position_components = ecs.write_storage::<Position>();

View file

@ -12,7 +12,7 @@ pub fn forest_builder(
difficulty: i32,
initial_player_level: i32,
) -> BuilderChain {
let mut chain = BuilderChain::new(new_id, width, height, difficulty, "Into the Woods", initial_player_level);
let mut chain = BuilderChain::new(new_id, width, height, difficulty, "the woods", initial_player_level);
chain.start_with(CellularAutomataBuilder::new());
chain.with(AreaStartingPosition::new(XStart::CENTRE, YStart::CENTRE));
chain.with(CullUnreachable::new());

View file

@ -308,7 +308,7 @@ pub fn random_builder(
initial_player_level: i32,
) -> BuilderChain {
rltk::console::log(format!("DEBUGINFO: Building random (ID:{}, DIFF:{})", new_id, difficulty));
let mut builder = BuilderChain::new(new_id, width, height, difficulty, "<PLACEHOLDER>", initial_player_level);
let mut builder = BuilderChain::new(new_id, width, height, difficulty, "the dungeon", initial_player_level);
let type_roll = rng.roll_dice(1, 2);
let mut want_doors = true;
match type_roll {

View file

@ -10,7 +10,7 @@ pub fn town_builder(
initial_player_level: i32,
) -> BuilderChain {
rltk::console::log(format!("DEBUGINFO: Building town (ID:{}, DIFF:{})", new_id, difficulty));
let mut chain = BuilderChain::new(new_id, width, height, difficulty, "<PLACEHOLDER>", initial_player_level);
let mut chain = BuilderChain::new(new_id, width, height, difficulty, "the town", initial_player_level);
chain.start_with(TownBuilder::new());
return chain;

View file

@ -457,6 +457,14 @@ pub fn player_input(gs: &mut State, ctx: &mut Rltk) -> RunState {
result = skip_turn(&mut gs.ecs); // (Wait a turn)
}
}
VirtualKeyCode::Comma => {
if ctx.shift {
if !try_previous_level(&mut gs.ecs) {
return RunState::AwaitingInput;
}
return RunState::PreviousLevel; // < to ascend
}
}
VirtualKeyCode::Slash => {
if ctx.shift {
return RunState::HelpScreen;
@ -496,7 +504,19 @@ pub fn try_next_level(ecs: &mut World) -> bool {
if map.tiles[player_idx] == TileType::DownStair {
return true;
} else {
gamelog::Logger::new().append("You don't see a way down.").log();
gamelog::Logger::new().append("You don't see a way down from here.").log();
return false;
}
}
pub fn try_previous_level(ecs: &mut World) -> bool {
let player_pos = ecs.fetch::<Point>();
let map = ecs.fetch::<Map>();
let player_idx = map.xy_idx(player_pos.x, player_pos.y);
if map.tiles[player_idx] == TileType::UpStair {
return true;
} else {
gamelog::Logger::new().append("You don't see a way up from here.").log();
return false;
}
}