├── .gitignore ├── LICENSE ├── README.md ├── images └── readme │ └── rusty_roguelike.png ├── port ├── 06_EntitiesComponentsAndSystems_01_playerecs │ ├── .vscode │ │ └── launch.json │ ├── Cargo.toml │ ├── resources │ │ └── dungeonfont.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder.rs │ │ ├── spawner.rs │ │ └── systems │ │ ├── entity_render.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ └── player_input.rs ├── 06_EntitiesComponentsAndSystems_02_dungeonecs │ ├── .vscode │ │ └── launch.json │ ├── Cargo.toml │ ├── resources │ │ └── dungeonfont.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder.rs │ │ ├── spawner.rs │ │ └── systems │ │ ├── collisions.rs │ │ ├── entity_render.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ └── player_input.rs ├── 07_TurnBasedGames_01_wandering │ └── README.md ├── 07_TurnBasedGames_02_turnbased │ ├── .vscode │ │ └── launch.json │ ├── Cargo.toml │ ├── resources │ │ └── dungeonfont.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── game_stage.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── collisions.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── player_input.rs │ │ └── random_move.rs │ │ └── turn_state.rs ├── 07_TurnBasedGames_03_intent │ ├── .vscode │ │ └── launch.json │ ├── Cargo.toml │ ├── resources │ │ └── dungeonfont.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── events.rs │ │ ├── game_stage.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── collisions.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ └── random_move.rs │ │ └── turn_state.rs ├── 08_HealthSimpleMelee_01_health │ ├── .vscode │ │ └── launch.json │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── events.rs │ │ ├── game_stage.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── collisions.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ └── tooltips.rs │ │ └── turn_state.rs ├── 08_HealthSimpleMelee_02_combat │ ├── .vscode │ │ └── launch.json │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── events.rs │ │ ├── game_stage.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ └── tooltips.rs │ │ └── turn_state.rs ├── 08_HealthSimpleMelee_03_healing │ ├── .vscode │ │ └── launch.json │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── events.rs │ │ ├── game_stage.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ └── tooltips.rs │ │ └── turn_state.rs ├── 09_WinningAndLosing_01_gauntlet │ ├── .vscode │ │ └── launch.json │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── events.rs │ │ ├── game_stage.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── chasing.rs │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ └── tooltips.rs │ │ └── turn_state.rs ├── 09_WinningAndLosing_02_losing │ ├── .vscode │ │ └── launch.json │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── events.rs │ │ ├── game_stage.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── chasing.rs │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ └── tooltips.rs │ │ └── turn_state.rs ├── 09_WinningAndLosing_03_winning │ ├── .vscode │ │ └── launch.json │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── events.rs │ │ ├── game_stage.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── chasing.rs │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ └── tooltips.rs │ │ └── turn_state.rs ├── 10_WhatCanISee_01_fov │ ├── .vscode │ │ └── launch.json │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── events.rs │ │ ├── game_stage.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── chasing.rs │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── fov.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ └── tooltips.rs │ │ └── turn_state.rs ├── 10_WhatCanISee_02_eyesight │ ├── .vscode │ │ └── launch.json │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── events.rs │ │ ├── game_stage.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── chasing.rs │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── fov.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ └── tooltips.rs │ │ └── turn_state.rs ├── 10_WhatCanISee_03_memory │ ├── .vscode │ │ └── launch.json │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── events.rs │ │ ├── game_stage.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── chasing.rs │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── fov.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ └── tooltips.rs │ │ └── turn_state.rs ├── 11_MoreInterestingDungeons │ ├── .vscode │ │ └── launch.json │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── events.rs │ │ ├── game_stage.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder │ │ ├── automata.rs │ │ ├── drunkard.rs │ │ ├── empty.rs │ │ ├── mod.rs │ │ ├── prefab.rs │ │ └── rooms.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── chasing.rs │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── fov.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ └── tooltips.rs │ │ └── turn_state.rs ├── 12_MapTheming │ ├── .vscode │ │ └── launch.json │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── events.rs │ │ ├── game_stage.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder │ │ ├── automata.rs │ │ ├── drunkard.rs │ │ ├── empty.rs │ │ ├── mod.rs │ │ ├── prefab.rs │ │ ├── rooms.rs │ │ └── themes.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── chasing.rs │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── fov.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ └── tooltips.rs │ │ └── turn_state.rs ├── 13_InventoryAndPowerUps_01_potions_and_scrolls │ ├── .vscode │ │ └── launch.json │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── events.rs │ │ ├── game_stage.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder │ │ ├── automata.rs │ │ ├── drunkard.rs │ │ ├── empty.rs │ │ ├── mod.rs │ │ ├── prefab.rs │ │ ├── rooms.rs │ │ └── themes.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── chasing.rs │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── fov.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ └── tooltips.rs │ │ └── turn_state.rs ├── 13_InventoryAndPowerUps_02_carrying_items │ ├── .vscode │ │ └── launch.json │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── events.rs │ │ ├── game_stage.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder │ │ ├── automata.rs │ │ ├── drunkard.rs │ │ ├── empty.rs │ │ ├── mod.rs │ │ ├── prefab.rs │ │ ├── rooms.rs │ │ └── themes.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── chasing.rs │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── fov.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ ├── tooltips.rs │ │ └── use_items.rs │ │ └── turn_state.rs ├── 14_DeeperDungeons │ ├── .vscode │ │ └── launch.json │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── events.rs │ │ ├── game_stage.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder │ │ ├── automata.rs │ │ ├── drunkard.rs │ │ ├── empty.rs │ │ ├── mod.rs │ │ ├── prefab.rs │ │ ├── rooms.rs │ │ └── themes.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── chasing.rs │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── fov.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ ├── tooltips.rs │ │ └── use_items.rs │ │ └── turn_state.rs ├── 15_Loot_01_loot_tables │ ├── .vscode │ │ └── launch.json │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ ├── template.ron │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── events.rs │ │ ├── game_stage.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder │ │ ├── automata.rs │ │ ├── drunkard.rs │ │ ├── empty.rs │ │ ├── mod.rs │ │ ├── prefab.rs │ │ ├── rooms.rs │ │ └── themes.rs │ │ ├── spawner │ │ ├── mod.rs │ │ └── template.rs │ │ ├── systems │ │ ├── chasing.rs │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── fov.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ ├── tooltips.rs │ │ └── use_items.rs │ │ └── turn_state.rs └── 15_Loot_02_better_combat │ ├── .vscode │ └── launch.json │ ├── Cargo.toml │ ├── resources │ ├── dungeonfont.png │ ├── template.ron │ └── terminal8x8.png │ └── src │ ├── camera.rs │ ├── components.rs │ ├── events.rs │ ├── game_stage.rs │ ├── main.rs │ ├── map.rs │ ├── map_builder │ ├── automata.rs │ ├── drunkard.rs │ ├── empty.rs │ ├── mod.rs │ ├── prefab.rs │ ├── rooms.rs │ └── themes.rs │ ├── spawner │ ├── mod.rs │ └── template.rs │ ├── state_label.rs │ ├── systems │ ├── chasing.rs │ ├── combat.rs │ ├── end_turn.rs │ ├── entity_render.rs │ ├── fov.rs │ ├── hud.rs │ ├── map_render.rs │ ├── mod.rs │ ├── movement.rs │ ├── player_input.rs │ ├── random_move.rs │ ├── tooltips.rs │ └── use_items.rs │ └── turn_state.rs ├── source ├── 06_EntitiesComponentsAndSystems_01_playerecs │ ├── Cargo.toml │ ├── resources │ │ └── dungeonfont.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder.rs │ │ ├── spawner.rs │ │ └── systems │ │ ├── entity_render.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ └── player_input.rs ├── 06_EntitiesComponentsAndSystems_02_dungeonecs │ ├── Cargo.toml │ ├── resources │ │ └── dungeonfont.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder.rs │ │ ├── spawner.rs │ │ └── systems │ │ ├── collisions.rs │ │ ├── entity_render.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ └── player_input.rs ├── 07_TurnBasedGames_01_wandering │ ├── Cargo.toml │ ├── resources │ │ └── dungeonfont.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder.rs │ │ ├── spawner.rs │ │ └── systems │ │ ├── collisions.rs │ │ ├── entity_render.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── player_input.rs │ │ └── random_move.rs ├── 07_TurnBasedGames_02_turnbased │ ├── Cargo.toml │ ├── resources │ │ └── dungeonfont.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── collisions.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── player_input.rs │ │ └── random_move.rs │ │ └── turn_state.rs ├── 07_TurnBasedGames_03_intent │ ├── Cargo.toml │ ├── resources │ │ └── dungeonfont.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── collisions.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ └── random_move.rs │ │ └── turn_state.rs ├── 08_HealthSimpleMelee_01_health │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── collisions.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ └── tooltips.rs │ │ └── turn_state.rs ├── 08_HealthSimpleMelee_02_combat │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ └── tooltips.rs │ │ └── turn_state.rs ├── 08_HealthSimpleMelee_03_healing │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ └── tooltips.rs │ │ └── turn_state.rs ├── 09_WinningAndLosing_01_gauntlet │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── chasing.rs │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ └── tooltips.rs │ │ └── turn_state.rs ├── 09_WinningAndLosing_02_losing │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── chasing.rs │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ └── tooltips.rs │ │ └── turn_state.rs ├── 09_WinningAndLosing_03_winning │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── chasing.rs │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ └── tooltips.rs │ │ └── turn_state.rs ├── 10_WhatCanISee_01_fov │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── chasing.rs │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── fov.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ └── tooltips.rs │ │ └── turn_state.rs ├── 10_WhatCanISee_02_eyesight │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── chasing.rs │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── fov.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ └── tooltips.rs │ │ └── turn_state.rs ├── 10_WhatCanISee_03_memory │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── chasing.rs │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── fov.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ └── tooltips.rs │ │ └── turn_state.rs ├── 11_MoreInterestingDungeons_01_traits │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder │ │ ├── empty.rs │ │ └── mod.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── chasing.rs │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── fov.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ └── tooltips.rs │ │ └── turn_state.rs ├── 11_MoreInterestingDungeons_02_traits_rooms │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder │ │ ├── empty.rs │ │ ├── mod.rs │ │ └── rooms.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── chasing.rs │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── fov.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ └── tooltips.rs │ │ └── turn_state.rs ├── 11_MoreInterestingDungeons_03_cellular │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder │ │ ├── automata.rs │ │ ├── empty.rs │ │ ├── mod.rs │ │ └── rooms.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── chasing.rs │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── fov.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ └── tooltips.rs │ │ └── turn_state.rs ├── 11_MoreInterestingDungeons_04_output_harness │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ ├── map.rs │ │ └── map_builder │ │ ├── automata.rs │ │ ├── drunkard.rs │ │ ├── empty.rs │ │ ├── mod.rs │ │ ├── prefab.rs │ │ └── rooms.rs ├── 11_MoreInterestingDungeons_05_drunkard │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder │ │ ├── automata.rs │ │ ├── drunkard.rs │ │ ├── empty.rs │ │ ├── mod.rs │ │ └── rooms.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── chasing.rs │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── fov.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ └── tooltips.rs │ │ └── turn_state.rs ├── 11_MoreInterestingDungeons_06_prefab │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder │ │ ├── automata.rs │ │ ├── drunkard.rs │ │ ├── empty.rs │ │ ├── mod.rs │ │ ├── prefab.rs │ │ └── rooms.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── chasing.rs │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── fov.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ └── tooltips.rs │ │ └── turn_state.rs ├── 12_MapTheming │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder │ │ ├── automata.rs │ │ ├── drunkard.rs │ │ ├── empty.rs │ │ ├── mod.rs │ │ ├── prefab.rs │ │ ├── rooms.rs │ │ └── themes.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── chasing.rs │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── fov.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ └── tooltips.rs │ │ └── turn_state.rs ├── 13_InventoryAndPowerUps_01_potions_and_scrolls │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder │ │ ├── automata.rs │ │ ├── drunkard.rs │ │ ├── empty.rs │ │ ├── mod.rs │ │ ├── prefab.rs │ │ ├── rooms.rs │ │ └── themes.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── chasing.rs │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── fov.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ └── tooltips.rs │ │ └── turn_state.rs ├── 13_InventoryAndPowerUps_02_carrying_items │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder │ │ ├── automata.rs │ │ ├── drunkard.rs │ │ ├── empty.rs │ │ ├── mod.rs │ │ ├── prefab.rs │ │ ├── rooms.rs │ │ └── themes.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── chasing.rs │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── fov.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ ├── tooltips.rs │ │ └── use_items.rs │ │ └── turn_state.rs ├── 14_DeeperDungeons │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder │ │ ├── automata.rs │ │ ├── drunkard.rs │ │ ├── empty.rs │ │ ├── mod.rs │ │ ├── prefab.rs │ │ ├── rooms.rs │ │ └── themes.rs │ │ ├── spawner.rs │ │ ├── systems │ │ ├── chasing.rs │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── fov.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ ├── tooltips.rs │ │ └── use_items.rs │ │ └── turn_state.rs ├── 15_Loot_01_loot_tables │ ├── Cargo.toml │ ├── resources │ │ ├── dungeonfont.png │ │ ├── template.ron │ │ └── terminal8x8.png │ └── src │ │ ├── camera.rs │ │ ├── components.rs │ │ ├── main.rs │ │ ├── map.rs │ │ ├── map_builder │ │ ├── automata.rs │ │ ├── drunkard.rs │ │ ├── empty.rs │ │ ├── mod.rs │ │ ├── prefab.rs │ │ ├── rooms.rs │ │ └── themes.rs │ │ ├── spawner │ │ ├── mod.rs │ │ └── template.rs │ │ ├── systems │ │ ├── chasing.rs │ │ ├── combat.rs │ │ ├── end_turn.rs │ │ ├── entity_render.rs │ │ ├── fov.rs │ │ ├── hud.rs │ │ ├── map_render.rs │ │ ├── mod.rs │ │ ├── movement.rs │ │ ├── player_input.rs │ │ ├── random_move.rs │ │ ├── tooltips.rs │ │ └── use_items.rs │ │ └── turn_state.rs └── 15_Loot_02_better_combat │ ├── Cargo.toml │ ├── resources │ ├── dungeonfont.png │ ├── template.ron │ └── terminal8x8.png │ └── src │ ├── camera.rs │ ├── components.rs │ ├── main.rs │ ├── map.rs │ ├── map_builder │ ├── automata.rs │ ├── drunkard.rs │ ├── empty.rs │ ├── mod.rs │ ├── prefab.rs │ ├── rooms.rs │ └── themes.rs │ ├── spawner │ ├── mod.rs │ └── template.rs │ ├── systems │ ├── chasing.rs │ ├── combat.rs │ ├── end_turn.rs │ ├── entity_render.rs │ ├── fov.rs │ ├── hud.rs │ ├── map_render.rs │ ├── mod.rs │ ├── movement.rs │ ├── player_input.rs │ ├── random_move.rs │ ├── tooltips.rs │ └── use_items.rs │ └── turn_state.rs └── util ├── prefix_commits.sh └── rusty_roguelike_step.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # Generic 2 | temp/ 3 | 4 | # Rust 5 | # 6 | .cargo/ 7 | Cargo.lock 8 | target/ 9 | target-ra/ 10 | target-win/ 11 | 12 | # Fyrox 13 | # 14 | fyrox.log 15 | history.bin 16 | -------------------------------------------------------------------------------- /images/readme/rusty_roguelike.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/images/readme/rusty_roguelike.png -------------------------------------------------------------------------------- /port/06_EntitiesComponentsAndSystems_01_playerecs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Herbert Wolverson ", "Saverio Miroddi "] 3 | edition = "2021" 4 | name = "rusty_roguelike-bevy" 5 | version = "0.1.0" 6 | 7 | [dependencies] 8 | bevy = {version = "0.7.0", default-features = false, features = ["dynamic"]} 9 | bracket-lib = "~0.8.1" 10 | -------------------------------------------------------------------------------- /port/06_EntitiesComponentsAndSystems_01_playerecs/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/06_EntitiesComponentsAndSystems_01_playerecs/resources/dungeonfont.png -------------------------------------------------------------------------------- /port/06_EntitiesComponentsAndSystems_01_playerecs/src/components.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // Every component needs to be derived, so for external types, a wrapper type is needed. 4 | #[derive(Component)] 5 | pub struct PointC(pub Point); 6 | 7 | #[derive(Component)] 8 | pub struct Render { 9 | pub color: ColorPair, 10 | pub glyph: FontCharType, 11 | } 12 | 13 | #[derive(Component)] 14 | pub struct Player; 15 | -------------------------------------------------------------------------------- /port/06_EntitiesComponentsAndSystems_01_playerecs/src/spawner.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn spawn_player(world: &mut World, pos: Point) { 4 | world.spawn().insert_bundle(( 5 | Player, 6 | PointC(pos), 7 | Render { 8 | color: ColorPair::new(WHITE, BLACK), 9 | glyph: to_cp437('@'), 10 | }, 11 | )); 12 | } 13 | -------------------------------------------------------------------------------- /port/06_EntitiesComponentsAndSystems_01_playerecs/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn entity_render(query: Query<(&PointC, &Render)>, camera: Res) { 4 | let mut draw_batch = DrawBatch::new(); 5 | draw_batch.target(1); 6 | let offset = Point::new(camera.left_x, camera.top_y); 7 | 8 | for (pos, render) in query.iter() { 9 | draw_batch.set(pos.0 - offset, render.color, render.glyph); 10 | } 11 | draw_batch.submit(5000).expect("Batch error"); 12 | } 13 | -------------------------------------------------------------------------------- /port/06_EntitiesComponentsAndSystems_01_playerecs/src/systems/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | mod entity_render; 4 | mod map_render; 5 | mod player_input; 6 | 7 | pub fn build_system_set() -> SystemSet { 8 | // At this project stage, system sets (Legion schedulers) are not differentiated, so we just use 9 | // a generic one. 10 | SystemSet::new() 11 | .with_system(player_input::player_input) 12 | .with_system(map_render::map_render) 13 | .with_system(entity_render::entity_render) 14 | } 15 | -------------------------------------------------------------------------------- /port/06_EntitiesComponentsAndSystems_02_dungeonecs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Herbert Wolverson ", "Saverio Miroddi "] 3 | edition = "2021" 4 | name = "rusty_roguelike-bevy" 5 | version = "0.1.0" 6 | 7 | [dependencies] 8 | bevy = {version = "0.7.0", default-features = false, features = ["dynamic"]} 9 | bracket-lib = "~0.8.1" 10 | -------------------------------------------------------------------------------- /port/06_EntitiesComponentsAndSystems_02_dungeonecs/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/06_EntitiesComponentsAndSystems_02_dungeonecs/resources/dungeonfont.png -------------------------------------------------------------------------------- /port/06_EntitiesComponentsAndSystems_02_dungeonecs/src/components.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // Every component needs to be derived, so for external types, a wrapper type is needed. 4 | #[derive(Component)] 5 | pub struct PointC(pub Point); 6 | 7 | #[derive(Component)] 8 | pub struct Render { 9 | pub color: ColorPair, 10 | pub glyph: FontCharType, 11 | } 12 | 13 | #[derive(Component)] 14 | pub struct Player; 15 | 16 | #[derive(Component)] 17 | pub struct Enemy; 18 | -------------------------------------------------------------------------------- /port/06_EntitiesComponentsAndSystems_02_dungeonecs/src/spawner.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn spawn_player(world: &mut World, pos: Point) { 4 | world.spawn().insert_bundle(( 5 | Player, 6 | PointC(pos), 7 | Render { 8 | color: ColorPair::new(WHITE, BLACK), 9 | glyph: to_cp437('@'), 10 | }, 11 | )); 12 | } 13 | 14 | pub fn spawn_monster(world: &mut World, rng: &mut RandomNumberGenerator, pos: Point) { 15 | world.spawn().insert_bundle(( 16 | Enemy, 17 | PointC(pos), 18 | Render { 19 | color: ColorPair::new(WHITE, BLACK), 20 | glyph: match rng.range(0, 4) { 21 | 0 => to_cp437('E'), 22 | 1 => to_cp437('O'), 23 | 2 => to_cp437('o'), 24 | _ => to_cp437('g'), 25 | }, 26 | }, 27 | )); 28 | } 29 | -------------------------------------------------------------------------------- /port/06_EntitiesComponentsAndSystems_02_dungeonecs/src/systems/collisions.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn collisions( 4 | mut commands: Commands, 5 | // Note that we can use two independent queries both accessing PointC, because they have compatible 6 | // access type (immutable); if they were incompatible, we would have needed ParamSet. 7 | player_query: Query<&PointC, With>, 8 | enemies_query: Query<(Entity, &PointC), With>, 9 | ) { 10 | // We can use Query#single() when it's guaranteed that an entity exists. 11 | let player_pos = player_query.single().0; 12 | 13 | for (entity, pos) in enemies_query.iter() { 14 | if pos.0 == player_pos { 15 | commands.entity(entity).despawn() 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /port/06_EntitiesComponentsAndSystems_02_dungeonecs/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn entity_render(query: Query<(&PointC, &Render)>, camera: Res) { 4 | let mut draw_batch = DrawBatch::new(); 5 | draw_batch.target(1); 6 | let offset = Point::new(camera.left_x, camera.top_y); 7 | 8 | for (pos, render) in query.iter() { 9 | draw_batch.set(pos.0 - offset, render.color, render.glyph); 10 | } 11 | draw_batch.submit(5000).expect("Batch error"); 12 | } 13 | -------------------------------------------------------------------------------- /port/06_EntitiesComponentsAndSystems_02_dungeonecs/src/systems/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | mod collisions; 4 | mod entity_render; 5 | mod map_render; 6 | mod player_input; 7 | 8 | pub fn build_system_set() -> SystemSet { 9 | // At this project stage, system sets (Legion schedulers) are not differentiated, so we just use 10 | // a generic one. 11 | SystemSet::new() 12 | .with_system(player_input::player_input) 13 | .with_system(collisions::collisions) 14 | .with_system(map_render::map_render) 15 | .with_system(entity_render::entity_render) 16 | } 17 | -------------------------------------------------------------------------------- /port/07_TurnBasedGames_01_wandering/README.md: -------------------------------------------------------------------------------- 1 | This step has been removed, because it required the crate `iyes_loopless` in order to be ported, which made it much closer to the following step than the current. 2 | -------------------------------------------------------------------------------- /port/07_TurnBasedGames_02_turnbased/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Herbert Wolverson ", "Saverio Miroddi "] 3 | edition = "2021" 4 | name = "rusty_roguelike-bevy" 5 | version = "0.1.0" 6 | 7 | [dependencies] 8 | bevy = {version = "0.7.0", default-features = false, features = ["dynamic"]} 9 | bracket-lib = "~0.8.1" 10 | iyes_loopless = "0.5.1" 11 | -------------------------------------------------------------------------------- /port/07_TurnBasedGames_02_turnbased/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/07_TurnBasedGames_02_turnbased/resources/dungeonfont.png -------------------------------------------------------------------------------- /port/07_TurnBasedGames_02_turnbased/src/components.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // Every component needs to be derived, so for external types, a wrapper type is needed. 4 | #[derive(Component)] 5 | pub struct PointC(pub Point); 6 | 7 | #[derive(Component)] 8 | pub struct Render { 9 | pub color: ColorPair, 10 | pub glyph: FontCharType, 11 | } 12 | 13 | #[derive(Component)] 14 | pub struct Player; 15 | 16 | #[derive(Component)] 17 | pub struct Enemy; 18 | 19 | #[derive(Component)] 20 | pub struct MovingRandomly; 21 | -------------------------------------------------------------------------------- /port/07_TurnBasedGames_02_turnbased/src/game_stage.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // From our game design perspective, GameStage is a group of systems that require the commands in the 4 | // previous group to be flushed. 5 | // See `mod.rs`. 6 | // 7 | #[derive(Debug, Clone, Eq, PartialEq, Hash, StageLabel)] 8 | pub enum GameStage { 9 | // The first stage is the standard Update 10 | MovePlayer, 11 | MoveMonsters, 12 | MonsterCollisions, 13 | } 14 | -------------------------------------------------------------------------------- /port/07_TurnBasedGames_02_turnbased/src/systems/collisions.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn collisions( 4 | mut commands: Commands, 5 | // Note that we can use two independent queries both accessing PointC, because they have compatible 6 | // access type (immutable); if they were incompatible, we would have needed ParamSet. 7 | player_query: Query<&PointC, With>, 8 | enemies_query: Query<(Entity, &PointC), With>, 9 | ) { 10 | // We can use Query#single() when it's guaranteed that an entity exists. 11 | let player_pos = player_query.single().0; 12 | 13 | for (entity, pos) in enemies_query.iter() { 14 | if pos.0 == player_pos { 15 | commands.entity(entity).despawn() 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /port/07_TurnBasedGames_02_turnbased/src/systems/end_turn.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn end_turn(mut commands: Commands, turn_state: Res) { 4 | let new_state = match *turn_state { 5 | // In the source project, AwaitingInput returns AwaitingInput, however, it's actually an unreachable 6 | // case, because the change to the next state (PlayerTurn) is performed in the `player_input` system. 7 | TurnState::AwaitingInput => unreachable!(), 8 | TurnState::PlayerTurn => TurnState::MonsterTurn, 9 | TurnState::MonsterTurn => TurnState::AwaitingInput, 10 | }; 11 | 12 | commands.insert_resource(new_state); 13 | } 14 | -------------------------------------------------------------------------------- /port/07_TurnBasedGames_02_turnbased/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn entity_render(query: Query<(&PointC, &Render)>, camera: Res) { 4 | let mut draw_batch = DrawBatch::new(); 5 | draw_batch.target(1); 6 | let offset = Point::new(camera.left_x, camera.top_y); 7 | 8 | for (pos, render) in query.iter() { 9 | draw_batch.set(pos.0 - offset, render.color, render.glyph); 10 | } 11 | draw_batch.submit(5000).expect("Batch error"); 12 | } 13 | -------------------------------------------------------------------------------- /port/07_TurnBasedGames_02_turnbased/src/systems/map_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn map_render((map, camera): (Res, Res)) { 4 | let mut draw_batch = DrawBatch::new(); 5 | draw_batch.target(0); 6 | for y in camera.top_y..=camera.bottom_y { 7 | for x in camera.left_x..camera.right_x { 8 | let pt = Point::new(x, y); 9 | let offset = Point::new(camera.left_x, camera.top_y); 10 | if map.in_bounds(pt) { 11 | let idx = map_idx(x, y); 12 | let glyph = match map.tiles[idx] { 13 | TileType::Floor => to_cp437('.'), 14 | TileType::Wall => to_cp437('#'), 15 | }; 16 | draw_batch.set(pt - offset, ColorPair::new(WHITE, BLACK), glyph); 17 | } 18 | } 19 | } 20 | draw_batch.submit(0).expect("Batch error"); 21 | } 22 | -------------------------------------------------------------------------------- /port/07_TurnBasedGames_02_turnbased/src/systems/random_move.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn random_move(mut movers: Query<&mut PointC, With>, map: Res) { 4 | movers.iter_mut().for_each(|mut pos| { 5 | let mut rng = RandomNumberGenerator::new(); 6 | let destination = match rng.range(0, 4) { 7 | 0 => Point::new(-1, 0), 8 | 1 => Point::new(1, 0), 9 | 2 => Point::new(0, -1), 10 | _ => Point::new(0, 1), 11 | } + pos.0; 12 | 13 | if map.can_enter_tile(destination) { 14 | pos.0 = destination; 15 | } 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /port/07_TurnBasedGames_02_turnbased/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, Eq, PartialEq, Hash)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | } 7 | -------------------------------------------------------------------------------- /port/07_TurnBasedGames_03_intent/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Herbert Wolverson ", "Saverio Miroddi "] 3 | edition = "2021" 4 | name = "rusty_roguelike-bevy" 5 | version = "0.1.0" 6 | 7 | [dependencies] 8 | bevy = {version = "0.7.0", default-features = false, features = ["dynamic"]} 9 | bracket-lib = "~0.8.1" 10 | iyes_loopless = "0.5.1" 11 | -------------------------------------------------------------------------------- /port/07_TurnBasedGames_03_intent/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/07_TurnBasedGames_03_intent/resources/dungeonfont.png -------------------------------------------------------------------------------- /port/07_TurnBasedGames_03_intent/src/components.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // Every component needs to be derived, so for external types, a wrapper type is needed. 4 | #[derive(Component)] 5 | pub struct PointC(pub Point); 6 | 7 | #[derive(Component)] 8 | pub struct Render { 9 | pub color: ColorPair, 10 | pub glyph: FontCharType, 11 | } 12 | 13 | #[derive(Component)] 14 | pub struct Player; 15 | 16 | #[derive(Component)] 17 | pub struct Enemy; 18 | 19 | #[derive(Component)] 20 | pub struct MovingRandomly; 21 | -------------------------------------------------------------------------------- /port/07_TurnBasedGames_03_intent/src/events.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // Differently from the source project, which uses resources, we use Bevy's messaging system for move 4 | // messages. 5 | // In the context of this project, it's a bit more ergonomic, but in larger ones, there advantages are 6 | // more significant. 7 | // Watch out! Events persist for two frames, which in this design is not a problem, but it's something 8 | // important to know. 9 | // 10 | pub struct WantsToMove { 11 | pub entity: Entity, 12 | // Event type fields don't need to be components; in this case we don't need to use PointC, but 13 | // it can be trivially done. 14 | pub destination: Point, 15 | } 16 | -------------------------------------------------------------------------------- /port/07_TurnBasedGames_03_intent/src/game_stage.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // From our game design perspective, GameStage is a group of systems that require the commands in the 4 | // previous group to be flushed. 5 | // See `mod.rs`. 6 | // 7 | #[derive(Debug, Clone, Eq, PartialEq, Hash, StageLabel)] 8 | pub enum GameStage { 9 | // The first stage is the standard Update 10 | MovePlayer, 11 | Collisions, 12 | GenerateMonsterMoves, 13 | MoveMonsters, 14 | } 15 | -------------------------------------------------------------------------------- /port/07_TurnBasedGames_03_intent/src/spawner.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn spawn_player(world: &mut World, pos: Point) { 4 | world.spawn().insert_bundle(( 5 | Player, 6 | PointC(pos), 7 | Render { 8 | color: ColorPair::new(WHITE, BLACK), 9 | glyph: to_cp437('@'), 10 | }, 11 | )); 12 | } 13 | 14 | pub fn spawn_monster(world: &mut World, rng: &mut RandomNumberGenerator, pos: Point) { 15 | world.spawn().insert_bundle(( 16 | Enemy, 17 | PointC(pos), 18 | Render { 19 | color: ColorPair::new(WHITE, BLACK), 20 | glyph: match rng.range(0, 4) { 21 | 0 => to_cp437('E'), 22 | 1 => to_cp437('O'), 23 | 2 => to_cp437('o'), 24 | _ => to_cp437('g'), 25 | }, 26 | }, 27 | MovingRandomly {}, 28 | )); 29 | } 30 | -------------------------------------------------------------------------------- /port/07_TurnBasedGames_03_intent/src/systems/collisions.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn collisions( 4 | mut commands: Commands, 5 | // Note that we can use two independent queries both accessing PointC, because they have compatible 6 | // access type (immutable); if they were incompatible, we would have needed ParamSet. 7 | player_query: Query<&PointC, With>, 8 | enemies_query: Query<(Entity, &PointC), With>, 9 | ) { 10 | // We can use Query#single() when it's guaranteed that an entity exists. 11 | let player_pos = player_query.single().0; 12 | 13 | for (entity, pos) in enemies_query.iter() { 14 | if pos.0 == player_pos { 15 | commands.entity(entity).despawn() 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /port/07_TurnBasedGames_03_intent/src/systems/end_turn.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn end_turn(mut commands: Commands, turn_state: Res) { 4 | let new_state = match *turn_state { 5 | // In the source project, AwaitingInput returns AwaitingInput, however, it's actually an unreachable 6 | // case, because the change to the next state (PlayerTurn) is performed in the `player_input` system. 7 | TurnState::AwaitingInput => unreachable!(), 8 | TurnState::PlayerTurn => TurnState::MonsterTurn, 9 | TurnState::MonsterTurn => TurnState::AwaitingInput, 10 | }; 11 | 12 | commands.insert_resource(new_state); 13 | } 14 | -------------------------------------------------------------------------------- /port/07_TurnBasedGames_03_intent/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn entity_render(query: Query<(&PointC, &Render)>, camera: Res) { 4 | let mut draw_batch = DrawBatch::new(); 5 | draw_batch.target(1); 6 | let offset = Point::new(camera.left_x, camera.top_y); 7 | 8 | for (pos, render) in query.iter() { 9 | draw_batch.set(pos.0 - offset, render.color, render.glyph); 10 | } 11 | draw_batch.submit(5000).expect("Batch error"); 12 | } 13 | -------------------------------------------------------------------------------- /port/07_TurnBasedGames_03_intent/src/systems/map_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn map_render((map, camera): (Res, Res)) { 4 | let mut draw_batch = DrawBatch::new(); 5 | draw_batch.target(0); 6 | for y in camera.top_y..=camera.bottom_y { 7 | for x in camera.left_x..camera.right_x { 8 | let pt = Point::new(x, y); 9 | let offset = Point::new(camera.left_x, camera.top_y); 10 | if map.in_bounds(pt) { 11 | let idx = map_idx(x, y); 12 | let glyph = match map.tiles[idx] { 13 | TileType::Floor => to_cp437('.'), 14 | TileType::Wall => to_cp437('#'), 15 | }; 16 | draw_batch.set(pt - offset, ColorPair::new(WHITE, BLACK), glyph); 17 | } 18 | } 19 | } 20 | draw_batch.submit(0).expect("Batch error"); 21 | } 22 | -------------------------------------------------------------------------------- /port/07_TurnBasedGames_03_intent/src/systems/movement.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn movement( 4 | mut commands: Commands, 5 | mut move_events: EventReader, 6 | query: Query<&Player>, 7 | (map, mut camera): (Res, ResMut), 8 | ) { 9 | for &WantsToMove { 10 | entity, 11 | destination, 12 | } in move_events.iter() 13 | { 14 | if map.can_enter_tile(destination) { 15 | commands.entity(entity).insert(PointC(destination)); 16 | 17 | // An alternative design is to split the messages in two: for player and for enemies. 18 | // 19 | if query.get(entity).is_ok() { 20 | camera.on_player_move(destination); 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /port/07_TurnBasedGames_03_intent/src/systems/random_move.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn random_move( 4 | mut move_events: EventWriter, 5 | movers: Query<(Entity, &PointC), With>, 6 | ) { 7 | movers.iter().for_each(|(entity, pos)| { 8 | let mut rng = RandomNumberGenerator::new(); 9 | let destination = match rng.range(0, 4) { 10 | 0 => Point::new(-1, 0), 11 | 1 => Point::new(1, 0), 12 | 2 => Point::new(0, -1), 13 | _ => Point::new(0, 1), 14 | } + pos.0; 15 | 16 | move_events.send(WantsToMove { 17 | entity, 18 | destination, 19 | }); 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /port/07_TurnBasedGames_03_intent/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, Eq, PartialEq, Hash)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | } 7 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_01_health/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Herbert Wolverson ", "Saverio Miroddi "] 3 | edition = "2021" 4 | name = "rusty_roguelike-bevy" 5 | version = "0.1.0" 6 | 7 | [dependencies] 8 | bevy = {version = "0.7.0", default-features = false, features = ["dynamic"]} 9 | bracket-lib = "~0.8.1" 10 | iyes_loopless = "0.5.1" 11 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_01_health/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/08_HealthSimpleMelee_01_health/resources/dungeonfont.png -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_01_health/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/08_HealthSimpleMelee_01_health/resources/terminal8x8.png -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_01_health/src/components.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // Every component needs to be derived, so for external types, a wrapper type is needed. 4 | #[derive(Component)] 5 | pub struct PointC(pub Point); 6 | 7 | #[derive(Component)] 8 | pub struct Render { 9 | pub color: ColorPair, 10 | pub glyph: FontCharType, 11 | } 12 | 13 | #[derive(Component)] 14 | pub struct Player; 15 | 16 | #[derive(Component)] 17 | pub struct Enemy; 18 | 19 | #[derive(Component)] 20 | pub struct MovingRandomly; 21 | 22 | #[derive(Component)] 23 | pub struct Health { 24 | pub current: i32, 25 | pub max: i32, 26 | } 27 | 28 | #[derive(Component)] 29 | pub struct Name(pub String); 30 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_01_health/src/events.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // Differently from the source project, which uses resources, we use Bevy's messaging system for move 4 | // messages. 5 | // In the context of this project, it's a bit more ergonomic, but in larger ones, there advantages are 6 | // more significant. 7 | // Watch out! Events persist for two frames, which in this design is not a problem, but it's something 8 | // important to know. 9 | // 10 | pub struct WantsToMove { 11 | pub entity: Entity, 12 | // Event type fields don't need to be components; in this case we don't need to use PointC, but 13 | // it can be trivially done. 14 | pub destination: Point, 15 | } 16 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_01_health/src/game_stage.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // From our game design perspective, GameStage is a group of systems that require the commands in the 4 | // previous group to be flushed. 5 | // See `mod.rs`. 6 | // 7 | #[derive(Debug, Clone, Eq, PartialEq, Hash, StageLabel)] 8 | pub enum GameStage { 9 | // The first stage is the standard Update 10 | MovePlayer, 11 | Collisions, 12 | GenerateMonsterMoves, 13 | MoveMonsters, 14 | } 15 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_01_health/src/systems/collisions.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn collisions( 4 | mut commands: Commands, 5 | // Note that we can use two independent queries both accessing PointC, because they have compatible 6 | // access type (immutable); if they were incompatible, we would have needed ParamSet. 7 | player_query: Query<&PointC, With>, 8 | enemies_query: Query<(Entity, &PointC), With>, 9 | ) { 10 | // We can use Query#single() when it's guaranteed that an entity exists. 11 | let player_pos = player_query.single().0; 12 | 13 | for (entity, pos) in enemies_query.iter() { 14 | if pos.0 == player_pos { 15 | commands.entity(entity).despawn() 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_01_health/src/systems/end_turn.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn end_turn(mut commands: Commands, turn_state: Res) { 4 | let new_state = match *turn_state { 5 | // In the source project, AwaitingInput returns AwaitingInput, however, it's actually an unreachable 6 | // case, because the change to the next state (PlayerTurn) is performed in the `player_input` system. 7 | TurnState::AwaitingInput => unreachable!(), 8 | TurnState::PlayerTurn => TurnState::MonsterTurn, 9 | TurnState::MonsterTurn => TurnState::AwaitingInput, 10 | }; 11 | 12 | commands.insert_resource(new_state); 13 | } 14 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_01_health/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn entity_render(query: Query<(&PointC, &Render)>, camera: Res) { 4 | let mut draw_batch = DrawBatch::new(); 5 | draw_batch.target(1); 6 | let offset = Point::new(camera.left_x, camera.top_y); 7 | 8 | for (pos, render) in query.iter() { 9 | draw_batch.set(pos.0 - offset, render.color, render.glyph); 10 | } 11 | draw_batch.submit(5000).expect("Batch error"); 12 | } 13 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_01_health/src/systems/hud.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn hud(player_query: Query<&Health, With>) { 4 | let player_health = player_query.single(); 5 | 6 | let mut draw_batch = DrawBatch::new(); 7 | draw_batch.target(2); 8 | draw_batch.print_centered(1, "Explore the Dungeon. Cursor keys to move."); 9 | draw_batch.bar_horizontal( 10 | Point::zero(), 11 | SCREEN_WIDTH * 2, 12 | player_health.current, 13 | player_health.max, 14 | ColorPair::new(RED, BLACK), 15 | ); 16 | draw_batch.print_color_centered( 17 | 0, 18 | format!( 19 | " Health: {} / {} ", 20 | player_health.current, player_health.max 21 | ), 22 | ColorPair::new(WHITE, RED), 23 | ); 24 | draw_batch.submit(10000).expect("Batch error"); 25 | } 26 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_01_health/src/systems/map_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn map_render((map, camera): (Res, Res)) { 4 | let mut draw_batch = DrawBatch::new(); 5 | draw_batch.target(0); 6 | for y in camera.top_y..=camera.bottom_y { 7 | for x in camera.left_x..camera.right_x { 8 | let pt = Point::new(x, y); 9 | let offset = Point::new(camera.left_x, camera.top_y); 10 | if map.in_bounds(pt) { 11 | let idx = map_idx(x, y); 12 | let glyph = match map.tiles[idx] { 13 | TileType::Floor => to_cp437('.'), 14 | TileType::Wall => to_cp437('#'), 15 | }; 16 | draw_batch.set(pt - offset, ColorPair::new(WHITE, BLACK), glyph); 17 | } 18 | } 19 | } 20 | draw_batch.submit(0).expect("Batch error"); 21 | } 22 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_01_health/src/systems/movement.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn movement( 4 | mut commands: Commands, 5 | mut move_events: EventReader, 6 | query: Query<&Player>, 7 | (map, mut camera): (Res, ResMut), 8 | ) { 9 | for &WantsToMove { 10 | entity, 11 | destination, 12 | } in move_events.iter() 13 | { 14 | if map.can_enter_tile(destination) { 15 | commands.entity(entity).insert(PointC(destination)); 16 | 17 | // An alternative design is to split the messages in two: for player and for enemies. 18 | // 19 | if query.get(entity).is_ok() { 20 | camera.on_player_move(destination); 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_01_health/src/systems/random_move.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn random_move( 4 | mut move_events: EventWriter, 5 | movers: Query<(Entity, &PointC), With>, 6 | ) { 7 | movers.iter().for_each(|(entity, pos)| { 8 | let mut rng = RandomNumberGenerator::new(); 9 | let destination = match rng.range(0, 4) { 10 | 0 => Point::new(-1, 0), 11 | 1 => Point::new(1, 0), 12 | 2 => Point::new(0, -1), 13 | _ => Point::new(0, 1), 14 | } + pos.0; 15 | 16 | move_events.send(WantsToMove { 17 | entity, 18 | destination, 19 | }); 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_01_health/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, Eq, PartialEq, Hash)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | } 7 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_02_combat/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Herbert Wolverson ", "Saverio Miroddi "] 3 | edition = "2021" 4 | name = "rusty_roguelike-bevy" 5 | version = "0.1.0" 6 | 7 | [dependencies] 8 | bevy = {version = "0.7.0", default-features = false, features = ["dynamic"]} 9 | bracket-lib = "~0.8.1" 10 | iyes_loopless = "0.5.1" 11 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_02_combat/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/08_HealthSimpleMelee_02_combat/resources/dungeonfont.png -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_02_combat/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/08_HealthSimpleMelee_02_combat/resources/terminal8x8.png -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_02_combat/src/components.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // Every component needs to be derived, so for external types, a wrapper type is needed. 4 | #[derive(Component)] 5 | pub struct PointC(pub Point); 6 | 7 | #[derive(Component)] 8 | pub struct Render { 9 | pub color: ColorPair, 10 | pub glyph: FontCharType, 11 | } 12 | 13 | #[derive(Component)] 14 | pub struct Player; 15 | 16 | #[derive(Component)] 17 | pub struct Enemy; 18 | 19 | #[derive(Component)] 20 | pub struct MovingRandomly; 21 | 22 | #[derive(Component)] 23 | pub struct Health { 24 | pub current: i32, 25 | pub max: i32, 26 | } 27 | 28 | #[derive(Component)] 29 | pub struct Name(pub String); 30 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_02_combat/src/events.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // Differently from the source project, which uses resources, we use Bevy's messaging system for move 4 | // and attack messages. 5 | // In the context of this project, it's a bit more ergonomic, but in larger ones, there advantages are 6 | // more significant. 7 | // Watch out! Events persist for two frames, which in this design is not a problem, but it's something 8 | // important to know. 9 | 10 | pub struct WantsToMove { 11 | pub entity: Entity, 12 | // Event type fields don't need to be components; in this case we don't need to use PointC, but 13 | // it can be trivially done. 14 | pub destination: Point, 15 | } 16 | 17 | pub struct WantsToAttack { 18 | pub attacker: Entity, 19 | pub victim: Entity, 20 | } 21 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_02_combat/src/game_stage.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // From our game design perspective, GameStage is a group of systems that require the commands in the 4 | // previous group to be flushed. 5 | // See `mod.rs`. 6 | // 7 | #[derive(Debug, Clone, Eq, PartialEq, Hash, StageLabel)] 8 | pub enum GameStage { 9 | // The first stage is the standard Update 10 | PlayerCombat, 11 | MovePlayer, 12 | GenerateMonsterMoves, 13 | MonsterCombat, 14 | MoveMonsters, 15 | } 16 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_02_combat/src/systems/combat.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn combat( 4 | mut commands: Commands, 5 | mut attack_events: EventReader, 6 | mut health_query: Query<&mut Health>, 7 | ) { 8 | // We can conveniently iterate the message reader, and destructure the message. 9 | for WantsToAttack { victim, .. } in attack_events.iter() { 10 | if let Ok(mut health) = health_query.get_mut(*victim) { 11 | println!("Health before attack: {}", health.current); 12 | health.current -= 1; 13 | if health.current < 1 { 14 | commands.entity(*victim).despawn(); 15 | } 16 | println!("Health after attack: {}", health.current); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_02_combat/src/systems/end_turn.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn end_turn(mut commands: Commands, turn_state: Res) { 4 | let new_state = match *turn_state { 5 | // In the source project, AwaitingInput returns AwaitingInput, however, it's actually an unreachable 6 | // case, because the change to the next state (PlayerTurn) is performed in the `player_input` system. 7 | TurnState::AwaitingInput => unreachable!(), 8 | TurnState::PlayerTurn => TurnState::MonsterTurn, 9 | TurnState::MonsterTurn => TurnState::AwaitingInput, 10 | }; 11 | 12 | commands.insert_resource(new_state); 13 | } 14 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_02_combat/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn entity_render(query: Query<(&PointC, &Render)>, camera: Res) { 4 | let mut draw_batch = DrawBatch::new(); 5 | draw_batch.target(1); 6 | let offset = Point::new(camera.left_x, camera.top_y); 7 | 8 | for (pos, render) in query.iter() { 9 | draw_batch.set(pos.0 - offset, render.color, render.glyph); 10 | } 11 | draw_batch.submit(5000).expect("Batch error"); 12 | } 13 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_02_combat/src/systems/hud.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn hud(player_query: Query<&Health, With>) { 4 | let player_health = player_query.single(); 5 | 6 | let mut draw_batch = DrawBatch::new(); 7 | draw_batch.target(2); 8 | draw_batch.print_centered(1, "Explore the Dungeon. Cursor keys to move."); 9 | draw_batch.bar_horizontal( 10 | Point::zero(), 11 | SCREEN_WIDTH * 2, 12 | player_health.current, 13 | player_health.max, 14 | ColorPair::new(RED, BLACK), 15 | ); 16 | draw_batch.print_color_centered( 17 | 0, 18 | format!( 19 | " Health: {} / {} ", 20 | player_health.current, player_health.max 21 | ), 22 | ColorPair::new(WHITE, RED), 23 | ); 24 | draw_batch.submit(10000).expect("Batch error"); 25 | } 26 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_02_combat/src/systems/map_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn map_render((map, camera): (Res, Res)) { 4 | let mut draw_batch = DrawBatch::new(); 5 | draw_batch.target(0); 6 | for y in camera.top_y..=camera.bottom_y { 7 | for x in camera.left_x..camera.right_x { 8 | let pt = Point::new(x, y); 9 | let offset = Point::new(camera.left_x, camera.top_y); 10 | if map.in_bounds(pt) { 11 | let idx = map_idx(x, y); 12 | let glyph = match map.tiles[idx] { 13 | TileType::Floor => to_cp437('.'), 14 | TileType::Wall => to_cp437('#'), 15 | }; 16 | draw_batch.set(pt - offset, ColorPair::new(WHITE, BLACK), glyph); 17 | } 18 | } 19 | } 20 | draw_batch.submit(0).expect("Batch error"); 21 | } 22 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_02_combat/src/systems/movement.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn movement( 4 | mut commands: Commands, 5 | mut move_events: EventReader, 6 | query: Query<&Player>, 7 | (map, mut camera): (Res, ResMut), 8 | ) { 9 | for &WantsToMove { 10 | entity, 11 | destination, 12 | } in move_events.iter() 13 | { 14 | if map.can_enter_tile(destination) { 15 | commands.entity(entity).insert(PointC(destination)); 16 | 17 | // An alternative design is to split the messages in two: for player and for enemies. 18 | // 19 | if query.get(entity).is_ok() { 20 | camera.on_player_move(destination); 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_02_combat/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, Eq, PartialEq, Hash)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | } 7 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_03_healing/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Herbert Wolverson ", "Saverio Miroddi "] 3 | edition = "2021" 4 | name = "rusty_roguelike-bevy" 5 | version = "0.1.0" 6 | 7 | [dependencies] 8 | bevy = {version = "0.7.0", default-features = false, features = ["dynamic"]} 9 | bracket-lib = "~0.8.1" 10 | iyes_loopless = "0.5.1" 11 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_03_healing/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/08_HealthSimpleMelee_03_healing/resources/dungeonfont.png -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_03_healing/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/08_HealthSimpleMelee_03_healing/resources/terminal8x8.png -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_03_healing/src/components.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // Every component needs to be derived, so for external types, a wrapper type is needed. 4 | #[derive(Component)] 5 | pub struct PointC(pub Point); 6 | 7 | #[derive(Component)] 8 | pub struct Render { 9 | pub color: ColorPair, 10 | pub glyph: FontCharType, 11 | } 12 | 13 | #[derive(Component)] 14 | pub struct Player; 15 | 16 | #[derive(Component)] 17 | pub struct Enemy; 18 | 19 | #[derive(Component)] 20 | pub struct MovingRandomly; 21 | 22 | #[derive(Component)] 23 | pub struct Health { 24 | pub current: i32, 25 | pub max: i32, 26 | } 27 | 28 | #[derive(Component)] 29 | pub struct Name(pub String); 30 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_03_healing/src/events.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // Differently from the source project, which uses resources, we use Bevy's messaging system for move 4 | // and attack messages. 5 | // In the context of this project, it's a bit more ergonomic, but in larger ones, there advantages are 6 | // more significant. 7 | // Watch out! Events persist for two frames, which in this design is not a problem, but it's something 8 | // important to know. 9 | 10 | pub struct WantsToMove { 11 | pub entity: Entity, 12 | // Event type fields don't need to be components; in this case we don't need to use PointC, but 13 | // it can be trivially done. 14 | pub destination: Point, 15 | } 16 | 17 | pub struct WantsToAttack { 18 | pub attacker: Entity, 19 | pub victim: Entity, 20 | } 21 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_03_healing/src/game_stage.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // From our game design perspective, GameStage is a group of systems that require the commands in the 4 | // previous group to be flushed. 5 | // See `mod.rs`. 6 | // 7 | #[derive(Debug, Clone, Eq, PartialEq, Hash, StageLabel)] 8 | pub enum GameStage { 9 | // The first stage is the standard Update 10 | PlayerCombat, 11 | MovePlayer, 12 | GenerateMonsterMoves, 13 | MonsterCombat, 14 | MoveMonsters, 15 | } 16 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_03_healing/src/systems/combat.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn combat( 4 | mut commands: Commands, 5 | mut attack_events: EventReader, 6 | mut health_query: Query<&mut Health>, 7 | ) { 8 | // We can conveniently iterate the message reader, and destructure the message. 9 | for WantsToAttack { victim, .. } in attack_events.iter() { 10 | if let Ok(mut health) = health_query.get_mut(*victim) { 11 | println!("Health before attack: {}", health.current); 12 | health.current -= 1; 13 | if health.current < 1 { 14 | commands.entity(*victim).despawn(); 15 | } 16 | println!("Health after attack: {}", health.current); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_03_healing/src/systems/end_turn.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn end_turn(mut commands: Commands, turn_state: Res) { 4 | let new_state = match *turn_state { 5 | // In the source project, AwaitingInput returns AwaitingInput, however, it's actually an unreachable 6 | // case, because the change to the next state (PlayerTurn) is performed in the `player_input` system. 7 | TurnState::AwaitingInput => unreachable!(), 8 | TurnState::PlayerTurn => TurnState::MonsterTurn, 9 | TurnState::MonsterTurn => TurnState::AwaitingInput, 10 | }; 11 | 12 | commands.insert_resource(new_state); 13 | } 14 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_03_healing/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn entity_render(query: Query<(&PointC, &Render)>, camera: Res) { 4 | let mut draw_batch = DrawBatch::new(); 5 | draw_batch.target(1); 6 | let offset = Point::new(camera.left_x, camera.top_y); 7 | 8 | for (pos, render) in query.iter() { 9 | draw_batch.set(pos.0 - offset, render.color, render.glyph); 10 | } 11 | draw_batch.submit(5000).expect("Batch error"); 12 | } 13 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_03_healing/src/systems/hud.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn hud(player_query: Query<&Health, With>) { 4 | let player_health = player_query.single(); 5 | 6 | let mut draw_batch = DrawBatch::new(); 7 | draw_batch.target(2); 8 | draw_batch.print_centered(1, "Explore the Dungeon. Cursor keys to move."); 9 | draw_batch.bar_horizontal( 10 | Point::zero(), 11 | SCREEN_WIDTH * 2, 12 | player_health.current, 13 | player_health.max, 14 | ColorPair::new(RED, BLACK), 15 | ); 16 | draw_batch.print_color_centered( 17 | 0, 18 | format!( 19 | " Health: {} / {} ", 20 | player_health.current, player_health.max 21 | ), 22 | ColorPair::new(WHITE, RED), 23 | ); 24 | draw_batch.submit(10000).expect("Batch error"); 25 | } 26 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_03_healing/src/systems/map_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn map_render((map, camera): (Res, Res)) { 4 | let mut draw_batch = DrawBatch::new(); 5 | draw_batch.target(0); 6 | for y in camera.top_y..=camera.bottom_y { 7 | for x in camera.left_x..camera.right_x { 8 | let pt = Point::new(x, y); 9 | let offset = Point::new(camera.left_x, camera.top_y); 10 | if map.in_bounds(pt) { 11 | let idx = map_idx(x, y); 12 | let glyph = match map.tiles[idx] { 13 | TileType::Floor => to_cp437('.'), 14 | TileType::Wall => to_cp437('#'), 15 | }; 16 | draw_batch.set(pt - offset, ColorPair::new(WHITE, BLACK), glyph); 17 | } 18 | } 19 | } 20 | draw_batch.submit(0).expect("Batch error"); 21 | } 22 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_03_healing/src/systems/movement.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn movement( 4 | mut commands: Commands, 5 | mut move_events: EventReader, 6 | query: Query<&Player>, 7 | (map, mut camera): (Res, ResMut), 8 | ) { 9 | for &WantsToMove { 10 | entity, 11 | destination, 12 | } in move_events.iter() 13 | { 14 | if map.can_enter_tile(destination) { 15 | commands.entity(entity).insert(PointC(destination)); 16 | 17 | // An alternative design is to split the messages in two: for player and for enemies. 18 | // 19 | if query.get(entity).is_ok() { 20 | camera.on_player_move(destination); 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /port/08_HealthSimpleMelee_03_healing/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, Eq, PartialEq, Hash)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | } 7 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_01_gauntlet/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Herbert Wolverson ", "Saverio Miroddi "] 3 | edition = "2021" 4 | name = "rusty_roguelike-bevy" 5 | version = "0.1.0" 6 | 7 | [dependencies] 8 | bevy = {version = "0.7.0", default-features = false, features = ["dynamic"]} 9 | bracket-lib = "~0.8.1" 10 | iyes_loopless = "0.5.1" 11 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_01_gauntlet/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/09_WinningAndLosing_01_gauntlet/resources/dungeonfont.png -------------------------------------------------------------------------------- /port/09_WinningAndLosing_01_gauntlet/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/09_WinningAndLosing_01_gauntlet/resources/terminal8x8.png -------------------------------------------------------------------------------- /port/09_WinningAndLosing_01_gauntlet/src/components.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // Every component needs to be derived, so for external types, a wrapper type is needed. 4 | #[derive(Component)] 5 | pub struct PointC(pub Point); 6 | 7 | #[derive(Component)] 8 | pub struct Render { 9 | pub color: ColorPair, 10 | pub glyph: FontCharType, 11 | } 12 | 13 | #[derive(Component)] 14 | pub struct Player; 15 | 16 | #[derive(Component)] 17 | pub struct Enemy; 18 | 19 | #[derive(Component)] 20 | pub struct MovingRandomly; 21 | 22 | #[derive(Component)] 23 | pub struct ChasingPlayer; 24 | 25 | #[derive(Component)] 26 | pub struct Health { 27 | pub current: i32, 28 | pub max: i32, 29 | } 30 | 31 | #[derive(Component)] 32 | pub struct Name(pub String); 33 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_01_gauntlet/src/events.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // Differently from the source project, which uses resources, we use Bevy's messaging system for move 4 | // and attack messages. 5 | // In the context of this project, it's a bit more ergonomic, but in larger ones, there advantages are 6 | // more significant. 7 | // Watch out! Events persist for two frames, which in this design is not a problem, but it's something 8 | // important to know. 9 | 10 | pub struct WantsToMove { 11 | pub entity: Entity, 12 | // Event type fields don't need to be components; in this case we don't need to use PointC, but 13 | // it can be trivially done. 14 | pub destination: Point, 15 | } 16 | 17 | pub struct WantsToAttack { 18 | pub attacker: Entity, 19 | pub victim: Entity, 20 | } 21 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_01_gauntlet/src/game_stage.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // From our game design perspective, GameStage is a group of systems that require the commands in the 4 | // previous group to be flushed. 5 | // See `mod.rs`. 6 | // 7 | #[derive(Debug, Clone, Eq, PartialEq, Hash, StageLabel)] 8 | pub enum GameStage { 9 | // The first stage is the standard Update 10 | PlayerCombat, 11 | MovePlayer, 12 | GenerateMonsterMoves, 13 | MonsterCombat, 14 | MoveMonsters, 15 | } 16 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_01_gauntlet/src/systems/combat.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn combat( 4 | mut commands: Commands, 5 | mut attack_events: EventReader, 6 | mut health_query: Query<&mut Health>, 7 | ) { 8 | // We can conveniently iterate the message reader, and destructure the message. 9 | for WantsToAttack { victim, .. } in attack_events.iter() { 10 | if let Ok(mut health) = health_query.get_mut(*victim) { 11 | println!("Health before attack: {}", health.current); 12 | health.current -= 1; 13 | if health.current < 1 { 14 | commands.entity(*victim).despawn(); 15 | } 16 | println!("Health after attack: {}", health.current); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_01_gauntlet/src/systems/end_turn.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn end_turn(mut commands: Commands, turn_state: Res) { 4 | let new_state = match *turn_state { 5 | // In the source project, AwaitingInput returns AwaitingInput, however, it's actually an unreachable 6 | // case, because the change to the next state (PlayerTurn) is performed in the `player_input` system. 7 | TurnState::AwaitingInput => unreachable!(), 8 | TurnState::PlayerTurn => TurnState::MonsterTurn, 9 | TurnState::MonsterTurn => TurnState::AwaitingInput, 10 | }; 11 | 12 | commands.insert_resource(new_state); 13 | } 14 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_01_gauntlet/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn entity_render(query: Query<(&PointC, &Render)>, camera: Res) { 4 | let mut draw_batch = DrawBatch::new(); 5 | draw_batch.target(1); 6 | let offset = Point::new(camera.left_x, camera.top_y); 7 | 8 | for (pos, render) in query.iter() { 9 | draw_batch.set(pos.0 - offset, render.color, render.glyph); 10 | } 11 | draw_batch.submit(5000).expect("Batch error"); 12 | } 13 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_01_gauntlet/src/systems/hud.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn hud(player_query: Query<&Health, With>) { 4 | let player_health = player_query.single(); 5 | 6 | let mut draw_batch = DrawBatch::new(); 7 | draw_batch.target(2); 8 | draw_batch.print_centered(1, "Explore the Dungeon. Cursor keys to move."); 9 | draw_batch.bar_horizontal( 10 | Point::zero(), 11 | SCREEN_WIDTH * 2, 12 | player_health.current, 13 | player_health.max, 14 | ColorPair::new(RED, BLACK), 15 | ); 16 | draw_batch.print_color_centered( 17 | 0, 18 | format!( 19 | " Health: {} / {} ", 20 | player_health.current, player_health.max 21 | ), 22 | ColorPair::new(WHITE, RED), 23 | ); 24 | draw_batch.submit(10000).expect("Batch error"); 25 | } 26 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_01_gauntlet/src/systems/map_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn map_render((map, camera): (Res, Res)) { 4 | let mut draw_batch = DrawBatch::new(); 5 | draw_batch.target(0); 6 | for y in camera.top_y..=camera.bottom_y { 7 | for x in camera.left_x..camera.right_x { 8 | let pt = Point::new(x, y); 9 | let offset = Point::new(camera.left_x, camera.top_y); 10 | if map.in_bounds(pt) { 11 | let idx = map_idx(x, y); 12 | let glyph = match map.tiles[idx] { 13 | TileType::Floor => to_cp437('.'), 14 | TileType::Wall => to_cp437('#'), 15 | }; 16 | draw_batch.set(pt - offset, ColorPair::new(WHITE, BLACK), glyph); 17 | } 18 | } 19 | } 20 | draw_batch.submit(0).expect("Batch error"); 21 | } 22 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_01_gauntlet/src/systems/movement.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn movement( 4 | mut commands: Commands, 5 | mut move_events: EventReader, 6 | query: Query<&Player>, 7 | (map, mut camera): (Res, ResMut), 8 | ) { 9 | for &WantsToMove { 10 | entity, 11 | destination, 12 | } in move_events.iter() 13 | { 14 | if map.can_enter_tile(destination) { 15 | commands.entity(entity).insert(PointC(destination)); 16 | 17 | // An alternative design is to split the messages in two: for player and for enemies. 18 | // 19 | if query.get(entity).is_ok() { 20 | camera.on_player_move(destination); 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_01_gauntlet/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, Eq, PartialEq, Hash)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | } 7 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_02_losing/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Herbert Wolverson ", "Saverio Miroddi "] 3 | edition = "2021" 4 | name = "rusty_roguelike-bevy" 5 | version = "0.1.0" 6 | 7 | [dependencies] 8 | bevy = {version = "0.7.0", default-features = false, features = ["dynamic"]} 9 | bracket-lib = "~0.8.1" 10 | iyes_loopless = "0.5.1" 11 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_02_losing/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/09_WinningAndLosing_02_losing/resources/dungeonfont.png -------------------------------------------------------------------------------- /port/09_WinningAndLosing_02_losing/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/09_WinningAndLosing_02_losing/resources/terminal8x8.png -------------------------------------------------------------------------------- /port/09_WinningAndLosing_02_losing/src/components.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // Every component needs to be derived, so for external types, a wrapper type is needed. 4 | #[derive(Component)] 5 | pub struct PointC(pub Point); 6 | 7 | #[derive(Component)] 8 | pub struct Render { 9 | pub color: ColorPair, 10 | pub glyph: FontCharType, 11 | } 12 | 13 | #[derive(Component)] 14 | pub struct Player; 15 | 16 | #[derive(Component)] 17 | pub struct Enemy; 18 | 19 | #[derive(Component)] 20 | pub struct MovingRandomly; 21 | 22 | #[derive(Component)] 23 | pub struct ChasingPlayer; 24 | 25 | #[derive(Component)] 26 | pub struct Health { 27 | pub current: i32, 28 | pub max: i32, 29 | } 30 | 31 | #[derive(Component)] 32 | pub struct Name(pub String); 33 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_02_losing/src/events.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // Differently from the source project, which uses resources, we use Bevy's messaging system for move 4 | // and attack messages. 5 | // In the context of this project, it's a bit more ergonomic, but in larger ones, there advantages are 6 | // more significant. 7 | // Watch out! Events persist for two frames, which in this design is not a problem, but it's something 8 | // important to know. 9 | 10 | pub struct WantsToMove { 11 | pub entity: Entity, 12 | // Event type fields don't need to be components; in this case we don't need to use PointC, but 13 | // it can be trivially done. 14 | pub destination: Point, 15 | } 16 | 17 | pub struct WantsToAttack { 18 | pub attacker: Entity, 19 | pub victim: Entity, 20 | } 21 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_02_losing/src/game_stage.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // From our game design perspective, GameStage is a group of systems that require the commands in the 4 | // previous group to be flushed. 5 | // See `mod.rs`. 6 | // 7 | #[derive(Debug, Clone, Eq, PartialEq, Hash, StageLabel)] 8 | pub enum GameStage { 9 | // The first stage is the standard Update 10 | PlayerCombat, 11 | MovePlayer, 12 | GenerateMonsterMoves, 13 | MonsterCombat, 14 | MoveMonsters, 15 | } 16 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_02_losing/src/systems/combat.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn combat( 4 | mut commands: Commands, 5 | mut attack_events: EventReader, 6 | mut health_query: Query<&mut Health>, 7 | player_query: Query<&Player>, 8 | ) { 9 | // We can conveniently iterate the message reader, and destructure the message. 10 | for WantsToAttack { victim, .. } in attack_events.iter() { 11 | let is_player = player_query.get(*victim).is_ok(); 12 | 13 | if let Ok(mut health) = health_query.get_mut(*victim) { 14 | health.current -= 1; 15 | if health.current < 1 && !is_player { 16 | commands.entity(*victim).despawn(); 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_02_losing/src/systems/end_turn.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn end_turn( 4 | mut commands: Commands, 5 | player_query: Query<&Health, With>, 6 | turn_state: Res, 7 | ) { 8 | let mut new_state = match *turn_state { 9 | TurnState::PlayerTurn => TurnState::MonsterTurn, 10 | TurnState::MonsterTurn => TurnState::AwaitingInput, 11 | // In the source project, AwaitingInput and GameOver return (themselves), however, they're actually 12 | // unreachable cases, because this system is not run in such states, and the change to their next 13 | // states is performed elsewhere. 14 | _ => unreachable!(), 15 | }; 16 | 17 | if player_query.single().current < 1 { 18 | new_state = TurnState::GameOver; 19 | } 20 | 21 | commands.insert_resource(new_state); 22 | } 23 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_02_losing/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn entity_render(query: Query<(&PointC, &Render)>, camera: Res) { 4 | let mut draw_batch = DrawBatch::new(); 5 | draw_batch.target(1); 6 | let offset = Point::new(camera.left_x, camera.top_y); 7 | 8 | for (pos, render) in query.iter() { 9 | draw_batch.set(pos.0 - offset, render.color, render.glyph); 10 | } 11 | draw_batch.submit(5000).expect("Batch error"); 12 | } 13 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_02_losing/src/systems/hud.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn hud(player_query: Query<&Health, With>) { 4 | let player_health = player_query.single(); 5 | 6 | let mut draw_batch = DrawBatch::new(); 7 | draw_batch.target(2); 8 | draw_batch.print_centered(1, "Explore the Dungeon. Cursor keys to move."); 9 | draw_batch.bar_horizontal( 10 | Point::zero(), 11 | SCREEN_WIDTH * 2, 12 | player_health.current, 13 | player_health.max, 14 | ColorPair::new(RED, BLACK), 15 | ); 16 | draw_batch.print_color_centered( 17 | 0, 18 | format!( 19 | " Health: {} / {} ", 20 | player_health.current, player_health.max 21 | ), 22 | ColorPair::new(WHITE, RED), 23 | ); 24 | draw_batch.submit(10000).expect("Batch error"); 25 | } 26 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_02_losing/src/systems/map_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn map_render((map, camera): (Res, Res)) { 4 | let mut draw_batch = DrawBatch::new(); 5 | draw_batch.target(0); 6 | for y in camera.top_y..=camera.bottom_y { 7 | for x in camera.left_x..camera.right_x { 8 | let pt = Point::new(x, y); 9 | let offset = Point::new(camera.left_x, camera.top_y); 10 | if map.in_bounds(pt) { 11 | let idx = map_idx(x, y); 12 | let glyph = match map.tiles[idx] { 13 | TileType::Floor => to_cp437('.'), 14 | TileType::Wall => to_cp437('#'), 15 | }; 16 | draw_batch.set(pt - offset, ColorPair::new(WHITE, BLACK), glyph); 17 | } 18 | } 19 | } 20 | draw_batch.submit(0).expect("Batch error"); 21 | } 22 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_02_losing/src/systems/movement.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn movement( 4 | mut commands: Commands, 5 | mut move_events: EventReader, 6 | query: Query<&Player>, 7 | (map, mut camera): (Res, ResMut), 8 | ) { 9 | for &WantsToMove { 10 | entity, 11 | destination, 12 | } in move_events.iter() 13 | { 14 | if map.can_enter_tile(destination) { 15 | commands.entity(entity).insert(PointC(destination)); 16 | 17 | // An alternative design is to split the messages in two: for player and for enemies. 18 | // 19 | if query.get(entity).is_ok() { 20 | camera.on_player_move(destination); 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_02_losing/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, Eq, PartialEq, Hash)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | GameOver, 7 | } 8 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_03_winning/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Herbert Wolverson ", "Saverio Miroddi "] 3 | edition = "2021" 4 | name = "rusty_roguelike-bevy" 5 | version = "0.1.0" 6 | 7 | [dependencies] 8 | bevy = {version = "0.7.0", default-features = false, features = ["dynamic"]} 9 | bracket-lib = "~0.8.1" 10 | iyes_loopless = "0.5.1" 11 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_03_winning/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/09_WinningAndLosing_03_winning/resources/dungeonfont.png -------------------------------------------------------------------------------- /port/09_WinningAndLosing_03_winning/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/09_WinningAndLosing_03_winning/resources/terminal8x8.png -------------------------------------------------------------------------------- /port/09_WinningAndLosing_03_winning/src/components.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // Every component needs to be derived, so for external types, a wrapper type is needed. 4 | #[derive(Component)] 5 | pub struct PointC(pub Point); 6 | 7 | #[derive(Component)] 8 | pub struct Render { 9 | pub color: ColorPair, 10 | pub glyph: FontCharType, 11 | } 12 | 13 | #[derive(Component)] 14 | pub struct Player; 15 | 16 | #[derive(Component)] 17 | pub struct Enemy; 18 | 19 | #[derive(Component)] 20 | pub struct Item; 21 | 22 | #[derive(Component)] 23 | pub struct AmuletOfYala; 24 | 25 | #[derive(Component)] 26 | pub struct MovingRandomly; 27 | 28 | #[derive(Component)] 29 | pub struct ChasingPlayer; 30 | 31 | #[derive(Component)] 32 | pub struct Health { 33 | pub current: i32, 34 | pub max: i32, 35 | } 36 | 37 | #[derive(Component)] 38 | pub struct Name(pub String); 39 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_03_winning/src/events.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // Differently from the source project, which uses resources, we use Bevy's messaging system for move 4 | // and attack messages. 5 | // In the context of this project, it's a bit more ergonomic, but in larger ones, there advantages are 6 | // more significant. 7 | // Watch out! Events persist for two frames, which in this design is not a problem, but it's something 8 | // important to know. 9 | 10 | pub struct WantsToMove { 11 | pub entity: Entity, 12 | // Event type fields don't need to be components; in this case we don't need to use PointC, but 13 | // it can be trivially done. 14 | pub destination: Point, 15 | } 16 | 17 | pub struct WantsToAttack { 18 | pub attacker: Entity, 19 | pub victim: Entity, 20 | } 21 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_03_winning/src/game_stage.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // From our game design perspective, GameStage is a group of systems that require the commands in the 4 | // previous group to be flushed. 5 | // See `mod.rs`. 6 | // 7 | #[derive(Debug, Clone, Eq, PartialEq, Hash, StageLabel)] 8 | pub enum GameStage { 9 | // The first stage is the standard Update 10 | PlayerCombat, 11 | MovePlayer, 12 | GenerateMonsterMoves, 13 | MonsterCombat, 14 | MoveMonsters, 15 | } 16 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_03_winning/src/systems/combat.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn combat( 4 | mut commands: Commands, 5 | mut attack_events: EventReader, 6 | mut health_query: Query<&mut Health>, 7 | player_query: Query<&Player>, 8 | ) { 9 | // We can conveniently iterate the message reader, and destructure the message. 10 | for WantsToAttack { victim, .. } in attack_events.iter() { 11 | let is_player = player_query.get(*victim).is_ok(); 12 | 13 | if let Ok(mut health) = health_query.get_mut(*victim) { 14 | health.current -= 1; 15 | if health.current < 1 && !is_player { 16 | commands.entity(*victim).despawn(); 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_03_winning/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn entity_render(query: Query<(&PointC, &Render)>, camera: Res) { 4 | let mut draw_batch = DrawBatch::new(); 5 | draw_batch.target(1); 6 | let offset = Point::new(camera.left_x, camera.top_y); 7 | 8 | for (pos, render) in query.iter() { 9 | draw_batch.set(pos.0 - offset, render.color, render.glyph); 10 | } 11 | draw_batch.submit(5000).expect("Batch error"); 12 | } 13 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_03_winning/src/systems/hud.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn hud(player_query: Query<&Health, With>) { 4 | let player_health = player_query.single(); 5 | 6 | let mut draw_batch = DrawBatch::new(); 7 | draw_batch.target(2); 8 | draw_batch.print_centered(1, "Explore the Dungeon. Cursor keys to move."); 9 | draw_batch.bar_horizontal( 10 | Point::zero(), 11 | SCREEN_WIDTH * 2, 12 | player_health.current, 13 | player_health.max, 14 | ColorPair::new(RED, BLACK), 15 | ); 16 | draw_batch.print_color_centered( 17 | 0, 18 | format!( 19 | " Health: {} / {} ", 20 | player_health.current, player_health.max 21 | ), 22 | ColorPair::new(WHITE, RED), 23 | ); 24 | draw_batch.submit(10000).expect("Batch error"); 25 | } 26 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_03_winning/src/systems/map_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn map_render((map, camera): (Res, Res)) { 4 | let mut draw_batch = DrawBatch::new(); 5 | draw_batch.target(0); 6 | for y in camera.top_y..=camera.bottom_y { 7 | for x in camera.left_x..camera.right_x { 8 | let pt = Point::new(x, y); 9 | let offset = Point::new(camera.left_x, camera.top_y); 10 | if map.in_bounds(pt) { 11 | let idx = map_idx(x, y); 12 | let glyph = match map.tiles[idx] { 13 | TileType::Floor => to_cp437('.'), 14 | TileType::Wall => to_cp437('#'), 15 | }; 16 | draw_batch.set(pt - offset, ColorPair::new(WHITE, BLACK), glyph); 17 | } 18 | } 19 | } 20 | draw_batch.submit(0).expect("Batch error"); 21 | } 22 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_03_winning/src/systems/movement.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn movement( 4 | mut commands: Commands, 5 | mut move_events: EventReader, 6 | query: Query<&Player>, 7 | (map, mut camera): (Res, ResMut), 8 | ) { 9 | for &WantsToMove { 10 | entity, 11 | destination, 12 | } in move_events.iter() 13 | { 14 | if map.can_enter_tile(destination) { 15 | commands.entity(entity).insert(PointC(destination)); 16 | 17 | // An alternative design is to split the messages in two: for player and for enemies. 18 | // 19 | if query.get(entity).is_ok() { 20 | camera.on_player_move(destination); 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /port/09_WinningAndLosing_03_winning/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, Eq, PartialEq, Hash)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | GameOver, 7 | Victory, 8 | } 9 | -------------------------------------------------------------------------------- /port/10_WhatCanISee_01_fov/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Herbert Wolverson ", "Saverio Miroddi "] 3 | edition = "2021" 4 | name = "rusty_roguelike-bevy" 5 | version = "0.1.0" 6 | 7 | [dependencies] 8 | bevy = {version = "0.7.0", default-features = false, features = ["dynamic"]} 9 | bracket-lib = "~0.8.1" 10 | iyes_loopless = "0.5.1" 11 | -------------------------------------------------------------------------------- /port/10_WhatCanISee_01_fov/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/10_WhatCanISee_01_fov/resources/dungeonfont.png -------------------------------------------------------------------------------- /port/10_WhatCanISee_01_fov/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/10_WhatCanISee_01_fov/resources/terminal8x8.png -------------------------------------------------------------------------------- /port/10_WhatCanISee_01_fov/src/events.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // Differently from the source project, which uses resources, we use Bevy's messaging system for move 4 | // and attack messages. 5 | // In the context of this project, it's a bit more ergonomic, but in larger ones, there advantages are 6 | // more significant. 7 | // Watch out! Events persist for two frames, which in this design is not a problem, but it's something 8 | // important to know. 9 | 10 | pub struct WantsToMove { 11 | pub entity: Entity, 12 | // Event type fields don't need to be components; in this case we don't need to use PointC, but 13 | // it can be trivially done. 14 | pub destination: Point, 15 | } 16 | 17 | pub struct WantsToAttack { 18 | pub attacker: Entity, 19 | pub victim: Entity, 20 | } 21 | -------------------------------------------------------------------------------- /port/10_WhatCanISee_01_fov/src/game_stage.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // From our game design perspective, GameStage is a group of systems that require the commands in the 4 | // previous group to be flushed. 5 | // See `mod.rs`. 6 | // 7 | #[derive(Debug, Clone, Eq, PartialEq, Hash, StageLabel)] 8 | pub enum GameStage { 9 | // The first stage (player input) is the standard Update 10 | PlayerCombat, 11 | MovePlayer, 12 | PlayerFov, 13 | GenerateMonsterMoves, 14 | MonsterCombat, 15 | MoveMonsters, 16 | MonsterFov, 17 | } 18 | -------------------------------------------------------------------------------- /port/10_WhatCanISee_01_fov/src/systems/combat.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn combat( 4 | mut commands: Commands, 5 | mut attack_events: EventReader, 6 | mut health_query: Query<&mut Health>, 7 | player_query: Query<&Player>, 8 | ) { 9 | // We can conveniently iterate the message reader, and destructure the message. 10 | for WantsToAttack { victim, .. } in attack_events.iter() { 11 | let is_player = player_query.get(*victim).is_ok(); 12 | 13 | if let Ok(mut health) = health_query.get_mut(*victim) { 14 | health.current -= 1; 15 | if health.current < 1 && !is_player { 16 | commands.entity(*victim).despawn(); 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /port/10_WhatCanISee_01_fov/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn entity_render( 4 | renderables: Query<(&PointC, &Render)>, 5 | player_fov_query: Query<&FieldOfView, With>, 6 | camera: Res, 7 | ) { 8 | let mut draw_batch = DrawBatch::new(); 9 | draw_batch.target(1); 10 | let offset = Point::new(camera.left_x, camera.top_y); 11 | 12 | let player_fov = player_fov_query.single(); 13 | 14 | for (pos, render) in renderables.iter() { 15 | if player_fov.visible_tiles.contains(&pos.0) { 16 | draw_batch.set(pos.0 - offset, render.color, render.glyph); 17 | } 18 | } 19 | 20 | draw_batch.submit(5000).expect("Batch error"); 21 | } 22 | -------------------------------------------------------------------------------- /port/10_WhatCanISee_01_fov/src/systems/fov.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn fov(mut views: Query<(&PointC, &mut FieldOfView)>, map: Res) { 4 | for (pos, mut fov) in views.iter_mut() { 5 | if fov.is_dirty { 6 | fov.visible_tiles = field_of_view_set(pos.0, fov.radius, map.as_ref()); 7 | fov.is_dirty = false; 8 | }; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /port/10_WhatCanISee_01_fov/src/systems/hud.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn hud(player_query: Query<&Health, With>) { 4 | let player_health = player_query.single(); 5 | 6 | let mut draw_batch = DrawBatch::new(); 7 | draw_batch.target(2); 8 | draw_batch.print_centered(1, "Explore the Dungeon. Cursor keys to move."); 9 | draw_batch.bar_horizontal( 10 | Point::zero(), 11 | SCREEN_WIDTH * 2, 12 | player_health.current, 13 | player_health.max, 14 | ColorPair::new(RED, BLACK), 15 | ); 16 | draw_batch.print_color_centered( 17 | 0, 18 | format!( 19 | " Health: {} / {} ", 20 | player_health.current, player_health.max 21 | ), 22 | ColorPair::new(WHITE, RED), 23 | ); 24 | draw_batch.submit(10000).expect("Batch error"); 25 | } 26 | -------------------------------------------------------------------------------- /port/10_WhatCanISee_01_fov/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, Eq, PartialEq, Hash)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | GameOver, 7 | Victory, 8 | } 9 | -------------------------------------------------------------------------------- /port/10_WhatCanISee_02_eyesight/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Herbert Wolverson ", "Saverio Miroddi "] 3 | edition = "2021" 4 | name = "rusty_roguelike-bevy" 5 | version = "0.1.0" 6 | 7 | [dependencies] 8 | bevy = {version = "0.7.0", default-features = false, features = ["dynamic"]} 9 | bracket-lib = "~0.8.1" 10 | iyes_loopless = "0.5.1" 11 | -------------------------------------------------------------------------------- /port/10_WhatCanISee_02_eyesight/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/10_WhatCanISee_02_eyesight/resources/dungeonfont.png -------------------------------------------------------------------------------- /port/10_WhatCanISee_02_eyesight/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/10_WhatCanISee_02_eyesight/resources/terminal8x8.png -------------------------------------------------------------------------------- /port/10_WhatCanISee_02_eyesight/src/events.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // Differently from the source project, which uses resources, we use Bevy's messaging system for move 4 | // and attack messages. 5 | // In the context of this project, it's a bit more ergonomic, but in larger ones, there advantages are 6 | // more significant. 7 | // Watch out! Events persist for two frames, which in this design is not a problem, but it's something 8 | // important to know. 9 | 10 | pub struct WantsToMove { 11 | pub entity: Entity, 12 | // Event type fields don't need to be components; in this case we don't need to use PointC, but 13 | // it can be trivially done. 14 | pub destination: Point, 15 | } 16 | 17 | pub struct WantsToAttack { 18 | pub attacker: Entity, 19 | pub victim: Entity, 20 | } 21 | -------------------------------------------------------------------------------- /port/10_WhatCanISee_02_eyesight/src/game_stage.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // From our game design perspective, GameStage is a group of systems that require the commands in the 4 | // previous group to be flushed. 5 | // See `mod.rs`. 6 | // 7 | #[derive(Debug, Clone, Eq, PartialEq, Hash, StageLabel)] 8 | pub enum GameStage { 9 | // The first stage (player input) is the standard Update 10 | PlayerCombat, 11 | MovePlayer, 12 | PlayerFov, 13 | GenerateMonsterMoves, 14 | MonsterCombat, 15 | MoveMonsters, 16 | MonsterFov, 17 | } 18 | -------------------------------------------------------------------------------- /port/10_WhatCanISee_02_eyesight/src/systems/combat.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn combat( 4 | mut commands: Commands, 5 | mut attack_events: EventReader, 6 | mut health_query: Query<&mut Health>, 7 | player_query: Query<&Player>, 8 | ) { 9 | // We can conveniently iterate the message reader, and destructure the message. 10 | for WantsToAttack { victim, .. } in attack_events.iter() { 11 | let is_player = player_query.get(*victim).is_ok(); 12 | 13 | if let Ok(mut health) = health_query.get_mut(*victim) { 14 | health.current -= 1; 15 | if health.current < 1 && !is_player { 16 | commands.entity(*victim).despawn(); 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /port/10_WhatCanISee_02_eyesight/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn entity_render( 4 | renderables: Query<(&PointC, &Render)>, 5 | player_fov_query: Query<&FieldOfView, With>, 6 | camera: Res, 7 | ) { 8 | let mut draw_batch = DrawBatch::new(); 9 | draw_batch.target(1); 10 | let offset = Point::new(camera.left_x, camera.top_y); 11 | 12 | let player_fov = player_fov_query.single(); 13 | 14 | for (pos, render) in renderables.iter() { 15 | if player_fov.visible_tiles.contains(&pos.0) { 16 | draw_batch.set(pos.0 - offset, render.color, render.glyph); 17 | } 18 | } 19 | 20 | draw_batch.submit(5000).expect("Batch error"); 21 | } 22 | -------------------------------------------------------------------------------- /port/10_WhatCanISee_02_eyesight/src/systems/fov.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn fov(mut views: Query<(&PointC, &mut FieldOfView)>, map: Res) { 4 | for (pos, mut fov) in views.iter_mut() { 5 | if fov.is_dirty { 6 | fov.visible_tiles = field_of_view_set(pos.0, fov.radius, map.as_ref()); 7 | fov.is_dirty = false; 8 | }; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /port/10_WhatCanISee_02_eyesight/src/systems/hud.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn hud(player_query: Query<&Health, With>) { 4 | let player_health = player_query.single(); 5 | 6 | let mut draw_batch = DrawBatch::new(); 7 | draw_batch.target(2); 8 | draw_batch.print_centered(1, "Explore the Dungeon. Cursor keys to move."); 9 | draw_batch.bar_horizontal( 10 | Point::zero(), 11 | SCREEN_WIDTH * 2, 12 | player_health.current, 13 | player_health.max, 14 | ColorPair::new(RED, BLACK), 15 | ); 16 | draw_batch.print_color_centered( 17 | 0, 18 | format!( 19 | " Health: {} / {} ", 20 | player_health.current, player_health.max 21 | ), 22 | ColorPair::new(WHITE, RED), 23 | ); 24 | draw_batch.submit(10000).expect("Batch error"); 25 | } 26 | -------------------------------------------------------------------------------- /port/10_WhatCanISee_02_eyesight/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, Eq, PartialEq, Hash)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | GameOver, 7 | Victory, 8 | } 9 | -------------------------------------------------------------------------------- /port/10_WhatCanISee_03_memory/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Herbert Wolverson ", "Saverio Miroddi "] 3 | edition = "2021" 4 | name = "rusty_roguelike-bevy" 5 | version = "0.1.0" 6 | 7 | [dependencies] 8 | bevy = {version = "0.7.0", default-features = false, features = ["dynamic"]} 9 | bracket-lib = "~0.8.1" 10 | iyes_loopless = "0.5.1" 11 | -------------------------------------------------------------------------------- /port/10_WhatCanISee_03_memory/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/10_WhatCanISee_03_memory/resources/dungeonfont.png -------------------------------------------------------------------------------- /port/10_WhatCanISee_03_memory/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/10_WhatCanISee_03_memory/resources/terminal8x8.png -------------------------------------------------------------------------------- /port/10_WhatCanISee_03_memory/src/events.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // Differently from the source project, which uses resources, we use Bevy's messaging system for move 4 | // and attack messages. 5 | // In the context of this project, it's a bit more ergonomic, but in larger ones, there advantages are 6 | // more significant. 7 | // Watch out! Events persist for two frames, which in this design is not a problem, but it's something 8 | // important to know. 9 | 10 | pub struct WantsToMove { 11 | pub entity: Entity, 12 | // Event type fields don't need to be components; in this case we don't need to use PointC, but 13 | // it can be trivially done. 14 | pub destination: Point, 15 | } 16 | 17 | pub struct WantsToAttack { 18 | pub attacker: Entity, 19 | pub victim: Entity, 20 | } 21 | -------------------------------------------------------------------------------- /port/10_WhatCanISee_03_memory/src/game_stage.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // From our game design perspective, GameStage is a group of systems that require the commands in the 4 | // previous group to be flushed. 5 | // See `mod.rs`. 6 | // 7 | #[derive(Debug, Clone, Eq, PartialEq, Hash, StageLabel)] 8 | pub enum GameStage { 9 | // The first stage (player input) is the standard Update 10 | PlayerCombat, 11 | MovePlayer, 12 | PlayerFov, 13 | GenerateMonsterMoves, 14 | MonsterCombat, 15 | MoveMonsters, 16 | MonsterFov, 17 | } 18 | -------------------------------------------------------------------------------- /port/10_WhatCanISee_03_memory/src/systems/combat.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn combat( 4 | mut commands: Commands, 5 | mut attack_events: EventReader, 6 | mut health_query: Query<&mut Health>, 7 | player_query: Query<&Player>, 8 | ) { 9 | // We can conveniently iterate the message reader, and destructure the message. 10 | for WantsToAttack { victim, .. } in attack_events.iter() { 11 | let is_player = player_query.get(*victim).is_ok(); 12 | 13 | if let Ok(mut health) = health_query.get_mut(*victim) { 14 | health.current -= 1; 15 | if health.current < 1 && !is_player { 16 | commands.entity(*victim).despawn(); 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /port/10_WhatCanISee_03_memory/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn entity_render( 4 | renderables: Query<(&PointC, &Render)>, 5 | player_fov_query: Query<&FieldOfView, With>, 6 | camera: Res, 7 | ) { 8 | let mut draw_batch = DrawBatch::new(); 9 | draw_batch.target(1); 10 | let offset = Point::new(camera.left_x, camera.top_y); 11 | 12 | let player_fov = player_fov_query.single(); 13 | 14 | for (pos, render) in renderables.iter() { 15 | if player_fov.visible_tiles.contains(&pos.0) { 16 | draw_batch.set(pos.0 - offset, render.color, render.glyph); 17 | } 18 | } 19 | 20 | draw_batch.submit(5000).expect("Batch error"); 21 | } 22 | -------------------------------------------------------------------------------- /port/10_WhatCanISee_03_memory/src/systems/fov.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn fov(mut views: Query<(&PointC, &mut FieldOfView)>, map: Res) { 4 | for (pos, mut fov) in views.iter_mut() { 5 | if fov.is_dirty { 6 | fov.visible_tiles = field_of_view_set(pos.0, fov.radius, map.as_ref()); 7 | fov.is_dirty = false; 8 | }; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /port/10_WhatCanISee_03_memory/src/systems/hud.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn hud(player_query: Query<&Health, With>) { 4 | let player_health = player_query.single(); 5 | 6 | let mut draw_batch = DrawBatch::new(); 7 | draw_batch.target(2); 8 | draw_batch.print_centered(1, "Explore the Dungeon. Cursor keys to move."); 9 | draw_batch.bar_horizontal( 10 | Point::zero(), 11 | SCREEN_WIDTH * 2, 12 | player_health.current, 13 | player_health.max, 14 | ColorPair::new(RED, BLACK), 15 | ); 16 | draw_batch.print_color_centered( 17 | 0, 18 | format!( 19 | " Health: {} / {} ", 20 | player_health.current, player_health.max 21 | ), 22 | ColorPair::new(WHITE, RED), 23 | ); 24 | draw_batch.submit(10000).expect("Batch error"); 25 | } 26 | -------------------------------------------------------------------------------- /port/10_WhatCanISee_03_memory/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, Eq, PartialEq, Hash)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | GameOver, 7 | Victory, 8 | } 9 | -------------------------------------------------------------------------------- /port/11_MoreInterestingDungeons/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Herbert Wolverson ", "Saverio Miroddi "] 3 | edition = "2021" 4 | name = "rusty_roguelike-bevy" 5 | version = "0.1.0" 6 | 7 | [dependencies] 8 | bevy = {version = "0.7.0", default-features = false, features = ["dynamic"]} 9 | bracket-lib = "~0.8.1" 10 | iyes_loopless = "0.5.1" 11 | -------------------------------------------------------------------------------- /port/11_MoreInterestingDungeons/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/11_MoreInterestingDungeons/resources/dungeonfont.png -------------------------------------------------------------------------------- /port/11_MoreInterestingDungeons/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/11_MoreInterestingDungeons/resources/terminal8x8.png -------------------------------------------------------------------------------- /port/11_MoreInterestingDungeons/src/events.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // Differently from the source project, which uses resources, we use Bevy's messaging system for move 4 | // and attack messages. 5 | // In the context of this project, it's a bit more ergonomic, but in larger ones, there advantages are 6 | // more significant. 7 | // Watch out! Events persist for two frames, which in this design is not a problem, but it's something 8 | // important to know. 9 | 10 | pub struct WantsToMove { 11 | pub entity: Entity, 12 | // Event type fields don't need to be components; in this case we don't need to use PointC, but 13 | // it can be trivially done. 14 | pub destination: Point, 15 | } 16 | 17 | pub struct WantsToAttack { 18 | pub attacker: Entity, 19 | pub victim: Entity, 20 | } 21 | -------------------------------------------------------------------------------- /port/11_MoreInterestingDungeons/src/game_stage.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // From our game design perspective, GameStage is a group of systems that require the commands in the 4 | // previous group to be flushed. 5 | // See `mod.rs`. 6 | // 7 | #[derive(Debug, Clone, Eq, PartialEq, Hash, StageLabel)] 8 | pub enum GameStage { 9 | // The first stage (player input) is the standard Update 10 | PlayerCombat, 11 | MovePlayer, 12 | PlayerFov, 13 | GenerateMonsterMoves, 14 | MonsterCombat, 15 | MoveMonsters, 16 | MonsterFov, 17 | } 18 | -------------------------------------------------------------------------------- /port/11_MoreInterestingDungeons/src/map_builder/rooms.rs: -------------------------------------------------------------------------------- 1 | use super::MapArchitect; 2 | use crate::prelude::*; 3 | 4 | pub struct RoomsArchitect {} 5 | 6 | impl MapArchitect for RoomsArchitect { 7 | fn new(&mut self, rng: &mut RandomNumberGenerator) -> MapBuilder { 8 | let mut mb = MapBuilder { 9 | map: Map::new(), 10 | rooms: Vec::new(), 11 | monster_spawns: Vec::new(), 12 | player_start: Point::zero(), 13 | amulet_start: Point::zero(), 14 | }; 15 | 16 | mb.fill(TileType::Wall); 17 | mb.build_random_rooms(rng); 18 | mb.build_corridors(rng); 19 | mb.player_start = mb.rooms[0].center(); 20 | mb.amulet_start = mb.find_most_distant(); 21 | for room in mb.rooms.iter().skip(1) { 22 | mb.monster_spawns.push(room.center()); 23 | } 24 | 25 | mb 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /port/11_MoreInterestingDungeons/src/systems/combat.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn combat( 4 | mut commands: Commands, 5 | mut attack_events: EventReader, 6 | mut health_query: Query<&mut Health>, 7 | player_query: Query<&Player>, 8 | ) { 9 | // We can conveniently iterate the message reader, and destructure the message. 10 | for WantsToAttack { victim, .. } in attack_events.iter() { 11 | let is_player = player_query.get(*victim).is_ok(); 12 | 13 | if let Ok(mut health) = health_query.get_mut(*victim) { 14 | health.current -= 1; 15 | if health.current < 1 && !is_player { 16 | commands.entity(*victim).despawn(); 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /port/11_MoreInterestingDungeons/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn entity_render( 4 | renderables: Query<(&PointC, &Render)>, 5 | player_fov_query: Query<&FieldOfView, With>, 6 | camera: Res, 7 | ) { 8 | let mut draw_batch = DrawBatch::new(); 9 | draw_batch.target(1); 10 | let offset = Point::new(camera.left_x, camera.top_y); 11 | 12 | let player_fov = player_fov_query.single(); 13 | 14 | for (pos, render) in renderables.iter() { 15 | if player_fov.visible_tiles.contains(&pos.0) { 16 | draw_batch.set(pos.0 - offset, render.color, render.glyph); 17 | } 18 | } 19 | 20 | draw_batch.submit(5000).expect("Batch error"); 21 | } 22 | -------------------------------------------------------------------------------- /port/11_MoreInterestingDungeons/src/systems/fov.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn fov(mut views: Query<(&PointC, &mut FieldOfView)>, map: Res) { 4 | for (pos, mut fov) in views.iter_mut() { 5 | if fov.is_dirty { 6 | fov.visible_tiles = field_of_view_set(pos.0, fov.radius, map.as_ref()); 7 | fov.is_dirty = false; 8 | }; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /port/11_MoreInterestingDungeons/src/systems/hud.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn hud(player_query: Query<&Health, With>) { 4 | let player_health = player_query.single(); 5 | 6 | let mut draw_batch = DrawBatch::new(); 7 | draw_batch.target(2); 8 | draw_batch.print_centered(1, "Explore the Dungeon. Cursor keys to move."); 9 | draw_batch.bar_horizontal( 10 | Point::zero(), 11 | SCREEN_WIDTH * 2, 12 | player_health.current, 13 | player_health.max, 14 | ColorPair::new(RED, BLACK), 15 | ); 16 | draw_batch.print_color_centered( 17 | 0, 18 | format!( 19 | " Health: {} / {} ", 20 | player_health.current, player_health.max 21 | ), 22 | ColorPair::new(WHITE, RED), 23 | ); 24 | draw_batch.submit(10000).expect("Batch error"); 25 | } 26 | -------------------------------------------------------------------------------- /port/11_MoreInterestingDungeons/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, Eq, PartialEq, Hash)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | GameOver, 7 | Victory, 8 | } 9 | -------------------------------------------------------------------------------- /port/12_MapTheming/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Herbert Wolverson ", "Saverio Miroddi "] 3 | edition = "2021" 4 | name = "rusty_roguelike-bevy" 5 | version = "0.1.0" 6 | 7 | [dependencies] 8 | bevy = {version = "0.7.0", default-features = false, features = ["dynamic"]} 9 | bracket-lib = "~0.8.1" 10 | iyes_loopless = "0.5.1" 11 | -------------------------------------------------------------------------------- /port/12_MapTheming/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/12_MapTheming/resources/dungeonfont.png -------------------------------------------------------------------------------- /port/12_MapTheming/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/12_MapTheming/resources/terminal8x8.png -------------------------------------------------------------------------------- /port/12_MapTheming/src/events.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // Differently from the source project, which uses resources, we use Bevy's messaging system for move 4 | // and attack messages. 5 | // In the context of this project, it's a bit more ergonomic, but in larger ones, there advantages are 6 | // more significant. 7 | // Watch out! Events persist for two frames, which in this design is not a problem, but it's something 8 | // important to know. 9 | 10 | pub struct WantsToMove { 11 | pub entity: Entity, 12 | // Event type fields don't need to be components; in this case we don't need to use PointC, but 13 | // it can be trivially done. 14 | pub destination: Point, 15 | } 16 | 17 | pub struct WantsToAttack { 18 | pub attacker: Entity, 19 | pub victim: Entity, 20 | } 21 | -------------------------------------------------------------------------------- /port/12_MapTheming/src/game_stage.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // From our game design perspective, GameStage is a group of systems that require the commands in the 4 | // previous group to be flushed. 5 | // See `mod.rs`. 6 | // 7 | #[derive(Debug, Clone, Eq, PartialEq, Hash, StageLabel)] 8 | pub enum GameStage { 9 | // The first stage (player input) is the standard Update 10 | PlayerCombat, 11 | MovePlayer, 12 | PlayerFov, 13 | GenerateMonsterMoves, 14 | MonsterCombat, 15 | MoveMonsters, 16 | MonsterFov, 17 | } 18 | -------------------------------------------------------------------------------- /port/12_MapTheming/src/systems/combat.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn combat( 4 | mut commands: Commands, 5 | mut attack_events: EventReader, 6 | mut health_query: Query<&mut Health>, 7 | player_query: Query<&Player>, 8 | ) { 9 | // We can conveniently iterate the message reader, and destructure the message. 10 | for WantsToAttack { victim, .. } in attack_events.iter() { 11 | let is_player = player_query.get(*victim).is_ok(); 12 | 13 | if let Ok(mut health) = health_query.get_mut(*victim) { 14 | health.current -= 1; 15 | if health.current < 1 && !is_player { 16 | commands.entity(*victim).despawn(); 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /port/12_MapTheming/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn entity_render( 4 | renderables: Query<(&PointC, &Render)>, 5 | player_fov_query: Query<&FieldOfView, With>, 6 | camera: Res, 7 | ) { 8 | let mut draw_batch = DrawBatch::new(); 9 | draw_batch.target(1); 10 | let offset = Point::new(camera.left_x, camera.top_y); 11 | 12 | let player_fov = player_fov_query.single(); 13 | 14 | for (pos, render) in renderables.iter() { 15 | if player_fov.visible_tiles.contains(&pos.0) { 16 | draw_batch.set(pos.0 - offset, render.color, render.glyph); 17 | } 18 | } 19 | 20 | draw_batch.submit(5000).expect("Batch error"); 21 | } 22 | -------------------------------------------------------------------------------- /port/12_MapTheming/src/systems/fov.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn fov(mut views: Query<(&PointC, &mut FieldOfView)>, map: Res) { 4 | for (pos, mut fov) in views.iter_mut() { 5 | if fov.is_dirty { 6 | fov.visible_tiles = field_of_view_set(pos.0, fov.radius, map.as_ref()); 7 | fov.is_dirty = false; 8 | }; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /port/12_MapTheming/src/systems/hud.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn hud(player_query: Query<&Health, With>) { 4 | let player_health = player_query.single(); 5 | 6 | let mut draw_batch = DrawBatch::new(); 7 | draw_batch.target(2); 8 | draw_batch.print_centered(1, "Explore the Dungeon. Cursor keys to move."); 9 | draw_batch.bar_horizontal( 10 | Point::zero(), 11 | SCREEN_WIDTH * 2, 12 | player_health.current, 13 | player_health.max, 14 | ColorPair::new(RED, BLACK), 15 | ); 16 | draw_batch.print_color_centered( 17 | 0, 18 | format!( 19 | " Health: {} / {} ", 20 | player_health.current, player_health.max 21 | ), 22 | ColorPair::new(WHITE, RED), 23 | ); 24 | draw_batch.submit(10000).expect("Batch error"); 25 | } 26 | -------------------------------------------------------------------------------- /port/12_MapTheming/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, Eq, PartialEq, Hash)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | GameOver, 7 | Victory, 8 | } 9 | -------------------------------------------------------------------------------- /port/13_InventoryAndPowerUps_01_potions_and_scrolls/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Herbert Wolverson ", "Saverio Miroddi "] 3 | edition = "2021" 4 | name = "rusty_roguelike-bevy" 5 | version = "0.1.0" 6 | 7 | [dependencies] 8 | bevy = {version = "0.7.0", default-features = false, features = ["dynamic"]} 9 | bracket-lib = "~0.8.1" 10 | iyes_loopless = "0.5.1" 11 | -------------------------------------------------------------------------------- /port/13_InventoryAndPowerUps_01_potions_and_scrolls/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/13_InventoryAndPowerUps_01_potions_and_scrolls/resources/dungeonfont.png -------------------------------------------------------------------------------- /port/13_InventoryAndPowerUps_01_potions_and_scrolls/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/13_InventoryAndPowerUps_01_potions_and_scrolls/resources/terminal8x8.png -------------------------------------------------------------------------------- /port/13_InventoryAndPowerUps_01_potions_and_scrolls/src/events.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // Differently from the source project, which uses resources, we use Bevy's messaging system for move 4 | // and attack messages. 5 | // In the context of this project, it's a bit more ergonomic, but in larger ones, there advantages are 6 | // more significant. 7 | // Watch out! Events persist for two frames, which in this design is not a problem, but it's something 8 | // important to know. 9 | 10 | pub struct WantsToMove { 11 | pub entity: Entity, 12 | // Event type fields don't need to be components; in this case we don't need to use PointC, but 13 | // it can be trivially done. 14 | pub destination: Point, 15 | } 16 | 17 | pub struct WantsToAttack { 18 | pub attacker: Entity, 19 | pub victim: Entity, 20 | } 21 | -------------------------------------------------------------------------------- /port/13_InventoryAndPowerUps_01_potions_and_scrolls/src/game_stage.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // From our game design perspective, GameStage is a group of systems that require the commands in the 4 | // previous group to be flushed. 5 | // See `mod.rs`. 6 | // 7 | #[derive(Debug, Clone, Eq, PartialEq, Hash, StageLabel)] 8 | pub enum GameStage { 9 | // The first stage (player input) is the standard Update 10 | PlayerCombat, 11 | MovePlayer, 12 | PlayerFov, 13 | GenerateMonsterMoves, 14 | MonsterCombat, 15 | MoveMonsters, 16 | MonsterFov, 17 | } 18 | -------------------------------------------------------------------------------- /port/13_InventoryAndPowerUps_01_potions_and_scrolls/src/systems/combat.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn combat( 4 | mut commands: Commands, 5 | mut attack_events: EventReader, 6 | mut health_query: Query<&mut Health>, 7 | player_query: Query<&Player>, 8 | ) { 9 | // We can conveniently iterate the message reader, and destructure the message. 10 | for WantsToAttack { victim, .. } in attack_events.iter() { 11 | let is_player = player_query.get(*victim).is_ok(); 12 | 13 | if let Ok(mut health) = health_query.get_mut(*victim) { 14 | health.current -= 1; 15 | if health.current < 1 && !is_player { 16 | commands.entity(*victim).despawn(); 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /port/13_InventoryAndPowerUps_01_potions_and_scrolls/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn entity_render( 4 | renderables: Query<(&PointC, &Render)>, 5 | player_fov_query: Query<&FieldOfView, With>, 6 | camera: Res, 7 | ) { 8 | let mut draw_batch = DrawBatch::new(); 9 | draw_batch.target(1); 10 | let offset = Point::new(camera.left_x, camera.top_y); 11 | 12 | let player_fov = player_fov_query.single(); 13 | 14 | for (pos, render) in renderables.iter() { 15 | if player_fov.visible_tiles.contains(&pos.0) { 16 | draw_batch.set(pos.0 - offset, render.color, render.glyph); 17 | } 18 | } 19 | 20 | draw_batch.submit(5000).expect("Batch error"); 21 | } 22 | -------------------------------------------------------------------------------- /port/13_InventoryAndPowerUps_01_potions_and_scrolls/src/systems/fov.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn fov(mut views: Query<(&PointC, &mut FieldOfView)>, map: Res) { 4 | for (pos, mut fov) in views.iter_mut() { 5 | if fov.is_dirty { 6 | fov.visible_tiles = field_of_view_set(pos.0, fov.radius, map.as_ref()); 7 | fov.is_dirty = false; 8 | }; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /port/13_InventoryAndPowerUps_01_potions_and_scrolls/src/systems/hud.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn hud(player_query: Query<&Health, With>) { 4 | let player_health = player_query.single(); 5 | 6 | let mut draw_batch = DrawBatch::new(); 7 | draw_batch.target(2); 8 | draw_batch.print_centered(1, "Explore the Dungeon. Cursor keys to move."); 9 | draw_batch.bar_horizontal( 10 | Point::zero(), 11 | SCREEN_WIDTH * 2, 12 | player_health.current, 13 | player_health.max, 14 | ColorPair::new(RED, BLACK), 15 | ); 16 | draw_batch.print_color_centered( 17 | 0, 18 | format!( 19 | " Health: {} / {} ", 20 | player_health.current, player_health.max 21 | ), 22 | ColorPair::new(WHITE, RED), 23 | ); 24 | draw_batch.submit(10000).expect("Batch error"); 25 | } 26 | -------------------------------------------------------------------------------- /port/13_InventoryAndPowerUps_01_potions_and_scrolls/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, Eq, PartialEq, Hash)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | GameOver, 7 | Victory, 8 | } 9 | -------------------------------------------------------------------------------- /port/13_InventoryAndPowerUps_02_carrying_items/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Herbert Wolverson ", "Saverio Miroddi "] 3 | edition = "2021" 4 | name = "rusty_roguelike-bevy" 5 | version = "0.1.0" 6 | 7 | [dependencies] 8 | bevy = {version = "0.7.0", default-features = false, features = ["dynamic"]} 9 | bracket-lib = "~0.8.1" 10 | iyes_loopless = "0.5.1" 11 | -------------------------------------------------------------------------------- /port/13_InventoryAndPowerUps_02_carrying_items/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/13_InventoryAndPowerUps_02_carrying_items/resources/dungeonfont.png -------------------------------------------------------------------------------- /port/13_InventoryAndPowerUps_02_carrying_items/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/13_InventoryAndPowerUps_02_carrying_items/resources/terminal8x8.png -------------------------------------------------------------------------------- /port/13_InventoryAndPowerUps_02_carrying_items/src/game_stage.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // From our game design perspective, GameStage is a group of systems that require the commands in the 4 | // previous group to be flushed. 5 | // See `mod.rs`. 6 | // 7 | #[derive(Debug, Clone, Eq, PartialEq, Hash, StageLabel)] 8 | pub enum GameStage { 9 | // The first stage (player input) is the standard Update 10 | PlayerCombat, 11 | MovePlayer, 12 | PlayerFov, 13 | GenerateMonsterMoves, 14 | MonsterCombat, 15 | MoveMonsters, 16 | MonsterFov, 17 | } 18 | -------------------------------------------------------------------------------- /port/13_InventoryAndPowerUps_02_carrying_items/src/systems/combat.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn combat( 4 | mut commands: Commands, 5 | mut attack_events: EventReader, 6 | mut health_query: Query<&mut Health>, 7 | player_query: Query<&Player>, 8 | ) { 9 | // We can conveniently iterate the message reader, and destructure the message. 10 | for WantsToAttack { victim, .. } in attack_events.iter() { 11 | let is_player = player_query.get(*victim).is_ok(); 12 | 13 | if let Ok(mut health) = health_query.get_mut(*victim) { 14 | health.current -= 1; 15 | if health.current < 1 && !is_player { 16 | commands.entity(*victim).despawn(); 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /port/13_InventoryAndPowerUps_02_carrying_items/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn entity_render( 4 | renderables: Query<(&PointC, &Render)>, 5 | player_fov_query: Query<&FieldOfView, With>, 6 | camera: Res, 7 | ) { 8 | let mut draw_batch = DrawBatch::new(); 9 | draw_batch.target(1); 10 | let offset = Point::new(camera.left_x, camera.top_y); 11 | 12 | let player_fov = player_fov_query.single(); 13 | 14 | for (pos, render) in renderables.iter() { 15 | if player_fov.visible_tiles.contains(&pos.0) { 16 | draw_batch.set(pos.0 - offset, render.color, render.glyph); 17 | } 18 | } 19 | 20 | draw_batch.submit(5000).expect("Batch error"); 21 | } 22 | -------------------------------------------------------------------------------- /port/13_InventoryAndPowerUps_02_carrying_items/src/systems/fov.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn fov(mut views: Query<(&PointC, &mut FieldOfView)>, map: Res) { 4 | for (pos, mut fov) in views.iter_mut() { 5 | if fov.is_dirty { 6 | fov.visible_tiles = field_of_view_set(pos.0, fov.radius, map.as_ref()); 7 | fov.is_dirty = false; 8 | }; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /port/13_InventoryAndPowerUps_02_carrying_items/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, Eq, PartialEq, Hash)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | GameOver, 7 | Victory, 8 | } 9 | -------------------------------------------------------------------------------- /port/14_DeeperDungeons/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Herbert Wolverson ", "Saverio Miroddi "] 3 | edition = "2021" 4 | name = "rusty_roguelike-bevy" 5 | version = "0.1.0" 6 | 7 | [dependencies] 8 | bevy = {version = "0.7.0", default-features = false, features = ["dynamic"]} 9 | bracket-lib = "~0.8.1" 10 | iyes_loopless = "0.5.1" 11 | -------------------------------------------------------------------------------- /port/14_DeeperDungeons/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/14_DeeperDungeons/resources/dungeonfont.png -------------------------------------------------------------------------------- /port/14_DeeperDungeons/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/14_DeeperDungeons/resources/terminal8x8.png -------------------------------------------------------------------------------- /port/14_DeeperDungeons/src/events.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // Differently from the source project, which uses resources, we use Bevy's messaging system for move 4 | // and attack messages. 5 | // In the context of this project, it's a bit more ergonomic, but in larger ones, there advantages are 6 | // more significant. 7 | // Watch out! Events persist for two frames, which in this design is not a problem, but it's something 8 | // important to know. 9 | 10 | pub struct WantsToMove { 11 | pub entity: Entity, 12 | // Event type fields don't need to be components; in this case we don't need to use PointC, but 13 | // it can be trivially done. 14 | pub destination: Point, 15 | } 16 | 17 | pub struct WantsToAttack { 18 | pub attacker: Entity, 19 | pub victim: Entity, 20 | } 21 | 22 | pub struct ActivateItem { 23 | pub used_by: Entity, 24 | pub item: Entity, 25 | } 26 | -------------------------------------------------------------------------------- /port/14_DeeperDungeons/src/game_stage.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // From our game design perspective, GameStage is a group of systems that require the commands in the 4 | // previous group to be flushed. 5 | // See `mod.rs`. 6 | // 7 | #[derive(Debug, Clone, Eq, PartialEq, Hash, StageLabel)] 8 | pub enum GameStage { 9 | // The first stage (player input) is the standard Update 10 | PlayerCombat, 11 | MovePlayer, 12 | PlayerFov, 13 | GenerateMonsterMoves, 14 | MonsterCombat, 15 | MoveMonsters, 16 | MonsterFov, 17 | } 18 | -------------------------------------------------------------------------------- /port/14_DeeperDungeons/src/systems/combat.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn combat( 4 | mut commands: Commands, 5 | mut attack_events: EventReader, 6 | mut health_query: Query<&mut Health>, 7 | player_query: Query<&Player>, 8 | ) { 9 | // We can conveniently iterate the message reader, and destructure the message. 10 | for WantsToAttack { victim, .. } in attack_events.iter() { 11 | let is_player = player_query.get(*victim).is_ok(); 12 | 13 | if let Ok(mut health) = health_query.get_mut(*victim) { 14 | health.current -= 1; 15 | if health.current < 1 && !is_player { 16 | commands.entity(*victim).despawn(); 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /port/14_DeeperDungeons/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn entity_render( 4 | renderables: Query<(&PointC, &Render)>, 5 | player_fov_query: Query<&FieldOfView, With>, 6 | camera: Res, 7 | ) { 8 | let mut draw_batch = DrawBatch::new(); 9 | draw_batch.target(1); 10 | let offset = Point::new(camera.left_x, camera.top_y); 11 | 12 | let player_fov = player_fov_query.single(); 13 | 14 | for (pos, render) in renderables.iter() { 15 | if player_fov.visible_tiles.contains(&pos.0) { 16 | draw_batch.set(pos.0 - offset, render.color, render.glyph); 17 | } 18 | } 19 | 20 | draw_batch.submit(5000).expect("Batch error"); 21 | } 22 | -------------------------------------------------------------------------------- /port/14_DeeperDungeons/src/systems/fov.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn fov(mut views: Query<(&PointC, &mut FieldOfView)>, map: Res) { 4 | for (pos, mut fov) in views.iter_mut() { 5 | if fov.is_dirty { 6 | fov.visible_tiles = field_of_view_set(pos.0, fov.radius, map.as_ref()); 7 | fov.is_dirty = false; 8 | }; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /port/14_DeeperDungeons/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, Eq, PartialEq, Hash)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | GameOver, 7 | Victory, 8 | NextLevel, 9 | } 10 | -------------------------------------------------------------------------------- /port/15_Loot_01_loot_tables/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Herbert Wolverson ", "Saverio Miroddi "] 3 | edition = "2021" 4 | name = "rusty_roguelike-bevy" 5 | version = "0.1.0" 6 | 7 | [dependencies] 8 | bevy = {version = "0.7.0", default-features = false, features = ["dynamic"]} 9 | bracket-lib = "~0.8.1" 10 | iyes_loopless = "0.5.1" 11 | ron = "0.6.1" 12 | serde = "1.0.115" 13 | -------------------------------------------------------------------------------- /port/15_Loot_01_loot_tables/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/15_Loot_01_loot_tables/resources/dungeonfont.png -------------------------------------------------------------------------------- /port/15_Loot_01_loot_tables/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/15_Loot_01_loot_tables/resources/terminal8x8.png -------------------------------------------------------------------------------- /port/15_Loot_01_loot_tables/src/events.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // Differently from the source project, which uses resources, we use Bevy's messaging system for move 4 | // and attack messages. 5 | // In the context of this project, it's a bit more ergonomic, but in larger ones, there advantages are 6 | // more significant. 7 | // Watch out! Events persist for two frames, which in this design is not a problem, but it's something 8 | // important to know. 9 | 10 | pub struct WantsToMove { 11 | pub entity: Entity, 12 | // Event type fields don't need to be components; in this case we don't need to use PointC, but 13 | // it can be trivially done. 14 | pub destination: Point, 15 | } 16 | 17 | pub struct WantsToAttack { 18 | pub attacker: Entity, 19 | pub victim: Entity, 20 | } 21 | 22 | pub struct ActivateItem { 23 | pub used_by: Entity, 24 | pub item: Entity, 25 | } 26 | -------------------------------------------------------------------------------- /port/15_Loot_01_loot_tables/src/game_stage.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // From our game design perspective, GameStage is a group of systems that require the commands in the 4 | // previous group to be flushed. 5 | // See `mod.rs`. 6 | // 7 | #[derive(Debug, Clone, Eq, PartialEq, Hash, StageLabel)] 8 | pub enum GameStage { 9 | // The first stage (player input) is the standard Update 10 | PlayerCombat, 11 | MovePlayer, 12 | PlayerFov, 13 | GenerateMonsterMoves, 14 | MonsterCombat, 15 | MoveMonsters, 16 | MonsterFov, 17 | } 18 | -------------------------------------------------------------------------------- /port/15_Loot_01_loot_tables/src/systems/combat.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn combat( 4 | mut commands: Commands, 5 | mut attack_events: EventReader, 6 | mut health_query: Query<&mut Health>, 7 | player_query: Query<&Player>, 8 | ) { 9 | // We can conveniently iterate the message reader, and destructure the message. 10 | for WantsToAttack { victim, .. } in attack_events.iter() { 11 | let is_player = player_query.get(*victim).is_ok(); 12 | 13 | if let Ok(mut health) = health_query.get_mut(*victim) { 14 | health.current -= 1; 15 | if health.current < 1 && !is_player { 16 | commands.entity(*victim).despawn(); 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /port/15_Loot_01_loot_tables/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn entity_render( 4 | renderables: Query<(&PointC, &Render)>, 5 | player_fov_query: Query<&FieldOfView, With>, 6 | camera: Res, 7 | ) { 8 | let mut draw_batch = DrawBatch::new(); 9 | draw_batch.target(1); 10 | let offset = Point::new(camera.left_x, camera.top_y); 11 | 12 | let player_fov = player_fov_query.single(); 13 | 14 | for (pos, render) in renderables.iter() { 15 | if player_fov.visible_tiles.contains(&pos.0) { 16 | draw_batch.set(pos.0 - offset, render.color, render.glyph); 17 | } 18 | } 19 | 20 | draw_batch.submit(5000).expect("Batch error"); 21 | } 22 | -------------------------------------------------------------------------------- /port/15_Loot_01_loot_tables/src/systems/fov.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn fov(mut views: Query<(&PointC, &mut FieldOfView)>, map: Res) { 4 | for (pos, mut fov) in views.iter_mut() { 5 | if fov.is_dirty { 6 | fov.visible_tiles = field_of_view_set(pos.0, fov.radius, map.as_ref()); 7 | fov.is_dirty = false; 8 | }; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /port/15_Loot_01_loot_tables/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, Eq, PartialEq, Hash)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | GameOver, 7 | Victory, 8 | NextLevel, 9 | } 10 | -------------------------------------------------------------------------------- /port/15_Loot_02_better_combat/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Herbert Wolverson ", "Saverio Miroddi "] 3 | edition = "2021" 4 | name = "rusty_roguelike-bevy" 5 | version = "0.1.0" 6 | 7 | [dependencies] 8 | bevy = {version = "0.7.0", default-features = false, features = ["dynamic"]} 9 | bracket-lib = "~0.8.1" 10 | iyes_loopless = "0.5.1" 11 | ron = "0.6.1" 12 | serde = "1.0.115" 13 | -------------------------------------------------------------------------------- /port/15_Loot_02_better_combat/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/15_Loot_02_better_combat/resources/dungeonfont.png -------------------------------------------------------------------------------- /port/15_Loot_02_better_combat/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/port/15_Loot_02_better_combat/resources/terminal8x8.png -------------------------------------------------------------------------------- /port/15_Loot_02_better_combat/src/events.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // Differently from the source project, which uses resources, we use Bevy's messaging system for move 4 | // and attack messages. 5 | // In the context of this project, it's a bit more ergonomic, but in larger ones, there advantages are 6 | // more significant. 7 | // Watch out! Events persist for two frames, which in this design is not a problem, but it's something 8 | // important to know. 9 | 10 | pub struct WantsToMove { 11 | pub entity: Entity, 12 | // Event type fields don't need to be components; in this case we don't need to use PointC, but 13 | // it can be trivially done. 14 | pub destination: Point, 15 | } 16 | 17 | pub struct WantsToAttack { 18 | pub attacker: Entity, 19 | pub victim: Entity, 20 | } 21 | 22 | pub struct ActivateItem { 23 | pub used_by: Entity, 24 | pub item: Entity, 25 | } 26 | -------------------------------------------------------------------------------- /port/15_Loot_02_better_combat/src/game_stage.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // From our game design perspective, GameStage is a group of systems that require the commands in the 4 | // previous group to be flushed. 5 | // See `mod.rs`. 6 | // 7 | #[derive(Debug, Clone, Eq, PartialEq, Hash, StageLabel)] 8 | pub enum GameStage { 9 | // The first stage (player input) is the standard Update 10 | PlayerCombat, 11 | MovePlayer, 12 | PlayerFov, 13 | GenerateMonsterMoves, 14 | MonsterCombat, 15 | MoveMonsters, 16 | MonsterFov, 17 | } 18 | -------------------------------------------------------------------------------- /port/15_Loot_02_better_combat/src/state_label.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // Only Fov is currently required; a String works as well, but this is the clean approach. 4 | // 5 | #[derive(Debug, Clone, PartialEq, Eq, Hash, SystemLabel)] 6 | pub enum StateLabel { 7 | Fov, 8 | } 9 | -------------------------------------------------------------------------------- /port/15_Loot_02_better_combat/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn entity_render( 4 | renderables: Query<(&PointC, &Render)>, 5 | player_fov_query: Query<&FieldOfView, With>, 6 | camera: Res, 7 | ) { 8 | let mut draw_batch = DrawBatch::new(); 9 | draw_batch.target(1); 10 | let offset = Point::new(camera.left_x, camera.top_y); 11 | 12 | let player_fov = player_fov_query.single(); 13 | 14 | for (pos, render) in renderables.iter() { 15 | if player_fov.visible_tiles.contains(&pos.0) { 16 | draw_batch.set(pos.0 - offset, render.color, render.glyph); 17 | } 18 | } 19 | 20 | draw_batch.submit(5000).expect("Batch error"); 21 | } 22 | -------------------------------------------------------------------------------- /port/15_Loot_02_better_combat/src/systems/fov.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn fov(mut views: Query<(&PointC, &mut FieldOfView)>, map: Res) { 4 | for (pos, mut fov) in views.iter_mut() { 5 | if fov.is_dirty { 6 | fov.visible_tiles = field_of_view_set(pos.0, fov.radius, map.as_ref()); 7 | fov.is_dirty = false; 8 | }; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /port/15_Loot_02_better_combat/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, Eq, PartialEq, Hash)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | GameOver, 7 | Victory, 8 | NextLevel, 9 | } 10 | -------------------------------------------------------------------------------- /source/06_EntitiesComponentsAndSystems_01_playerecs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "playerecs" 3 | version = "0.1.0" 4 | authors = ["Herbert Wolverson "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | bracket-lib = "~0.8.1" 11 | legion = "=0.3.1" 12 | -------------------------------------------------------------------------------- /source/06_EntitiesComponentsAndSystems_01_playerecs/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/06_EntitiesComponentsAndSystems_01_playerecs/resources/dungeonfont.png -------------------------------------------------------------------------------- /source/06_EntitiesComponentsAndSystems_01_playerecs/src/components.rs: -------------------------------------------------------------------------------- 1 | pub use crate::prelude::*; 2 | 3 | #[derive(Clone, Copy, Debug, PartialEq)] 4 | pub struct Render { 5 | pub color: ColorPair, 6 | pub glyph: FontCharType, 7 | } 8 | 9 | #[derive(Clone, Copy, Debug, PartialEq)] 10 | pub struct Player; 11 | -------------------------------------------------------------------------------- /source/06_EntitiesComponentsAndSystems_01_playerecs/src/spawner.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn spawn_player(ecs: &mut World, pos: Point) { 4 | ecs.push(( 5 | Player, 6 | pos, 7 | Render { 8 | color: ColorPair::new(WHITE, BLACK), 9 | glyph: to_cp437('@'), 10 | }, 11 | )); 12 | } 13 | -------------------------------------------------------------------------------- /source/06_EntitiesComponentsAndSystems_01_playerecs/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[read_component(Render)] 6 | pub fn entity_render(ecs: &SubWorld, #[resource] camera: &Camera) { 7 | let mut draw_batch = DrawBatch::new(); 8 | draw_batch.target(1); 9 | let offset = Point::new(camera.left_x, camera.top_y); 10 | 11 | <(&Point, &Render)>::query() 12 | .iter(ecs) 13 | .for_each(|(pos, render)| { 14 | draw_batch.set(*pos - offset, render.color, render.glyph); 15 | }); 16 | draw_batch.submit(5000).expect("Batch error"); 17 | } 18 | -------------------------------------------------------------------------------- /source/06_EntitiesComponentsAndSystems_01_playerecs/src/systems/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | mod entity_render; 4 | mod map_render; 5 | mod player_input; 6 | 7 | pub fn build_scheduler() -> Schedule { 8 | Schedule::builder() 9 | .add_system(player_input::player_input_system()) 10 | .add_system(map_render::map_render_system()) 11 | .add_system(entity_render::entity_render_system()) 12 | .build() 13 | } 14 | -------------------------------------------------------------------------------- /source/06_EntitiesComponentsAndSystems_02_dungeonecs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dungeonecs" 3 | version = "0.1.0" 4 | authors = ["Herbert Wolverson "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | bracket-lib = "~0.8.1" 9 | legion = "=0.3.1" 10 | -------------------------------------------------------------------------------- /source/06_EntitiesComponentsAndSystems_02_dungeonecs/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/06_EntitiesComponentsAndSystems_02_dungeonecs/resources/dungeonfont.png -------------------------------------------------------------------------------- /source/06_EntitiesComponentsAndSystems_02_dungeonecs/src/components.rs: -------------------------------------------------------------------------------- 1 | pub use crate::prelude::*; 2 | 3 | #[derive(Clone, Copy, Debug, PartialEq)] 4 | pub struct Render { 5 | pub color: ColorPair, 6 | pub glyph: FontCharType, 7 | } 8 | 9 | #[derive(Clone, Copy, Debug, PartialEq)] 10 | pub struct Player; 11 | 12 | #[derive(Clone, Copy, Debug, PartialEq)] 13 | pub struct Enemy; 14 | -------------------------------------------------------------------------------- /source/06_EntitiesComponentsAndSystems_02_dungeonecs/src/spawner.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn spawn_player(ecs: &mut World, pos: Point) { 4 | ecs.push(( 5 | Player, 6 | pos, 7 | Render { 8 | color: ColorPair::new(WHITE, BLACK), 9 | glyph: to_cp437('@'), 10 | }, 11 | )); 12 | } 13 | 14 | pub fn spawn_monster(ecs: &mut World, rng: &mut RandomNumberGenerator, pos: Point) { 15 | ecs.push(( 16 | Enemy, 17 | pos, 18 | Render { 19 | color: ColorPair::new(WHITE, BLACK), 20 | glyph: match rng.range(0, 4) { 21 | 0 => to_cp437('E'), 22 | 1 => to_cp437('O'), 23 | 2 => to_cp437('o'), 24 | _ => to_cp437('g'), 25 | }, 26 | }, 27 | )); 28 | } 29 | -------------------------------------------------------------------------------- /source/06_EntitiesComponentsAndSystems_02_dungeonecs/src/systems/collisions.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[read_component(Player)] 6 | #[read_component(Enemy)] 7 | pub fn collisions(ecs: &mut SubWorld, commands: &mut CommandBuffer) { 8 | let mut player_pos = Point::zero(); 9 | let mut players = <&Point>::query().filter(component::()); 10 | players.iter(ecs).for_each(|pos| player_pos = *pos); 11 | let mut enemies = <(Entity, &Point)>::query().filter(component::()); 12 | enemies 13 | .iter(ecs) 14 | .filter(|(_, pos)| **pos == player_pos) 15 | .for_each(|(entity, _)| { 16 | commands.remove(*entity); 17 | }); 18 | } 19 | -------------------------------------------------------------------------------- /source/06_EntitiesComponentsAndSystems_02_dungeonecs/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[read_component(Render)] 6 | pub fn entity_render(ecs: &SubWorld, #[resource] camera: &Camera) { 7 | let mut draw_batch = DrawBatch::new(); 8 | draw_batch.target(1); 9 | let offset = Point::new(camera.left_x, camera.top_y); 10 | 11 | <(&Point, &Render)>::query() 12 | .iter(ecs) 13 | .for_each(|(pos, render)| { 14 | draw_batch.set(*pos - offset, render.color, render.glyph); 15 | }); 16 | draw_batch.submit(5000).expect("Batch error"); 17 | } 18 | -------------------------------------------------------------------------------- /source/06_EntitiesComponentsAndSystems_02_dungeonecs/src/systems/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | mod collisions; 4 | mod entity_render; 5 | mod map_render; 6 | mod player_input; 7 | 8 | pub fn build_scheduler() -> Schedule { 9 | Schedule::builder() 10 | .add_system(player_input::player_input_system()) 11 | .add_system(collisions::collisions_system()) 12 | .add_system(map_render::map_render_system()) 13 | .add_system(entity_render::entity_render_system()) 14 | .build() 15 | } 16 | -------------------------------------------------------------------------------- /source/07_TurnBasedGames_01_wandering/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wandering" 3 | version = "0.1.0" 4 | authors = ["Herbert Wolverson "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | bracket-lib = "~0.8.1" 11 | legion = "=0.3.1" 12 | -------------------------------------------------------------------------------- /source/07_TurnBasedGames_01_wandering/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/07_TurnBasedGames_01_wandering/resources/dungeonfont.png -------------------------------------------------------------------------------- /source/07_TurnBasedGames_01_wandering/src/components.rs: -------------------------------------------------------------------------------- 1 | pub use crate::prelude::*; 2 | 3 | #[derive(Clone, Copy, Debug, PartialEq)] 4 | pub struct Render { 5 | pub color: ColorPair, 6 | pub glyph: FontCharType, 7 | } 8 | 9 | #[derive(Clone, Copy, Debug, PartialEq)] 10 | pub struct Player; 11 | 12 | #[derive(Clone, Copy, Debug, PartialEq)] 13 | pub struct Enemy; 14 | 15 | #[derive(Clone, Copy, Debug, PartialEq)] 16 | pub struct MovingRandomly; 17 | -------------------------------------------------------------------------------- /source/07_TurnBasedGames_01_wandering/src/spawner.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn spawn_player(ecs: &mut World, pos: Point) { 4 | ecs.push(( 5 | Player, 6 | pos, 7 | Render { 8 | color: ColorPair::new(WHITE, BLACK), 9 | glyph: to_cp437('@'), 10 | }, 11 | )); 12 | } 13 | 14 | pub fn spawn_monster(ecs: &mut World, rng: &mut RandomNumberGenerator, pos: Point) { 15 | ecs.push(( 16 | Enemy, 17 | pos, 18 | Render { 19 | color: ColorPair::new(WHITE, BLACK), 20 | glyph: match rng.range(0, 4) { 21 | 0 => to_cp437('E'), 22 | 1 => to_cp437('O'), 23 | 2 => to_cp437('o'), 24 | _ => to_cp437('g'), 25 | }, 26 | }, 27 | MovingRandomly {}, 28 | )); 29 | } 30 | -------------------------------------------------------------------------------- /source/07_TurnBasedGames_01_wandering/src/systems/collisions.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[read_component(Player)] 6 | #[read_component(Enemy)] 7 | pub fn collisions(ecs: &mut SubWorld, commands: &mut CommandBuffer) { 8 | let mut player_pos = Point::zero(); 9 | let mut players = <&Point>::query().filter(component::()); 10 | players.iter(ecs).for_each(|pos| player_pos = *pos); 11 | let mut enemies = <(Entity, &Point)>::query().filter(component::()); 12 | enemies 13 | .iter(ecs) 14 | .filter(|(_, pos)| **pos == player_pos) 15 | .for_each(|(entity, _)| { 16 | commands.remove(*entity); 17 | }); 18 | } 19 | -------------------------------------------------------------------------------- /source/07_TurnBasedGames_01_wandering/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[read_component(Render)] 6 | pub fn entity_render(ecs: &SubWorld, #[resource] camera: &Camera) { 7 | let mut draw_batch = DrawBatch::new(); 8 | draw_batch.target(1); 9 | let offset = Point::new(camera.left_x, camera.top_y); 10 | 11 | <(&Point, &Render)>::query() 12 | .iter(ecs) 13 | .for_each(|(pos, render)| { 14 | draw_batch.set(*pos - offset, render.color, render.glyph); 15 | }); 16 | draw_batch.submit(5000).expect("Batch error"); 17 | } 18 | -------------------------------------------------------------------------------- /source/07_TurnBasedGames_01_wandering/src/systems/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | mod collisions; 4 | mod entity_render; 5 | mod map_render; 6 | mod player_input; 7 | mod random_move; 8 | 9 | pub fn build_scheduler() -> Schedule { 10 | Schedule::builder() 11 | .add_system(player_input::player_input_system()) 12 | .add_system(collisions::collisions_system()) 13 | .flush() 14 | .add_system(map_render::map_render_system()) 15 | .add_system(entity_render::entity_render_system()) 16 | .add_system(random_move::random_move_system()) 17 | .build() 18 | } 19 | -------------------------------------------------------------------------------- /source/07_TurnBasedGames_01_wandering/src/systems/random_move.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[write_component(Point)] 5 | #[read_component(MovingRandomly)] 6 | pub fn random_move(ecs: &mut SubWorld, #[resource] map: &Map) { 7 | let mut movers = <(&mut Point, &MovingRandomly)>::query(); 8 | movers.iter_mut(ecs).for_each(|(pos, _)| { 9 | let mut rng = RandomNumberGenerator::new(); 10 | let destination = match rng.range(0, 4) { 11 | 0 => Point::new(-1, 0), 12 | 1 => Point::new(1, 0), 13 | 2 => Point::new(0, -1), 14 | _ => Point::new(0, 1), 15 | } + *pos; 16 | 17 | if map.can_enter_tile(destination) { 18 | *pos = destination; 19 | } 20 | }); 21 | } 22 | -------------------------------------------------------------------------------- /source/07_TurnBasedGames_02_turnbased/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "turnbased" 3 | version = "0.1.0" 4 | authors = ["Herbert Wolverson "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | bracket-lib = "~0.8.1" 11 | legion = "=0.3.1" 12 | -------------------------------------------------------------------------------- /source/07_TurnBasedGames_02_turnbased/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/07_TurnBasedGames_02_turnbased/resources/dungeonfont.png -------------------------------------------------------------------------------- /source/07_TurnBasedGames_02_turnbased/src/components.rs: -------------------------------------------------------------------------------- 1 | pub use crate::prelude::*; 2 | 3 | #[derive(Clone, Copy, Debug, PartialEq)] 4 | pub struct Render { 5 | pub color: ColorPair, 6 | pub glyph: FontCharType, 7 | } 8 | 9 | #[derive(Clone, Copy, Debug, PartialEq)] 10 | pub struct Player; 11 | 12 | #[derive(Clone, Copy, Debug, PartialEq)] 13 | pub struct Enemy; 14 | 15 | #[derive(Clone, Copy, Debug, PartialEq)] 16 | pub struct MovingRandomly; 17 | -------------------------------------------------------------------------------- /source/07_TurnBasedGames_02_turnbased/src/spawner.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn spawn_player(ecs: &mut World, pos: Point) { 4 | ecs.push(( 5 | Player, 6 | pos, 7 | Render { 8 | color: ColorPair::new(WHITE, BLACK), 9 | glyph: to_cp437('@'), 10 | }, 11 | )); 12 | } 13 | 14 | pub fn spawn_monster(ecs: &mut World, rng: &mut RandomNumberGenerator, pos: Point) { 15 | ecs.push(( 16 | Enemy, 17 | pos, 18 | Render { 19 | color: ColorPair::new(WHITE, BLACK), 20 | glyph: match rng.range(0, 4) { 21 | 0 => to_cp437('E'), 22 | 1 => to_cp437('O'), 23 | 2 => to_cp437('o'), 24 | _ => to_cp437('g'), 25 | }, 26 | }, 27 | MovingRandomly {}, 28 | )); 29 | } 30 | -------------------------------------------------------------------------------- /source/07_TurnBasedGames_02_turnbased/src/systems/collisions.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[read_component(Player)] 6 | #[read_component(Enemy)] 7 | pub fn collisions(ecs: &mut SubWorld, commands: &mut CommandBuffer) { 8 | let mut player_pos = Point::zero(); 9 | let mut players = <&Point>::query().filter(component::()); 10 | players.iter(ecs).for_each(|pos| player_pos = *pos); 11 | let mut enemies = <(Entity, &Point)>::query().filter(component::()); 12 | enemies 13 | .iter(ecs) 14 | .filter(|(_, pos)| **pos == player_pos) 15 | .for_each(|(entity, _)| { 16 | commands.remove(*entity); 17 | }); 18 | } 19 | -------------------------------------------------------------------------------- /source/07_TurnBasedGames_02_turnbased/src/systems/end_turn.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | pub fn end_turn(#[resource] turn_state: &mut TurnState) { 5 | let new_state = match turn_state { 6 | TurnState::AwaitingInput => return, 7 | TurnState::PlayerTurn => TurnState::MonsterTurn, 8 | TurnState::MonsterTurn => TurnState::AwaitingInput, 9 | }; 10 | 11 | *turn_state = new_state; 12 | } 13 | -------------------------------------------------------------------------------- /source/07_TurnBasedGames_02_turnbased/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[read_component(Render)] 6 | pub fn entity_render(ecs: &SubWorld, #[resource] camera: &Camera) { 7 | let mut draw_batch = DrawBatch::new(); 8 | draw_batch.target(1); 9 | let offset = Point::new(camera.left_x, camera.top_y); 10 | 11 | <(&Point, &Render)>::query() 12 | .iter(ecs) 13 | .for_each(|(pos, render)| { 14 | draw_batch.set(*pos - offset, render.color, render.glyph); 15 | }); 16 | draw_batch.submit(5000).expect("Batch error"); 17 | } 18 | -------------------------------------------------------------------------------- /source/07_TurnBasedGames_02_turnbased/src/systems/random_move.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[write_component(Point)] 5 | #[read_component(MovingRandomly)] 6 | pub fn random_move(ecs: &mut SubWorld, #[resource] map: &Map) { 7 | let mut movers = <(&mut Point, &MovingRandomly)>::query(); 8 | movers.iter_mut(ecs).for_each(|(pos, _)| { 9 | let mut rng = RandomNumberGenerator::new(); 10 | let destination = match rng.range(0, 4) { 11 | 0 => Point::new(-1, 0), 12 | 1 => Point::new(1, 0), 13 | 2 => Point::new(0, -1), 14 | _ => Point::new(0, 1), 15 | } + *pos; 16 | 17 | if map.can_enter_tile(destination) { 18 | *pos = destination; 19 | } 20 | }); 21 | } 22 | -------------------------------------------------------------------------------- /source/07_TurnBasedGames_02_turnbased/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Copy, Clone, Debug, PartialEq)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | } 7 | -------------------------------------------------------------------------------- /source/07_TurnBasedGames_03_intent/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "intent" 3 | version = "0.1.0" 4 | authors = ["Herbert Wolverson "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | bracket-lib = "~0.8.1" 11 | legion = "=0.3.1" 12 | -------------------------------------------------------------------------------- /source/07_TurnBasedGames_03_intent/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/07_TurnBasedGames_03_intent/resources/dungeonfont.png -------------------------------------------------------------------------------- /source/07_TurnBasedGames_03_intent/src/components.rs: -------------------------------------------------------------------------------- 1 | pub use crate::prelude::*; 2 | 3 | #[derive(Clone, Copy, Debug, PartialEq)] 4 | pub struct Render { 5 | pub color: ColorPair, 6 | pub glyph: FontCharType, 7 | } 8 | 9 | #[derive(Clone, Copy, Debug, PartialEq)] 10 | pub struct Player; 11 | 12 | #[derive(Clone, Copy, Debug, PartialEq)] 13 | pub struct Enemy; 14 | 15 | #[derive(Clone, Copy, Debug, PartialEq)] 16 | pub struct MovingRandomly; 17 | 18 | #[derive(Clone, Copy, Debug, PartialEq)] 19 | pub struct WantsToMove { 20 | pub entity: Entity, 21 | pub destination: Point, 22 | } 23 | -------------------------------------------------------------------------------- /source/07_TurnBasedGames_03_intent/src/spawner.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn spawn_player(ecs: &mut World, pos: Point) { 4 | ecs.push(( 5 | Player, 6 | pos, 7 | Render { 8 | color: ColorPair::new(WHITE, BLACK), 9 | glyph: to_cp437('@'), 10 | }, 11 | )); 12 | } 13 | 14 | pub fn spawn_monster(ecs: &mut World, rng: &mut RandomNumberGenerator, pos: Point) { 15 | ecs.push(( 16 | Enemy, 17 | pos, 18 | Render { 19 | color: ColorPair::new(WHITE, BLACK), 20 | glyph: match rng.range(0, 4) { 21 | 0 => to_cp437('E'), 22 | 1 => to_cp437('O'), 23 | 2 => to_cp437('o'), 24 | _ => to_cp437('g'), 25 | }, 26 | }, 27 | MovingRandomly {}, 28 | )); 29 | } 30 | -------------------------------------------------------------------------------- /source/07_TurnBasedGames_03_intent/src/systems/collisions.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[read_component(Player)] 6 | #[read_component(Enemy)] 7 | pub fn collisions(ecs: &mut SubWorld, commands: &mut CommandBuffer) { 8 | let mut player_pos = Point::zero(); 9 | let mut players = <&Point>::query().filter(component::()); 10 | players.iter(ecs).for_each(|pos| player_pos = *pos); 11 | let mut enemies = <(Entity, &Point)>::query().filter(component::()); 12 | enemies 13 | .iter(ecs) 14 | .filter(|(_, pos)| **pos == player_pos) 15 | .for_each(|(entity, _)| { 16 | commands.remove(*entity); 17 | }); 18 | } 19 | -------------------------------------------------------------------------------- /source/07_TurnBasedGames_03_intent/src/systems/end_turn.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | pub fn end_turn(#[resource] turn_state: &mut TurnState) { 5 | let new_state = match turn_state { 6 | TurnState::AwaitingInput => return, 7 | TurnState::PlayerTurn => TurnState::MonsterTurn, 8 | TurnState::MonsterTurn => TurnState::AwaitingInput, 9 | }; 10 | 11 | *turn_state = new_state; 12 | } 13 | -------------------------------------------------------------------------------- /source/07_TurnBasedGames_03_intent/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[read_component(Render)] 6 | pub fn entity_render(ecs: &SubWorld, #[resource] camera: &Camera) { 7 | let mut draw_batch = DrawBatch::new(); 8 | draw_batch.target(1); 9 | let offset = Point::new(camera.left_x, camera.top_y); 10 | 11 | <(&Point, &Render)>::query() 12 | .iter(ecs) 13 | .for_each(|(pos, render)| { 14 | draw_batch.set(*pos - offset, render.color, render.glyph); 15 | }); 16 | draw_batch.submit(5000).expect("Batch error"); 17 | } 18 | -------------------------------------------------------------------------------- /source/07_TurnBasedGames_03_intent/src/systems/movement.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system(for_each)] 4 | #[read_component(Player)] 5 | pub fn movement( 6 | entity: &Entity, 7 | want_move: &WantsToMove, 8 | #[resource] map: &Map, 9 | #[resource] camera: &mut Camera, 10 | ecs: &mut SubWorld, 11 | commands: &mut CommandBuffer, 12 | ) { 13 | if map.can_enter_tile(want_move.destination) { 14 | commands.add_component(want_move.entity, want_move.destination); 15 | 16 | if ecs 17 | .entry_ref(want_move.entity) 18 | .unwrap() 19 | .get_component::() 20 | .is_ok() 21 | { 22 | camera.on_player_move(want_move.destination); 23 | } 24 | } 25 | commands.remove(*entity); 26 | } 27 | -------------------------------------------------------------------------------- /source/07_TurnBasedGames_03_intent/src/systems/random_move.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[read_component(MovingRandomly)] 6 | pub fn random_move(ecs: &SubWorld, commands: &mut CommandBuffer) { 7 | let mut movers = <(Entity, &Point, &MovingRandomly)>::query(); 8 | movers.iter(ecs).for_each(|(entity, pos, _)| { 9 | let mut rng = RandomNumberGenerator::new(); 10 | let destination = match rng.range(0, 4) { 11 | 0 => Point::new(-1, 0), 12 | 1 => Point::new(1, 0), 13 | 2 => Point::new(0, -1), 14 | _ => Point::new(0, 1), 15 | } + *pos; 16 | 17 | commands.push(( 18 | (), 19 | WantsToMove { 20 | entity: *entity, 21 | destination, 22 | }, 23 | )); 24 | }); 25 | } 26 | -------------------------------------------------------------------------------- /source/07_TurnBasedGames_03_intent/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Copy, Clone, Debug, PartialEq)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | } 7 | -------------------------------------------------------------------------------- /source/08_HealthSimpleMelee_01_health/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "health" 3 | version = "0.1.0" 4 | authors = ["Herbert Wolverson "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | bracket-lib = "~0.8.1" 11 | legion = "=0.3.1" 12 | -------------------------------------------------------------------------------- /source/08_HealthSimpleMelee_01_health/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/08_HealthSimpleMelee_01_health/resources/dungeonfont.png -------------------------------------------------------------------------------- /source/08_HealthSimpleMelee_01_health/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/08_HealthSimpleMelee_01_health/resources/terminal8x8.png -------------------------------------------------------------------------------- /source/08_HealthSimpleMelee_01_health/src/components.rs: -------------------------------------------------------------------------------- 1 | pub use crate::prelude::*; 2 | 3 | #[derive(Clone, Copy, Debug, PartialEq)] 4 | pub struct Render { 5 | pub color: ColorPair, 6 | pub glyph: FontCharType, 7 | } 8 | 9 | #[derive(Clone, Copy, Debug, PartialEq)] 10 | pub struct Player; 11 | 12 | #[derive(Clone, Copy, Debug, PartialEq)] 13 | pub struct Enemy; 14 | 15 | #[derive(Clone, Copy, Debug, PartialEq)] 16 | pub struct MovingRandomly; 17 | 18 | #[derive(Clone, Copy, Debug, PartialEq)] 19 | pub struct WantsToMove { 20 | pub entity: Entity, 21 | pub destination: Point, 22 | } 23 | 24 | #[derive(Clone, Copy, Debug, PartialEq)] 25 | pub struct Health { 26 | pub current: i32, 27 | pub max: i32, 28 | } 29 | 30 | #[derive(Clone, PartialEq)] 31 | pub struct Name(pub String); 32 | -------------------------------------------------------------------------------- /source/08_HealthSimpleMelee_01_health/src/systems/collisions.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[read_component(Player)] 6 | #[read_component(Enemy)] 7 | pub fn collisions(ecs: &mut SubWorld, commands: &mut CommandBuffer) { 8 | let mut player_pos = Point::zero(); 9 | let mut players = <&Point>::query().filter(component::()); 10 | players.iter(ecs).for_each(|pos| player_pos = *pos); 11 | let mut enemies = <(Entity, &Point)>::query().filter(component::()); 12 | enemies 13 | .iter(ecs) 14 | .filter(|(_, pos)| **pos == player_pos) 15 | .for_each(|(entity, _)| { 16 | commands.remove(*entity); 17 | }); 18 | } 19 | -------------------------------------------------------------------------------- /source/08_HealthSimpleMelee_01_health/src/systems/end_turn.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | pub fn end_turn(#[resource] turn_state: &mut TurnState) { 5 | let new_state = match turn_state { 6 | TurnState::AwaitingInput => return, 7 | TurnState::PlayerTurn => TurnState::MonsterTurn, 8 | TurnState::MonsterTurn => TurnState::AwaitingInput, 9 | }; 10 | 11 | *turn_state = new_state; 12 | } 13 | -------------------------------------------------------------------------------- /source/08_HealthSimpleMelee_01_health/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[read_component(Render)] 6 | pub fn entity_render(ecs: &SubWorld, #[resource] camera: &Camera) { 7 | let mut draw_batch = DrawBatch::new(); 8 | draw_batch.target(1); 9 | let offset = Point::new(camera.left_x, camera.top_y); 10 | 11 | <(&Point, &Render)>::query() 12 | .iter(ecs) 13 | .for_each(|(pos, render)| { 14 | draw_batch.set(*pos - offset, render.color, render.glyph); 15 | }); 16 | draw_batch.submit(5000).expect("Batch error"); 17 | } 18 | -------------------------------------------------------------------------------- /source/08_HealthSimpleMelee_01_health/src/systems/movement.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system(for_each)] 4 | #[read_component(Player)] 5 | pub fn movement( 6 | entity: &Entity, 7 | want_move: &WantsToMove, 8 | #[resource] map: &Map, 9 | #[resource] camera: &mut Camera, 10 | ecs: &mut SubWorld, 11 | commands: &mut CommandBuffer, 12 | ) { 13 | if map.can_enter_tile(want_move.destination) { 14 | commands.add_component(want_move.entity, want_move.destination); 15 | 16 | if ecs 17 | .entry_ref(want_move.entity) 18 | .unwrap() 19 | .get_component::() 20 | .is_ok() 21 | { 22 | camera.on_player_move(want_move.destination); 23 | } 24 | } 25 | commands.remove(*entity); 26 | } 27 | -------------------------------------------------------------------------------- /source/08_HealthSimpleMelee_01_health/src/systems/random_move.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[read_component(MovingRandomly)] 6 | pub fn random_move(ecs: &SubWorld, commands: &mut CommandBuffer) { 7 | let mut movers = <(Entity, &Point, &MovingRandomly)>::query(); 8 | movers.iter(ecs).for_each(|(entity, pos, _)| { 9 | let mut rng = RandomNumberGenerator::new(); 10 | let destination = match rng.range(0, 4) { 11 | 0 => Point::new(-1, 0), 12 | 1 => Point::new(1, 0), 13 | 2 => Point::new(0, -1), 14 | _ => Point::new(0, 1), 15 | } + *pos; 16 | 17 | commands.push(( 18 | (), 19 | WantsToMove { 20 | entity: *entity, 21 | destination, 22 | }, 23 | )); 24 | }); 25 | } 26 | -------------------------------------------------------------------------------- /source/08_HealthSimpleMelee_01_health/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Copy, Clone, Debug, PartialEq)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | } 7 | -------------------------------------------------------------------------------- /source/08_HealthSimpleMelee_02_combat/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "combat" 3 | version = "0.1.0" 4 | authors = ["Herbert Wolverson "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | bracket-lib = "~0.8.1" 11 | legion = "=0.3.1" 12 | -------------------------------------------------------------------------------- /source/08_HealthSimpleMelee_02_combat/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/08_HealthSimpleMelee_02_combat/resources/dungeonfont.png -------------------------------------------------------------------------------- /source/08_HealthSimpleMelee_02_combat/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/08_HealthSimpleMelee_02_combat/resources/terminal8x8.png -------------------------------------------------------------------------------- /source/08_HealthSimpleMelee_02_combat/src/systems/end_turn.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | pub fn end_turn(#[resource] turn_state: &mut TurnState) { 5 | let new_state = match turn_state { 6 | TurnState::AwaitingInput => return, 7 | TurnState::PlayerTurn => TurnState::MonsterTurn, 8 | TurnState::MonsterTurn => TurnState::AwaitingInput, 9 | }; 10 | 11 | *turn_state = new_state; 12 | } 13 | -------------------------------------------------------------------------------- /source/08_HealthSimpleMelee_02_combat/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[read_component(Render)] 6 | pub fn entity_render(ecs: &SubWorld, #[resource] camera: &Camera) { 7 | let mut draw_batch = DrawBatch::new(); 8 | draw_batch.target(1); 9 | let offset = Point::new(camera.left_x, camera.top_y); 10 | 11 | <(&Point, &Render)>::query() 12 | .iter(ecs) 13 | .for_each(|(pos, render)| { 14 | draw_batch.set(*pos - offset, render.color, render.glyph); 15 | }); 16 | draw_batch.submit(5000).expect("Batch error"); 17 | } 18 | -------------------------------------------------------------------------------- /source/08_HealthSimpleMelee_02_combat/src/systems/movement.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system(for_each)] 4 | #[read_component(Player)] 5 | pub fn movement( 6 | entity: &Entity, 7 | want_move: &WantsToMove, 8 | #[resource] map: &Map, 9 | #[resource] camera: &mut Camera, 10 | ecs: &mut SubWorld, 11 | commands: &mut CommandBuffer, 12 | ) { 13 | if map.can_enter_tile(want_move.destination) { 14 | commands.add_component(want_move.entity, want_move.destination); 15 | 16 | if ecs 17 | .entry_ref(want_move.entity) 18 | .unwrap() 19 | .get_component::() 20 | .is_ok() 21 | { 22 | camera.on_player_move(want_move.destination); 23 | } 24 | } 25 | commands.remove(*entity); 26 | } 27 | -------------------------------------------------------------------------------- /source/08_HealthSimpleMelee_02_combat/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Copy, Clone, Debug, PartialEq)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | } 7 | -------------------------------------------------------------------------------- /source/08_HealthSimpleMelee_03_healing/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "healing" 3 | version = "0.1.0" 4 | authors = ["Herbert Wolverson "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | bracket-lib = "~0.8.1" 11 | legion = "=0.3.1" 12 | -------------------------------------------------------------------------------- /source/08_HealthSimpleMelee_03_healing/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/08_HealthSimpleMelee_03_healing/resources/dungeonfont.png -------------------------------------------------------------------------------- /source/08_HealthSimpleMelee_03_healing/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/08_HealthSimpleMelee_03_healing/resources/terminal8x8.png -------------------------------------------------------------------------------- /source/08_HealthSimpleMelee_03_healing/src/systems/end_turn.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | pub fn end_turn(#[resource] turn_state: &mut TurnState) { 5 | let new_state = match turn_state { 6 | TurnState::AwaitingInput => return, 7 | TurnState::PlayerTurn => TurnState::MonsterTurn, 8 | TurnState::MonsterTurn => TurnState::AwaitingInput, 9 | }; 10 | 11 | *turn_state = new_state; 12 | } 13 | -------------------------------------------------------------------------------- /source/08_HealthSimpleMelee_03_healing/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[read_component(Render)] 6 | pub fn entity_render(ecs: &SubWorld, #[resource] camera: &Camera) { 7 | let mut draw_batch = DrawBatch::new(); 8 | draw_batch.target(1); 9 | let offset = Point::new(camera.left_x, camera.top_y); 10 | 11 | <(&Point, &Render)>::query() 12 | .iter(ecs) 13 | .for_each(|(pos, render)| { 14 | draw_batch.set(*pos - offset, render.color, render.glyph); 15 | }); 16 | draw_batch.submit(5000).expect("Batch error"); 17 | } 18 | -------------------------------------------------------------------------------- /source/08_HealthSimpleMelee_03_healing/src/systems/movement.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system(for_each)] 4 | #[read_component(Player)] 5 | pub fn movement( 6 | entity: &Entity, 7 | want_move: &WantsToMove, 8 | #[resource] map: &Map, 9 | #[resource] camera: &mut Camera, 10 | ecs: &mut SubWorld, 11 | commands: &mut CommandBuffer, 12 | ) { 13 | if map.can_enter_tile(want_move.destination) { 14 | commands.add_component(want_move.entity, want_move.destination); 15 | 16 | if ecs 17 | .entry_ref(want_move.entity) 18 | .unwrap() 19 | .get_component::() 20 | .is_ok() 21 | { 22 | camera.on_player_move(want_move.destination); 23 | } 24 | } 25 | commands.remove(*entity); 26 | } 27 | -------------------------------------------------------------------------------- /source/08_HealthSimpleMelee_03_healing/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Copy, Clone, Debug, PartialEq)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | } 7 | -------------------------------------------------------------------------------- /source/09_WinningAndLosing_01_gauntlet/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "gauntlet" 3 | version = "0.1.0" 4 | authors = ["Herbert Wolverson "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | bracket-lib = "~0.8.1" 11 | legion = "=0.3.1" 12 | -------------------------------------------------------------------------------- /source/09_WinningAndLosing_01_gauntlet/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/09_WinningAndLosing_01_gauntlet/resources/dungeonfont.png -------------------------------------------------------------------------------- /source/09_WinningAndLosing_01_gauntlet/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/09_WinningAndLosing_01_gauntlet/resources/terminal8x8.png -------------------------------------------------------------------------------- /source/09_WinningAndLosing_01_gauntlet/src/systems/end_turn.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | pub fn end_turn(#[resource] turn_state: &mut TurnState) { 5 | let new_state = match turn_state { 6 | TurnState::AwaitingInput => return, 7 | TurnState::PlayerTurn => TurnState::MonsterTurn, 8 | TurnState::MonsterTurn => TurnState::AwaitingInput, 9 | }; 10 | 11 | *turn_state = new_state; 12 | } 13 | -------------------------------------------------------------------------------- /source/09_WinningAndLosing_01_gauntlet/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[read_component(Render)] 6 | pub fn entity_render(ecs: &SubWorld, #[resource] camera: &Camera) { 7 | let mut draw_batch = DrawBatch::new(); 8 | draw_batch.target(1); 9 | let offset = Point::new(camera.left_x, camera.top_y); 10 | 11 | <(&Point, &Render)>::query() 12 | .iter(ecs) 13 | .for_each(|(pos, render)| { 14 | draw_batch.set(*pos - offset, render.color, render.glyph); 15 | }); 16 | draw_batch.submit(5000).expect("Batch error"); 17 | } 18 | -------------------------------------------------------------------------------- /source/09_WinningAndLosing_01_gauntlet/src/systems/movement.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system(for_each)] 4 | #[read_component(Player)] 5 | pub fn movement( 6 | entity: &Entity, 7 | want_move: &WantsToMove, 8 | #[resource] map: &Map, 9 | #[resource] camera: &mut Camera, 10 | ecs: &mut SubWorld, 11 | commands: &mut CommandBuffer, 12 | ) { 13 | if map.can_enter_tile(want_move.destination) { 14 | commands.add_component(want_move.entity, want_move.destination); 15 | 16 | if ecs 17 | .entry_ref(want_move.entity) 18 | .unwrap() 19 | .get_component::() 20 | .is_ok() 21 | { 22 | camera.on_player_move(want_move.destination); 23 | } 24 | } 25 | commands.remove(*entity); 26 | } 27 | -------------------------------------------------------------------------------- /source/09_WinningAndLosing_01_gauntlet/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Copy, Clone, Debug, PartialEq)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | } 7 | -------------------------------------------------------------------------------- /source/09_WinningAndLosing_02_losing/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "losing" 3 | version = "0.1.0" 4 | authors = ["Herbert Wolverson "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | bracket-lib = "~0.8.1" 11 | legion = "=0.3.1" 12 | -------------------------------------------------------------------------------- /source/09_WinningAndLosing_02_losing/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/09_WinningAndLosing_02_losing/resources/dungeonfont.png -------------------------------------------------------------------------------- /source/09_WinningAndLosing_02_losing/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/09_WinningAndLosing_02_losing/resources/terminal8x8.png -------------------------------------------------------------------------------- /source/09_WinningAndLosing_02_losing/src/systems/end_turn.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Health)] 5 | #[read_component(Player)] 6 | pub fn end_turn(ecs: &SubWorld, #[resource] turn_state: &mut TurnState) { 7 | let mut player_hp = <&Health>::query().filter(component::()); 8 | let current_state = *turn_state; 9 | let mut new_state = match current_state { 10 | TurnState::AwaitingInput => return, 11 | TurnState::PlayerTurn => TurnState::MonsterTurn, 12 | TurnState::MonsterTurn => TurnState::AwaitingInput, 13 | _ => current_state, 14 | }; 15 | 16 | player_hp.iter(ecs).for_each(|hp| { 17 | if hp.current < 1 { 18 | new_state = TurnState::GameOver; 19 | } 20 | }); 21 | 22 | *turn_state = new_state; 23 | } 24 | -------------------------------------------------------------------------------- /source/09_WinningAndLosing_02_losing/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[read_component(Render)] 6 | pub fn entity_render(ecs: &SubWorld, #[resource] camera: &Camera) { 7 | let mut draw_batch = DrawBatch::new(); 8 | draw_batch.target(1); 9 | let offset = Point::new(camera.left_x, camera.top_y); 10 | 11 | <(&Point, &Render)>::query() 12 | .iter(ecs) 13 | .for_each(|(pos, render)| { 14 | draw_batch.set(*pos - offset, render.color, render.glyph); 15 | }); 16 | draw_batch.submit(5000).expect("Batch error"); 17 | } 18 | -------------------------------------------------------------------------------- /source/09_WinningAndLosing_02_losing/src/systems/movement.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system(for_each)] 4 | #[read_component(Player)] 5 | pub fn movement( 6 | entity: &Entity, 7 | want_move: &WantsToMove, 8 | #[resource] map: &Map, 9 | #[resource] camera: &mut Camera, 10 | ecs: &mut SubWorld, 11 | commands: &mut CommandBuffer, 12 | ) { 13 | if map.can_enter_tile(want_move.destination) { 14 | commands.add_component(want_move.entity, want_move.destination); 15 | 16 | if ecs 17 | .entry_ref(want_move.entity) 18 | .unwrap() 19 | .get_component::() 20 | .is_ok() 21 | { 22 | camera.on_player_move(want_move.destination); 23 | } 24 | } 25 | commands.remove(*entity); 26 | } 27 | -------------------------------------------------------------------------------- /source/09_WinningAndLosing_02_losing/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Copy, Clone, Debug, PartialEq)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | GameOver, 7 | } 8 | -------------------------------------------------------------------------------- /source/09_WinningAndLosing_03_winning/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "winning" 3 | version = "0.1.0" 4 | authors = ["Herbert Wolverson "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | bracket-lib = "~0.8.1" 11 | legion = "=0.3.1" 12 | -------------------------------------------------------------------------------- /source/09_WinningAndLosing_03_winning/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/09_WinningAndLosing_03_winning/resources/dungeonfont.png -------------------------------------------------------------------------------- /source/09_WinningAndLosing_03_winning/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/09_WinningAndLosing_03_winning/resources/terminal8x8.png -------------------------------------------------------------------------------- /source/09_WinningAndLosing_03_winning/src/systems/entity_render.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[read_component(Render)] 6 | pub fn entity_render(ecs: &SubWorld, #[resource] camera: &Camera) { 7 | let mut draw_batch = DrawBatch::new(); 8 | draw_batch.target(1); 9 | let offset = Point::new(camera.left_x, camera.top_y); 10 | 11 | <(&Point, &Render)>::query() 12 | .iter(ecs) 13 | .for_each(|(pos, render)| { 14 | draw_batch.set(*pos - offset, render.color, render.glyph); 15 | }); 16 | draw_batch.submit(5000).expect("Batch error"); 17 | } 18 | -------------------------------------------------------------------------------- /source/09_WinningAndLosing_03_winning/src/systems/movement.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system(for_each)] 4 | #[read_component(Player)] 5 | pub fn movement( 6 | entity: &Entity, 7 | want_move: &WantsToMove, 8 | #[resource] map: &Map, 9 | #[resource] camera: &mut Camera, 10 | ecs: &mut SubWorld, 11 | commands: &mut CommandBuffer, 12 | ) { 13 | if map.can_enter_tile(want_move.destination) { 14 | commands.add_component(want_move.entity, want_move.destination); 15 | 16 | if ecs 17 | .entry_ref(want_move.entity) 18 | .unwrap() 19 | .get_component::() 20 | .is_ok() 21 | { 22 | camera.on_player_move(want_move.destination); 23 | } 24 | } 25 | commands.remove(*entity); 26 | } 27 | -------------------------------------------------------------------------------- /source/09_WinningAndLosing_03_winning/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Copy, Clone, Debug, PartialEq)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | GameOver, 7 | Victory, 8 | } 9 | -------------------------------------------------------------------------------- /source/10_WhatCanISee_01_fov/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fov" 3 | version = "0.1.0" 4 | authors = ["Herbert Wolverson "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | bracket-lib = "~0.8.1" 11 | legion = "=0.3.1" 12 | -------------------------------------------------------------------------------- /source/10_WhatCanISee_01_fov/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/10_WhatCanISee_01_fov/resources/dungeonfont.png -------------------------------------------------------------------------------- /source/10_WhatCanISee_01_fov/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/10_WhatCanISee_01_fov/resources/terminal8x8.png -------------------------------------------------------------------------------- /source/10_WhatCanISee_01_fov/src/systems/fov.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[write_component(FieldOfView)] 6 | pub fn fov(ecs: &mut SubWorld, #[resource] map: &Map) { 7 | let mut views = <(&Point, &mut FieldOfView)>::query(); 8 | views 9 | .iter_mut(ecs) 10 | .filter(|(_, fov)| fov.is_dirty) 11 | .for_each(|(pos, mut fov)| { 12 | fov.visible_tiles = field_of_view_set(*pos, fov.radius, map); 13 | fov.is_dirty = false; 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /source/10_WhatCanISee_01_fov/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Copy, Clone, Debug, PartialEq)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | GameOver, 7 | Victory, 8 | } 9 | -------------------------------------------------------------------------------- /source/10_WhatCanISee_02_eyesight/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eyesight" 3 | version = "0.1.0" 4 | authors = ["Herbert Wolverson "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | bracket-lib = "~0.8.1" 11 | legion = "=0.3.1" -------------------------------------------------------------------------------- /source/10_WhatCanISee_02_eyesight/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/10_WhatCanISee_02_eyesight/resources/dungeonfont.png -------------------------------------------------------------------------------- /source/10_WhatCanISee_02_eyesight/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/10_WhatCanISee_02_eyesight/resources/terminal8x8.png -------------------------------------------------------------------------------- /source/10_WhatCanISee_02_eyesight/src/systems/fov.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[write_component(FieldOfView)] 6 | pub fn fov(ecs: &mut SubWorld, #[resource] map: &Map) { 7 | let mut views = <(&Point, &mut FieldOfView)>::query(); 8 | views 9 | .iter_mut(ecs) 10 | .filter(|(_, fov)| fov.is_dirty) 11 | .for_each(|(pos, mut fov)| { 12 | fov.visible_tiles = field_of_view_set(*pos, fov.radius, map); 13 | fov.is_dirty = false; 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /source/10_WhatCanISee_02_eyesight/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Copy, Clone, Debug, PartialEq)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | GameOver, 7 | Victory, 8 | } 9 | -------------------------------------------------------------------------------- /source/10_WhatCanISee_03_memory/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "memory" 3 | version = "0.1.0" 4 | authors = ["Herbert Wolverson "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | bracket-lib = "~0.8.1" 11 | legion = "=0.3.1" 12 | -------------------------------------------------------------------------------- /source/10_WhatCanISee_03_memory/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/10_WhatCanISee_03_memory/resources/dungeonfont.png -------------------------------------------------------------------------------- /source/10_WhatCanISee_03_memory/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/10_WhatCanISee_03_memory/resources/terminal8x8.png -------------------------------------------------------------------------------- /source/10_WhatCanISee_03_memory/src/systems/fov.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[write_component(FieldOfView)] 6 | pub fn fov(ecs: &mut SubWorld, #[resource] map: &Map) { 7 | let mut views = <(&Point, &mut FieldOfView)>::query(); 8 | views 9 | .iter_mut(ecs) 10 | .filter(|(_, fov)| fov.is_dirty) 11 | .for_each(|(pos, mut fov)| { 12 | fov.visible_tiles = field_of_view_set(*pos, fov.radius, map); 13 | fov.is_dirty = false; 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /source/10_WhatCanISee_03_memory/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Copy, Clone, Debug, PartialEq)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | GameOver, 7 | Victory, 8 | } 9 | -------------------------------------------------------------------------------- /source/11_MoreInterestingDungeons_01_traits/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "traits" 3 | version = "0.1.0" 4 | authors = ["Herbert Wolverson "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | bracket-lib = "~0.8.1" 11 | legion = "=0.3.1" 12 | -------------------------------------------------------------------------------- /source/11_MoreInterestingDungeons_01_traits/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/11_MoreInterestingDungeons_01_traits/resources/dungeonfont.png -------------------------------------------------------------------------------- /source/11_MoreInterestingDungeons_01_traits/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/11_MoreInterestingDungeons_01_traits/resources/terminal8x8.png -------------------------------------------------------------------------------- /source/11_MoreInterestingDungeons_01_traits/src/systems/fov.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[write_component(FieldOfView)] 6 | pub fn fov(ecs: &mut SubWorld, #[resource] map: &Map) { 7 | let mut views = <(&Point, &mut FieldOfView)>::query(); 8 | views 9 | .iter_mut(ecs) 10 | .filter(|(_, fov)| fov.is_dirty) 11 | .for_each(|(pos, mut fov)| { 12 | fov.visible_tiles = field_of_view_set(*pos, fov.radius, map); 13 | fov.is_dirty = false; 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /source/11_MoreInterestingDungeons_01_traits/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Copy, Clone, Debug, PartialEq)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | GameOver, 7 | Victory, 8 | } 9 | -------------------------------------------------------------------------------- /source/11_MoreInterestingDungeons_02_traits_rooms/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "traits_rooms" 3 | version = "0.1.0" 4 | authors = ["Herbert Wolverson "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | bracket-lib = "~0.8.1" 11 | legion = "=0.3.1" 12 | -------------------------------------------------------------------------------- /source/11_MoreInterestingDungeons_02_traits_rooms/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/11_MoreInterestingDungeons_02_traits_rooms/resources/dungeonfont.png -------------------------------------------------------------------------------- /source/11_MoreInterestingDungeons_02_traits_rooms/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/11_MoreInterestingDungeons_02_traits_rooms/resources/terminal8x8.png -------------------------------------------------------------------------------- /source/11_MoreInterestingDungeons_02_traits_rooms/src/systems/fov.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[write_component(FieldOfView)] 6 | pub fn fov(ecs: &mut SubWorld, #[resource] map: &Map) { 7 | let mut views = <(&Point, &mut FieldOfView)>::query(); 8 | views 9 | .iter_mut(ecs) 10 | .filter(|(_, fov)| fov.is_dirty) 11 | .for_each(|(pos, mut fov)| { 12 | fov.visible_tiles = field_of_view_set(*pos, fov.radius, map); 13 | fov.is_dirty = false; 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /source/11_MoreInterestingDungeons_02_traits_rooms/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Copy, Clone, Debug, PartialEq)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | GameOver, 7 | Victory, 8 | } 9 | -------------------------------------------------------------------------------- /source/11_MoreInterestingDungeons_03_cellular/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cellular" 3 | version = "0.1.0" 4 | authors = ["Herbert Wolverson "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | bracket-lib = "~0.8.1" 11 | legion = "=0.3.1" 12 | -------------------------------------------------------------------------------- /source/11_MoreInterestingDungeons_03_cellular/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/11_MoreInterestingDungeons_03_cellular/resources/dungeonfont.png -------------------------------------------------------------------------------- /source/11_MoreInterestingDungeons_03_cellular/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/11_MoreInterestingDungeons_03_cellular/resources/terminal8x8.png -------------------------------------------------------------------------------- /source/11_MoreInterestingDungeons_03_cellular/src/systems/fov.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[write_component(FieldOfView)] 6 | pub fn fov(ecs: &mut SubWorld, #[resource] map: &Map) { 7 | let mut views = <(&Point, &mut FieldOfView)>::query(); 8 | views 9 | .iter_mut(ecs) 10 | .filter(|(_, fov)| fov.is_dirty) 11 | .for_each(|(pos, mut fov)| { 12 | fov.visible_tiles = field_of_view_set(*pos, fov.radius, map); 13 | fov.is_dirty = false; 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /source/11_MoreInterestingDungeons_03_cellular/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Copy, Clone, Debug, PartialEq)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | GameOver, 7 | Victory, 8 | } 9 | -------------------------------------------------------------------------------- /source/11_MoreInterestingDungeons_04_output_harness/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "output_harness" 3 | version = "0.1.0" 4 | authors = ["Herbert Wolverson "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | bracket-lib = "~0.8.1" 11 | colored = "2" -------------------------------------------------------------------------------- /source/11_MoreInterestingDungeons_04_output_harness/src/main.rs: -------------------------------------------------------------------------------- 1 | mod map; 2 | mod map_builder; 3 | 4 | mod prelude { 5 | pub use crate::map::*; 6 | pub use crate::map_builder::*; 7 | pub use bracket_lib::prelude::*; 8 | pub const SCREEN_WIDTH: i32 = 80; 9 | pub const SCREEN_HEIGHT: i32 = 50; 10 | pub const NUM_TILES: usize = (SCREEN_WIDTH * SCREEN_HEIGHT) as usize; 11 | } 12 | 13 | fn main() { 14 | use crate::prelude::*; 15 | let mut rng = RandomNumberGenerator::new(); 16 | let mb = MapBuilder::build(&mut rng, Algorithm::Drunkard); 17 | display( 18 | "Final Map", 19 | &mb.map, 20 | &mb.player_start, 21 | &mb.amulet_start, 22 | &mb.monster_spawns, 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /source/11_MoreInterestingDungeons_05_drunkard/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "drunkard" 3 | version = "0.1.0" 4 | authors = ["Herbert Wolverson "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | bracket-lib = "~0.8.1" 11 | legion = "=0.3.1" 12 | -------------------------------------------------------------------------------- /source/11_MoreInterestingDungeons_05_drunkard/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/11_MoreInterestingDungeons_05_drunkard/resources/dungeonfont.png -------------------------------------------------------------------------------- /source/11_MoreInterestingDungeons_05_drunkard/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/11_MoreInterestingDungeons_05_drunkard/resources/terminal8x8.png -------------------------------------------------------------------------------- /source/11_MoreInterestingDungeons_05_drunkard/src/systems/fov.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[write_component(FieldOfView)] 6 | pub fn fov(ecs: &mut SubWorld, #[resource] map: &Map) { 7 | let mut views = <(&Point, &mut FieldOfView)>::query(); 8 | views 9 | .iter_mut(ecs) 10 | .filter(|(_, fov)| fov.is_dirty) 11 | .for_each(|(pos, mut fov)| { 12 | fov.visible_tiles = field_of_view_set(*pos, fov.radius, map); 13 | fov.is_dirty = false; 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /source/11_MoreInterestingDungeons_05_drunkard/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Copy, Clone, Debug, PartialEq)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | GameOver, 7 | Victory, 8 | } 9 | -------------------------------------------------------------------------------- /source/11_MoreInterestingDungeons_06_prefab/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "prefab" 3 | version = "0.1.0" 4 | authors = ["Herbert Wolverson "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | bracket-lib = "~0.8.1" 11 | legion = "=0.3.1" 12 | -------------------------------------------------------------------------------- /source/11_MoreInterestingDungeons_06_prefab/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/11_MoreInterestingDungeons_06_prefab/resources/dungeonfont.png -------------------------------------------------------------------------------- /source/11_MoreInterestingDungeons_06_prefab/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/11_MoreInterestingDungeons_06_prefab/resources/terminal8x8.png -------------------------------------------------------------------------------- /source/11_MoreInterestingDungeons_06_prefab/src/systems/fov.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[write_component(FieldOfView)] 6 | pub fn fov(ecs: &mut SubWorld, #[resource] map: &Map) { 7 | let mut views = <(&Point, &mut FieldOfView)>::query(); 8 | views 9 | .iter_mut(ecs) 10 | .filter(|(_, fov)| fov.is_dirty) 11 | .for_each(|(pos, mut fov)| { 12 | fov.visible_tiles = field_of_view_set(*pos, fov.radius, map); 13 | fov.is_dirty = false; 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /source/11_MoreInterestingDungeons_06_prefab/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Copy, Clone, Debug, PartialEq)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | GameOver, 7 | Victory, 8 | } 9 | -------------------------------------------------------------------------------- /source/12_MapTheming/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "themed" 3 | version = "0.1.0" 4 | authors = ["Herbert Wolverson "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | bracket-lib = "~0.8.1" 11 | legion = "=0.3.1" 12 | -------------------------------------------------------------------------------- /source/12_MapTheming/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/12_MapTheming/resources/dungeonfont.png -------------------------------------------------------------------------------- /source/12_MapTheming/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/12_MapTheming/resources/terminal8x8.png -------------------------------------------------------------------------------- /source/12_MapTheming/src/systems/fov.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[write_component(FieldOfView)] 6 | pub fn fov(ecs: &mut SubWorld, #[resource] map: &Map) { 7 | let mut views = <(&Point, &mut FieldOfView)>::query(); 8 | views 9 | .iter_mut(ecs) 10 | .filter(|(_, fov)| fov.is_dirty) 11 | .for_each(|(pos, mut fov)| { 12 | fov.visible_tiles = field_of_view_set(*pos, fov.radius, map); 13 | fov.is_dirty = false; 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /source/12_MapTheming/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Copy, Clone, Debug, PartialEq)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | GameOver, 7 | Victory, 8 | } 9 | -------------------------------------------------------------------------------- /source/13_InventoryAndPowerUps_01_potions_and_scrolls/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "potions_and_scrolls" 3 | version = "0.1.0" 4 | authors = ["Herbert Wolverson "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | bracket-lib = "~0.8.1" 11 | legion = "=0.3.1" 12 | -------------------------------------------------------------------------------- /source/13_InventoryAndPowerUps_01_potions_and_scrolls/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/13_InventoryAndPowerUps_01_potions_and_scrolls/resources/dungeonfont.png -------------------------------------------------------------------------------- /source/13_InventoryAndPowerUps_01_potions_and_scrolls/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/13_InventoryAndPowerUps_01_potions_and_scrolls/resources/terminal8x8.png -------------------------------------------------------------------------------- /source/13_InventoryAndPowerUps_01_potions_and_scrolls/src/systems/fov.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[write_component(FieldOfView)] 6 | pub fn fov(ecs: &mut SubWorld, #[resource] map: &Map) { 7 | let mut views = <(&Point, &mut FieldOfView)>::query(); 8 | views 9 | .iter_mut(ecs) 10 | .filter(|(_, fov)| fov.is_dirty) 11 | .for_each(|(pos, mut fov)| { 12 | fov.visible_tiles = field_of_view_set(*pos, fov.radius, map); 13 | fov.is_dirty = false; 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /source/13_InventoryAndPowerUps_01_potions_and_scrolls/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Copy, Clone, Debug, PartialEq)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | GameOver, 7 | Victory, 8 | } 9 | -------------------------------------------------------------------------------- /source/13_InventoryAndPowerUps_02_carrying_items/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "carrying_items" 3 | version = "0.1.0" 4 | authors = ["Herbert Wolverson "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | bracket-lib = "~0.8.1" 11 | legion = "=0.3.1" 12 | -------------------------------------------------------------------------------- /source/13_InventoryAndPowerUps_02_carrying_items/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/13_InventoryAndPowerUps_02_carrying_items/resources/dungeonfont.png -------------------------------------------------------------------------------- /source/13_InventoryAndPowerUps_02_carrying_items/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/13_InventoryAndPowerUps_02_carrying_items/resources/terminal8x8.png -------------------------------------------------------------------------------- /source/13_InventoryAndPowerUps_02_carrying_items/src/systems/fov.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[write_component(FieldOfView)] 6 | pub fn fov(ecs: &mut SubWorld, #[resource] map: &Map) { 7 | let mut views = <(&Point, &mut FieldOfView)>::query(); 8 | views 9 | .iter_mut(ecs) 10 | .filter(|(_, fov)| fov.is_dirty) 11 | .for_each(|(pos, mut fov)| { 12 | fov.visible_tiles = field_of_view_set(*pos, fov.radius, map); 13 | fov.is_dirty = false; 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /source/13_InventoryAndPowerUps_02_carrying_items/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Copy, Clone, Debug, PartialEq)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | GameOver, 7 | Victory, 8 | } 9 | -------------------------------------------------------------------------------- /source/14_DeeperDungeons/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "more_levels" 3 | version = "0.1.0" 4 | authors = ["Herbert Wolverson "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | bracket-lib = "~0.8.1" 11 | legion = "=0.3.1" 12 | -------------------------------------------------------------------------------- /source/14_DeeperDungeons/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/14_DeeperDungeons/resources/dungeonfont.png -------------------------------------------------------------------------------- /source/14_DeeperDungeons/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/14_DeeperDungeons/resources/terminal8x8.png -------------------------------------------------------------------------------- /source/14_DeeperDungeons/src/systems/fov.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[write_component(FieldOfView)] 6 | pub fn fov(ecs: &mut SubWorld, #[resource] map: &Map) { 7 | let mut views = <(&Point, &mut FieldOfView)>::query(); 8 | views 9 | .iter_mut(ecs) 10 | .filter(|(_, fov)| fov.is_dirty) 11 | .for_each(|(pos, mut fov)| { 12 | fov.visible_tiles = field_of_view_set(*pos, fov.radius, map); 13 | fov.is_dirty = false; 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /source/14_DeeperDungeons/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Copy, Clone, Debug, PartialEq)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | GameOver, 7 | Victory, 8 | NextLevel, 9 | } 10 | -------------------------------------------------------------------------------- /source/15_Loot_01_loot_tables/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "loot_tables" 3 | version = "0.1.0" 4 | authors = ["Herbert Wolverson "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | bracket-lib = "~0.8.1" 11 | legion = "=0.3.1" 12 | serde = "=1.0.115" 13 | ron = "=0.6.1" 14 | -------------------------------------------------------------------------------- /source/15_Loot_01_loot_tables/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/15_Loot_01_loot_tables/resources/dungeonfont.png -------------------------------------------------------------------------------- /source/15_Loot_01_loot_tables/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/15_Loot_01_loot_tables/resources/terminal8x8.png -------------------------------------------------------------------------------- /source/15_Loot_01_loot_tables/src/systems/fov.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[write_component(FieldOfView)] 6 | pub fn fov(ecs: &mut SubWorld, #[resource] map: &Map) { 7 | let mut views = <(&Point, &mut FieldOfView)>::query(); 8 | views 9 | .iter_mut(ecs) 10 | .filter(|(_, fov)| fov.is_dirty) 11 | .for_each(|(pos, mut fov)| { 12 | fov.visible_tiles = field_of_view_set(*pos, fov.radius, map); 13 | fov.is_dirty = false; 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /source/15_Loot_01_loot_tables/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Copy, Clone, Debug, PartialEq)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | GameOver, 7 | Victory, 8 | NextLevel, 9 | } 10 | -------------------------------------------------------------------------------- /source/15_Loot_02_better_combat/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "better_combat" 3 | version = "0.1.0" 4 | authors = ["Herbert Wolverson "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | bracket-lib = "~0.8.1" 11 | legion = "=0.3.1" 12 | serde = "=1.0.115" 13 | ron = "=0.6.1" 14 | -------------------------------------------------------------------------------- /source/15_Loot_02_better_combat/resources/dungeonfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/15_Loot_02_better_combat/resources/dungeonfont.png -------------------------------------------------------------------------------- /source/15_Loot_02_better_combat/resources/terminal8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/64kramsystem/learn_bevy_ecs_by_ripping_off-code/175a1c09239d42eb5d57d129a009bb96da14ddcd/source/15_Loot_02_better_combat/resources/terminal8x8.png -------------------------------------------------------------------------------- /source/15_Loot_02_better_combat/src/systems/fov.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[system] 4 | #[read_component(Point)] 5 | #[write_component(FieldOfView)] 6 | pub fn fov(ecs: &mut SubWorld, #[resource] map: &Map) { 7 | let mut views = <(&Point, &mut FieldOfView)>::query(); 8 | views 9 | .iter_mut(ecs) 10 | .filter(|(_, fov)| fov.is_dirty) 11 | .for_each(|(pos, mut fov)| { 12 | fov.visible_tiles = field_of_view_set(*pos, fov.radius, map); 13 | fov.is_dirty = false; 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /source/15_Loot_02_better_combat/src/turn_state.rs: -------------------------------------------------------------------------------- 1 | #[derive(Copy, Clone, Debug, PartialEq)] 2 | pub enum TurnState { 3 | AwaitingInput, 4 | PlayerTurn, 5 | MonsterTurn, 6 | GameOver, 7 | Victory, 8 | NextLevel, 9 | } 10 | --------------------------------------------------------------------------------