use crate::{activities::Activity, game::ZLayer, State}; use comfy::{ draw_circle, draw_rect_outline, draw_sprite, error, info, is_key_down, main_camera_mut, EngineContext, IVec2, KeyCode, Vec2, RED, WHITE }; use std::time::Instant; use worldgen::MovementCost; pub mod worldgen; pub fn draw(state: &crate::State, _engine: &comfy::EngineContext<'_>) { for (coords, tile) in state.overworld.iter_tiles() { for (i, texture) in tile.textures().iter().rev().enumerate() { let i = i as i32; draw_sprite( *texture, coords.as_vec2(), WHITE, ZLayer::MapMax - i, Vec2::ONE ); draw_rect_outline(coords.as_vec2(), Vec2::ONE, 0.1, RED, 10); } } draw_circle(state.ghost.overworld_pos, 0.5, RED, ZLayer::Ghost.into()); } fn update_move_player(state: &mut State, ctx: &mut EngineContext<'_>) { let now = Instant::now(); // Are there any pending position updates? If so, we ignore all user input and execute // the pending updates. if state.ghost.overworld_movement_pending != Vec2::ZERO { info!( "Pending Movement: {:?}", state.ghost.overworld_movement_pending ); state.ghost.update_overworld_pos(now); return; } // Otherwise, we check for user inputs, and update the pending movement accordingly. let tile_pos = IVec2 { x: state.ghost.overworld_pos.x.round() as _, y: state.ghost.overworld_pos.y.round() as _ }; let Some(tile) = state.overworld.get_tile(tile_pos).copied() else { error!("How can we be standing inside a non-generated tile?"); return; }; let mut requested_pos = None; let mut requested_pos_diff = None; let mut requested_cost_curr = None; let mut requested_cost_new = None; if is_key_down(KeyCode::Up) { let diff = IVec2 { x: 0, y: 1 }; let new_pos = tile_pos + diff; let new_tile = state.overworld.get_or_generate_tile(new_pos); if new_tile.can_stand_inside() { requested_pos = Some(new_pos); requested_pos_diff = Some(diff); requested_cost_curr = Some(tile.movement_cost_up()); requested_cost_new = Some(new_tile.movement_cost_down()); } else { info!("Rejecting movement - cannot stand in the requested tile."); } } if is_key_down(KeyCode::Down) { let diff = IVec2 { x: 0, y: -1 }; let new_pos = tile_pos + diff; let new_tile = state.overworld.get_or_generate_tile(new_pos); if new_tile.can_stand_inside() { requested_pos = Some(new_pos); requested_pos_diff = Some(diff); requested_cost_curr = Some(tile.movement_cost_down()); requested_cost_new = Some(new_tile.movement_cost_up()); } else { info!("Rejecting movement - cannot stand in the requested tile."); } } if is_key_down(KeyCode::Left) { let diff = IVec2 { x: -1, y: 0 }; let new_pos = tile_pos + diff; let new_tile = state.overworld.get_or_generate_tile(new_pos); if new_tile.can_stand_inside() { requested_pos = Some(new_pos); requested_pos_diff = Some(diff); requested_cost_curr = Some(tile.movement_cost_left()); requested_cost_new = Some(new_tile.movement_cost_right()); } else { info!("Rejecting movement - cannot stand in the requested tile."); } } if is_key_down(KeyCode::Right) { let diff = IVec2 { x: 1, y: 0 }; let new_pos = tile_pos + diff; let new_tile = state.overworld.get_or_generate_tile(new_pos); if new_tile.can_stand_inside() { requested_pos = Some(new_pos); requested_pos_diff = Some(diff); requested_cost_curr = Some(tile.movement_cost_right()); requested_cost_new = Some(new_tile.movement_cost_left()); } else { info!("Rejecting movement - cannot stand in the requested tile."); } } // only continue if some movement was requested let Some(_requested_pos) = requested_pos else { return; }; let Some(requested_pos_diff) = requested_pos_diff else { return; }; let Some(requested_cost_curr) = requested_cost_curr else { return; }; let Some(requested_cost_new) = requested_cost_new else { return; }; state.ghost.overworld_movement_speed = match (requested_cost_curr, requested_cost_new) { // movement in this direction not possible (MovementCost::Infinite, _) | (_, MovementCost::Infinite) => { info!("Rejecting movement - movement cost is infinite"); return; }, // we are walking on a path (MovementCost::Path, MovementCost::Path) => 10.0, // we are walking across an obstacle (MovementCost::Obstacle, _) | (_, MovementCost::Obstacle) => 1.0, // we are walking on grass _ => 5.0 }; state.ghost.overworld_movement_pending = Vec2 { x: requested_pos_diff.x as _, y: requested_pos_diff.y as _ }; state.ghost.overworld_pos_last_update = now; //move into house if player stepp at door { let current_tile = state.overworld.get_or_generate_tile(tile_pos); if current_tile.can_enter_house() { info!("enter house at {tile_pos}"); state.activity = Activity::House(tile_pos); state.house_mut(ctx); // gen new house } } } pub fn update(state: &mut State, ctx: &mut EngineContext<'_>) { let mut camera = main_camera_mut(); camera.center = Vec2::ZERO; camera.zoom = 30.0; // move player update_move_player(state, ctx); // generate more chunks if needed { let half_viewport = (camera.world_viewport() * 0.5 + 3.0).as_ivec2(); let rounded_ghost_pos = IVec2 { x: state.ghost.overworld_pos.x.round() as _, y: state.ghost.overworld_pos.y.round() as _ }; state.overworld.get_or_generate_tile( rounded_ghost_pos + IVec2::new(half_viewport.x, half_viewport.y) ); state.overworld.get_or_generate_tile( rounded_ghost_pos + IVec2::new(half_viewport.x, -half_viewport.y) ); state.overworld.get_or_generate_tile( rounded_ghost_pos + IVec2::new(-half_viewport.x, half_viewport.y) ); state.overworld.get_or_generate_tile( rounded_ghost_pos + IVec2::new(-half_viewport.x, -half_viewport.y) ); } }