- Delete obsolete .gitea/workflows/nix.yml and rust.yml.
- Rename packages.yml to tests.yml.
- Add jobs check, nix, linux, aur with proper needs ordering.
- Update docs for new unified workflow.
- Remove bash and docker from flake.nix buildInputs.
Introduce support structures (roof supports) and a stress system that
propagates from bases through tunnels, causing collapses when stress
reaches 100 %. Add auto‑support feature with toggleable tasks, new
keybindings (Tasks, AutoSupports, Stress), and a support‑building tab.
Implement collapsed tunnels, support work progress, and related UI
rendering (stress view, auto‑support indicators). Extend board resize
logic, update game state structs, and adjust keybinding actions. Update
documentation (README, AGENTS, CODE_MAP, PROGRESS, TESTING) to reflect
new features. Add flake.nix dependencies (bash, gitea‑actions‑runner,
docker). Add extensive tests for tunnel stress, support building,
auto‑supports, and related mechanics.
- Add selection indices and option lists to SkirmishState.
- Implement `cycle_popup_option` and expose Left/Right actions in
keybindings.
- Introduce `cancel_focused_tasks` in BoardState for Delete handling.
- CellWidget now displays recruitment progress on Base structures.
- Update README and documentation to describe new tabs and arrow
navigation.
- Adjust test counts and add extensive task‑cancellation tests.
- Replace Ctrl+Space with `b` and Alt+Space with `r` in README and
documentation.
- Remove the old Alt+Space recruitment keybinding and adjust key
handling code.
- Revamp skirmish view to display colored lines and updated status
messages.
- Increase test suite to 83 tests and update test expectations for new
shortcuts.
- Update flake.lock with the latest revision and hash.
- Adjust rustfmt.toml to set tab_spaces = 4.
- Reformat imports, struct definitions, function bodies, and match arms
across the project to match the new style (aligned fields, added
spacing, etc.).
- Ensure all code complies with the updated rustfmt settings.
- Updated CLI, README and documentation to use `--starting-metal` with
`--starting-iron` retained as an alias.
- Introduced `Resources` struct and constants for wood delivery and mine
production.
- Added new structures `Mine` and `MineConstruction` with cost,
production
and cancel logic.
- Implemented building view for constructing mines and recruitment view
for spawning miners.
- Extended keybindings with `Building` and `Recruitment` actions and
updated
action availability logic.
- Modified game state, board, units and UI widgets to handle metal
resources
and new construction mechanics.
- Updated tests and increased total test count to 82, covering
resources,
construction, recruitment and context‑aware keybindings.
Introduce a new CI workflow `.gitea/workflows/packages.yml` that builds
deb, rpm, AppImage, Flatpak and AUR packages on push and PR events.
Add packaging helpers (`build.sh`, `stage.sh`, spec file, PKGBUILD,
desktop entry, SVG icon) and supporting assets under `packaging/`.
Update `.gitignore` to ignore the generated `dist` directory.
Expand documentation (CODE_MAP, AGENTS, PROGRESS, TESTING and new
PACKAGING.md) to describe the packaging process and its limitations.
Adjust `src/app/threads/audio.rs` and `tests/audio.rs` imports to
support loading audio files from installed package layouts.
Install required system packages and set RUST_VERSION=1.99.1. Cache the
Rust
toolchain and Cargo registry, and run Cargo commands directly instead of
via
`nix develop`. Documentation files are updated to reflect the new
workflow.
- Run CI jobs in `node:22-bookworm` container, install sudo and disable
KVM for the Nix installer.
- Replace CC0 with the MIT license and add `license = "MIT"` to
Cargo.toml.
- Update README and documentation (CODE_MAP, PROGRESS, TESTING) to
reflect the new license and CI changes.
- Document new Rust formatting standards in AGENTS, CODE_MAP, and
PROGRESS.
- Add rustfmt.toml with style 2024, 2‑space indents, 100‑char width, LF
endings.
- Apply consistent 2‑space indentation and ordering across source files.
- Minor clean‑up of imports and whitespace to match the new style.
Introduce a new MovingTask type for movement segments and extend
the Tasks enum
to include it. Add total‑step tracking and a get_total_progress default
in the
Task trait, and implement the corresponding methods for MovingTask.
Update
units to allow coordinate changes via set_coords, add stone damage
handling,
and adjust board advancement logic to use the new task system. Update
UI
code to display step and total percentages in the Tab panel. Expand
documentation (README, AGENTS, CODE_MAP, PROGRESS, TESTING) to describe
digging
and moving, and add extensive tests (including tests/digging.rs) for the
new
behaviour.
- Introduce a comprehensive test suite (cli, app, board, tasks, audio)
and a
new TESTING.md document describing test execution.
- Correct vertical offset calculation in `BoardState` to use saturating
subtraction and ceiling division.
- Clamp initial `Offset` values to the provided maximum in
`Offset::new`.
- Export `load_audio` from the audio thread module and switch to
`LoopedDecoder` for proper OGG looping.
- Update several crate versions: clap, ratatui, log, rodio, and
bitflags.
Introduce AGENTS.md as an entry point for agents, add CODE_MAP.md with a
module overview and diagrams, and create PROGRESS.md to log work
progress.
Update flake.lock to reflect dependency revisions.
- Disable automatic board.advance_turn and replace it with explicit unit
movement handling.
- Add Tunnel structure creation during digging tasks.
- Extend DiggingTask with pop_front and current_target helpers.
- Rename task getters to get_ref_tasks and add mutable get_mut_tasks.
- Update Unit trait and Units enum to expose these new methods.
- Remove unused EMPTY_TASKS lazy static.
- Bump flake.lock revisions, hashes, and timestamps for several
dependencies.
- Extend the `Task` trait with methods for progress handling and
completion.
- Update `DiggingTask` to store `progress` and `tick_increase`, and
implement the new trait methods.
- Implement the new methods in the `Tasks` enum, adding a mutable
accessor.
- Introduce `BoardState::get_active_tasks` and
`BoardState::advance_turn` to iterate over active tasks and update
their progress each turn.
- Un-comment the call to `board.advance_turn()` in
`SkirmishState::tick_update`.
Map width flag changed from -M to -W and height flag set to -H.
Added short flags: -w (wood), -i (iron), -L (supply limit),
-P (skill points), -m (mute soundtrack), -l (enable logging).
Introduce push_marked_cell, pop_marked_cell and end_marking_cells to
replace the
previous set_marked_cell, undo_marked_cell and clear_marked_cells.
Collapse
get_row/get_col into get_coords and update all callers accordingly.
Change `get_tasks_formatted` to return a `Vec<Line<'_>>` instead of a
plain
`String`. Update `MinerUnit` to construct colored task lines, modify the
`Unit` trait and `Units` implementations to use the new return type, and
add the required `ratatui` imports. Adjust `base_text` handling to
render
each task line separately.
Define a full `Task` trait with icon and path accessors. Implement the
trait for
`DiggingTask` and delegate it through the `Tasks` enum. Introduce helper
functions in `MinerUnit` to convert coordinates to spreadsheet‑style
strings
and use them in a revamped `get_tasks_formatted`. Update the unit
rendering
logic to show the tasks queue only when tasks are present.
- Change `get_tasks` to return `&VecDeque<Tasks>` instead of a formatted
`String`.
- Introduce `get_tasks_formatted` for display purposes.
- Update `MinerUnit`, `Unit` trait, `Units` enum, and its `Option`
implementation accordingly.
- Add `EMPTY_TASKS` lazy static for handling empty task lists.
- Adjust `BoardState` to use the new task API (commented out
conditional).
Add `get_tasks` to the `Unit` trait and implement it for `MinerUnit`,
`Units` enum and `Option<Units>`. Use the new method in `base_text` to
display a “Tasks Queue” line.
Refactor task assignment in `BoardState` to a chained call.
Update the skirmish view and `SidePanelWidget` to pass a flag indicating
whether the displayed unit is the currently marked one, and highlight
the
unit name accordingly.
Introduce Tasks handling for units, store coordinates in MinerUnit,
expose getters/setters for unit tasks, add logging of marked cells,
and provide cell accessors for mutable unit options.
Refactor App, GameStates, SkirmishState and BoardState to carry a
generic
lifetime `'a`. Introduce a new `MarkedCells` type that holds marking
state
and selected unit, replacing the previous `marking_cells` flag and raw
deque. Update related methods, keybindings, view implementations and
module exports to use the new structures.
Replace `Vec` with `VecDeque` in `BoardState` marked cells,
`DiggingTask` path,
and `MinerUnit` tasks to enable efficient push/pop operations. Remove
the
`Copy` trait from several structs and enums, adjust derives accordingly,
and
use `as_ref` in `Option<Units>` implementations to avoid consuming the
option.
Update cell rendering to clone widgets and adjust
`CellWidget::get_option_unit`
to return a cloned `Option<Units>`. Add necessary `VecDeque` imports.
Rename `structure` to `s` in Structures and `unit` to `u` in Units,
updating all
call sites. Refactor `Structures::text` to match on the owner directly
and
push the owner line only for claimed owners. Change the “% )” token
color
in unit display from green to gray.
- Remove lifetime and path storage from DiggingTask, make it Copy.
- Add a placeholder `new` constructor that accepts a path.
- Update the Tasks enum to hold a DiggingTask value.
- Reorder module declarations and re‑export order for tasks.
- Add a commented‑out tasks field to MinerUnit as a preparation step.
- Extend MinerUnit with hp, digging ability, and power, and provide
getters for these fields.
- Update the Unit trait and Units enum to expose hp, max hp,
can_dig, and digging_power, and enhance base_text to display them.
- Remove unnecessary `Eq` derives from several structs and enums.
- Introduce a `--disable-audio` CLI flag and conditionally spawn the
audio thread based on its value.
Move the 33 ms tick interval into `tick` as a public constant `TICK_MS`
and drop the parameter from `handle_tick_event`.
Update re‑exports and callers accordingly
Add owner line to structure text, using gray label and owner span.
Switch side panel layout to Fill/Length and remove left border from side
panel widget.
Import Stylize for colored text rendering.
Introduce a numeric `level` field for `BaseBuilding` and `Ore`, update
their
constructors and `get_level` implementations, and increase the default
ore
amount to the new maximum. Extend the `Structure` and `Unit` traits with
`base_text` and `text` methods, add `is_unit` to `Units`, and adjust the
`Structures` enum to delegate text rendering. Refactor `SidePanelWidget`
to
use the unified trait methods, removing duplicated rendering code.
Update
`BoardState` to create ore structures with an initial level of 1.
Add a new Ore structure with ownership, amount, and durability, and
extend the
Structures enum to include it. Update board generation to place ore
cells next
to player and enemy bases and adjust base coordinates accordingly.
Remove the
redundant `max_durability` field from BaseBuilding, Stone, and Tunnel,
fixing
their `get_max_durability` implementations to return constant values.
Rename the
tick handling parameter from `interval_ms` to `tick_ms`. Minor clean‑ups
include
re‑exporting the Ore module, adding TODO comments in the side panel
widget, and
simplifying the audio thread spawn in `main.rs`.
Refactor App::run to accept individual Receiver arguments instead of an
AppChannels struct. Delete the AppChannels definition and its re‑export,
and update main.rs to create each channel manually and pass the
receivers
to App::run. Rename the CLI field `sound_track` to `soundtrack` and
adjust
all references. Clean up imports and formatting accordingly.
App now receives an AppChannels struct; AppEvent enum removed.
Event handling, tick generation, and audio communication are now
performed through dedicated channels.
Introduce `AppEvent::Tick` and a background thread that emits timed
events. `App` now handles `Tick` by calling a new `update` method,
which advances the board and increments a `turn_counter` in
`SkirmishState`. Add required imports, fields, and the
`spawn_tick_thread` call in `main`.
Move the GameMode and Players enums from the top‑level states module
into the
skirmish_states submodule, add an Unclaimed variant to Players, and
update all
imports, trait implementations, and related logic accordingly. Adjust
the
durability percentage calculation to use u32 for safety.
- Introduce `max_durability` fields to BaseBuilding, Stone, and Tunnel
structures.
- Extend `Structure` trait with `get_max_durability` and implement it in
all structures.
- Update `Structures` enum to forward `get_max_durability`.
- Add color utilities and `get_span` method to `Players` enum for styled
text.
- Refactor `CellWidget` method names (`get_option_unit`,
`set_structure`).
- Revise side panel widget to accept references to `Structures` and
`Option<Units>`, render colored blocks and detailed stats.
- Simplify skirmish view to use `BoardState` directly and adapt side
panel rendering.
Introduce a `side_panel` flag throughout the skirmish state, board
creation,
and cell area calculation to enable a detachable side panel. Refactor
the
title helper to own its strings and use a static separator, updating the
single‑title helper accordingly. Add a new `SidePanelWidget` and expose
the
`skirmish_main_area_layout` helper. Extend keybindings with `Tab` and
`ShiftTab` actions under a new `Opener` group. Update structures and
units
to implement a `get_name` method and adjust related traits and imports.
Introduce Structure and Unit traits with enum wrappers.
Replace old zoom helper with ZoomLevel methods.
Update imports, BoardState, CellWidget, and CLI to use new locations.
Introduce new building types Stone and Tunnel with their own tag, color,
and
properties. CellStructure now holds these structs (Tunnel, Stone)
instead of
simple variants. BaseBuilding is simplified to return a char tag and a
color
based on owner. BoardState creation and CellWidget rendering are updated
to
use the new building structs and their methods.
- Define `pname` once and inherit it in the package definition.
- Change description to “TUI underground RTS”.
- Set `mainProgram` to `pname` for consistency.
Export `block_title` and `helpers` with `pub mod` for external use.
Add Nix improvements: version check hook, update script, install check.
Include post‑install step to copy soundtracks and rename binary.
Extend meta with platforms, mainProgram, and maintainer handling.
Update docs to show required imports for block title helpers.
Move Units enum from the units module into the skirmish state module,
add a dedicated Players enum, and remove the now‑unused unit module.
Update all imports accordingly.
Adjust CellWidget's set_zoom_level and set_structure to return &mut
Self,
enabling method chaining.
The refactor removes the `Buildings` enum and the `building` module,
replacing
`CellTag` with a new `CellStructure` enum that directly holds a
`BaseBuilding`.
A `get_owner` method is added to `BaseBuilding` to support the new
structure.
All related imports, constructors, and rendering logic are updated to
use
`CellStructure` instead of the old tag and building fields.
Introduce BaseBuilding struct. Rename Building and Unit to enum types
(Buildings, Units). Move CellTag and Players enums to the skirmish state
module and update imports and re‑exports accordingly. Add placeholder
miner module.
Introduce empty Building and Unit types and expose them
through new modules. Extend CellWidget to store optional
Unit and Building, update its constructor, and adjust board
rendering to create cells with these new fields (currently always None).
CellWidget::set_selected and set_marked now return &mut Self for method
chaining. Added BoardState::undo_marked_cell to remove the last marked
cell and restore focus. Backspace triggers undo, Delete clears marking.
Introduce a public `BoardState::toggle_marking` that flips the
marking mode and starts or clears marking accordingly. Refactor
`set_marked_cell` to accept tuple coordinates and clean up its
logic. Update `change_focused_cell` to work with the new signature
and use the toggle helper. Adjust cell display to show coordinates
when a cell is marked.
Introduce a marking mode that lets users toggle cells with Space and
clear
them with Backspace. BoardState now stores `marking_cells` and a list of
`marked_cells` and provides methods to start, clear, and update marks.
CellWidget tracks a `marked` flag and renders marked cells in
LightMagenta.
Keybindings are updated: Space now reads “Marking cells”, Backspace
reads
“Cancel marking”, and the original Enter binding is commented out.
The former `resize_change` and `zoom_change` functions are renamed to
`change_resize` and `change_zoom`; all call sites are updated
accordingly.
Introduce `CellTag` and `Players` enums and extend `CellWidget` to carry
a tag.
Store player and enemy base coordinates in `BoardState` and tag those
cells.
Reduce horizontal margin from 3 to 1 in board layout helpers.
Change CLI defaults: map width default 42, map height min 11 and default
11.
Adjust offset calculation and render constraints to match the new
layout.
The event loop function is now defined in `events.rs`, the redundant
`handle_events.rs` file is removed, and the module re‑exports are
updated
to expose `handle_events` from `events`.
Introduce a `Soundtrack` enum with Clap `ValueEnum` support and expose
it in the CLI as a `--sound-track` option. Extend `AudioCmd` with a
`ChangeSoundtrack` variant and refactor audio handling to load and cache
soundtracks per‑track using a thread‑safe `RwLock`. Update the
`handle_audio` function signature to accept the selected soundtrack,
adjust re‑exports, and modify `main` to pass the chosen soundtrack to
the audio thread. Also reposition the logging flag in the CLI
definition.
Add once_cell 1.21.4 and a Lazy‑initialized HashMap to store OGG bytes.
Replace file reads with in‑memory Cursor decoding, fix the
SoundrackParts enum typo, and derive Hash traits for it.
Introduce a `ChangePart` variant to `AudioCmd` and a `current_part`
state in
`handle_audio`. The audio sink is now created via
`DeviceSinkBuilder::from_default_device` with a fixed buffer size.
`load_audio`
now accepts a reference to `SoundrackParts`, and the player
automatically
queues the correct part when the queue becomes empty.
Update `CellWidget::new` to take a `selected` flag and remove the
chaining return values from `set_selected` and `set_zoom_level`. The
board code now passes the selection state directly during construction.
Store cells as a nested vector instead of a flat list, simplifying
indexing and
rendering. Add `is_focused_cell_visible` to detect when the focused cell
is
outside the viewport and adjust vertical/horizontal offsets accordingly
in
the skirmish keybindings. Update related methods and widget rendering to
use
the new 2‑D structure.
Introduce a MoveFocusedCell enum and a BoardState.change_focused_cell
method to
centralize focus movement logic. Update skirmish keybindings to use this
new
method and simplify board rendering by directly using stored CellWidget
state.
Make CellWidget setters chainable and expose the new enum in the module
re‑exports. Remove duplicated max_offset logic and old move_* methods.
- CellWidget now stores a ZoomLevel, renders size‑dependent text, and
provides
methods to set the zoom level and build its block.
- BoardState creates cells with the current zoom level, adds a helper to
get a
mutable cell, and updates each cell’s zoom level in `zoom_change`.
- KeybindingsWidget constructor now takes the widget height, calculates
vertical padding to centre groups, and adds left borders between
groups.
- Views (default, main_menu, skirmish) pass the area height to the new
constructor.
- Keybinding descriptions are replaced with emoji symbols (🔈, 🔊, 🔉).
- BoardWidget clones the cell template instead of dereferencing it.
Rename the input event handler module and function.
Update imports, re‑exports, and main.rs to use handle_events.
Add a brief doc comment for the new function.
Add ALSA and Rodio crates to Cargo.toml and lockfile to enable audio
playback.
Update Nix expressions to include `alsa-lib` as a build input.
Refactor input event handling into a new `app::threads` module:
- Define `AppEvent` enum and `handle_input_events` function there.
- Adjust imports in `app/app.rs` and `main.rs` accordingly.
Remove the now‑unused `handle_input_events` and `AppEvent`
definitions from
`app/app.rs`.
Store the input event thread handle and join it after the app finishes.
This
replaces the previous fire‑and‑forget spawn and ensures the thread is
cleanly
terminated before the program exits.
Rename the generic `Event` enum to `AppEvent` and propagate the change
through `app.rs`, `mod.rs`, and `main.rs`. Adjust function signatures,
imports, and channel usage to use the new name and the `read` helper
from crossterm. Ensure all senders/receivers now work with `AppEvent`.
App now stores CLI arguments and an optional GameStates, initializing
the
states lazily on the first window resize. Skirmish board logic is moved
to
a new BoardState module with dedicated helpers (cells_area_helper and
updated cell size handling). Views and keybindings are updated to use
the
optional state accessors.
Extract Offset and FocusedCell structs from skirmish.rs into a new
skirmish_states module. Re-export the structs from the top-level states
module and adjust imports in skirmish.rs.
- Track terminal size in `App::window_area` and update on resize
- Accept action slices in `count_largest_group` and
`KeybindingsWidget::new`
- Add ACTIONS slices and layout helpers for default, main_menu, skirmish
- Add `main_menu_option_helper` for formatting menu strings and export
it
Introduce a new `zoom_level` module containing the `CellSizes` enum and
`cell_size_helper` function to map `ZoomLevel` values to width and
height
dimensions. Export the helper from `mod.rs` and refactor `BoardWidget`
to
import and use `cell_size_helper`, eliminating duplicated match
statements.
- Initialize FocusedCell with map dimensions and start near the map
centre.
- Store max rows/cols in FocusedCell and clamp moves to these bounds.
- Scroll actions now adjust the corresponding offset and also move the
focused cell, keeping navigation consistent.
- Zoom actions modify the vertical offset to keep the view centered
after
changing zoom levels.
- Cell widget now uses a Padding widget with dynamic top padding based
on
the area height.
Introduce `col_to_letters` to convert a zero‑based column index into
Excel‑style
letters. Add `display_coords` that returns the column letters followed
by the
row number. Update `render` to use this formatted coordinate as the
block
title instead of the previous row/col placeholder.