generated from GarandPLG/rust-flake-template
Replace named Ratatui colors with RGB values
Update docs, increase test count to 107, adjust flake.lock, and modify rendering logic to use explicit Color::Rgb throughout the codebase.
This commit is contained in:
1 parent
b1f548e3d3
commit
851d3410dd
28 files changed
+282
-152
No files matched your search
+1
-1
@@ -27,7 +27,7 @@ nix develop -c cargo run -- --disable-audio --view skirmish
|
||||
|
||||
Ostatnie polecenie wymaga interaktywnego terminala. `shellHook` drukuje dostępne polecenia, bez automatycznej kompilacji. Przy kontrolach używaj `--locked`, aby nie aktualizować `Cargo.lock`. Formatowanie stosuj wyłącznie do uzgodnionych zmian; nie używaj automatycznego `clippy --fix` do porządkowania całego repozytorium.
|
||||
|
||||
Aktualny zestaw obejmuje 106 testów. Clippy ma istniejące ostrzeżenia dla biblioteki. `clippy::unused_unit` jest dozwolony ze względu na wymagane jawne `-> ()`. Zakres i polecenia opisano w [TESTING.md](TESTING.md). Nie traktuj tego jako potwierdzenia działania pełnej rozgrywki. Nowa nietrywialna logika wymaga małego testu regresji. Nie dodawaj zależności ani warstw abstrakcji bez potrzeby.
|
||||
Aktualny zestaw obejmuje 107 testów. Clippy ma istniejące ostrzeżenia dla biblioteki. `clippy::unused_unit` jest dozwolony ze względu na wymagane jawne `-> ()`. Zakres i polecenia opisano w [TESTING.md](TESTING.md). Nie traktuj tego jako potwierdzenia działania pełnej rozgrywki. Nowa nietrywialna logika wymaga małego testu regresji. Nie dodawaj zależności ani warstw abstrakcji bez potrzeby.
|
||||
|
||||
`Cargo.toml` wymaga Rust 1.88 lub nowszego, zabrania `unsafe` we własnym kodzie i ignorowania wyników `must_use`, a w release włącza kontrolę przepełnień. CI Gitea to jeden workflow `Project tests` w `.gitea/workflows/tests.yml`, uruchamiany po pushu i dla pull requestów. Zależności `needs` ustalają kolejność `check → nix → linux → aur`; błąd joba pomija zależne joby. `check` sprawdza formatowanie, kompilację, testy debug/release i Clippy bez Nix, przez Rust 1.99.1 instalowany rustup; lokalnie nadal używaj Nix. Job `nix` buduje `.#default` z `default.nix`, z testami pakietu i kontrolą instalacji. Nie dodawaj `-D warnings` przed uporządkowaniem istniejących ostrzeżeń.
|
||||
|
||||
|
||||
+3
-3
@@ -123,7 +123,7 @@ Postęp bieżącego kroku jest udostępniany przez `MovingTask::get_movement_pro
|
||||
|
||||
Gdy panel Tab jest otwarty, fokus wskazuje własną jednostkę z zadaniami i nie jest rysowana trasa, legenda udostępnia Backspace/Cancel last task oraz Delete/Cancel all tasks. BoardState::cancel_focused_tasks usuwa ostatnie zadanie albo czyści kolejkę; waliduje właściciela, niepustą kolejkę i brak rysowania. Usunięcie zadania usuwa również jego timer. Teren i położenie jednostki pozostają bez zmian. Nie usuwamy zadań ze środka trasy, ponieważ dalsze odcinki zależą od końca poprzednich. Modal budowania zachowuje Delete do anulowania budowy.
|
||||
|
||||
BoardWidget podczas renderowania zbiera pozostałe współrzędne zadań własnych jednostek do HashSet. W widocznych kopiach CellWidget ustawia marked dla tych pól, korzystając z istniejącej pary LightMagenta/Magenta i obsługi zoomu. Nie modyfikuje flag modelu ani rysowanej trasy. Zakończenie lub anulowanie zadania usuwa podświetlenie przy kolejnym renderowaniu; trasy przeciwnika nie są pokazywane.
|
||||
BoardWidget podczas renderowania zbiera pozostałe współrzędne zadań własnych jednostek do HashSet. W widocznych kopiach CellWidget ustawia marked dla tych pól, korzystając z pary RGB magenta i obsługi zoomu. Skupione pole gotowej trasy poza wytyczaniem zadania pozostaje żółte; magenta fokusu obowiązuje podczas wytyczania. Nie modyfikuje flag modelu ani rysowanej trasy. Zakończenie lub anulowanie zadania usuwa podświetlenie przy kolejnym renderowaniu; trasy przeciwnika nie są pokazywane.
|
||||
|
||||
## Stres, podpory i zawalenia
|
||||
|
||||
@@ -135,7 +135,7 @@ Panel zadań ma zakładki TASK_OPTIONS: Digging/Moving i indeks selected_task. D
|
||||
|
||||
`advance_turn_with_events` wykonuje jeden krok jednostek i zwraca Excavation (origin, destination, owner, auto_supports). Tick SkirmishState najpierw advance_support_work (maksymalnie jedna praca na budowniczego, pauza bez budowniczego), następnie prepare_automatic_supports. Przed niebezpiecznym wykopem automat opłaca i rozpoczyna podporę na własnym polu 80%; prospective_tunnel_stress wylicza ryzyko przed uszkodzeniem przeszkody. working_on_support wstrzymuje ruch i kopanie pracującego górnika. Po wykopach tick rozstrzyga zawalenia przed rekrutacją i budową. Automat nie stawia podpory na końcu trasy, jeśli kolejny wykop jej nie potrzebuje. Low-level advance_turn pozostaje krokiem jednostek bez gospodarki i rozstrzygania stresu; pełną symulację uruchamia tick_update. Zakończenie budowy Mine również odświeża odległości sieci.
|
||||
|
||||
`Task::auto_supports/set_auto_supports` delegują ustawienie przez Tasks, DiggingTask i MovingTask; konwersja rodzaju zadania je zachowuje. BoardState::auto_supports jest domyślnym wyborem kopiowanym do nowych segmentów podczas zatwierdzenia trasy. Panel `t` jest dostępny tylko w trybie zaznaczenia przez Space i korzysta z prawego obszaru istniejącego layoutu, bez okna na środku mapy; `a` zmienia opcję, Enter zmienia rodzaj aktualnej trasy przez configure_selected_task, bez zatwierdzania jej do kolejki. Jeśli wybrano Moving, a szkic zawiera kamień, resetuje szkic do początku. Resize uwzględnia task_view. Budowanie ma zakładki Mine/Support. `s` przełącza stress_view i BoardWidget rysuje komórki przez CellWidget::render_stress: procent, gradient zielony/czerwony i dotychczasowy kolor fokusu, bez znaczników jednostek, tras i innych postępów; zwykły Stone jest wyjątkiem i zachowuje normalny wygląd, bez stresu. Model komórek nie jest mutowany przez renderowanie.
|
||||
`Task::auto_supports/set_auto_supports` delegują ustawienie przez Tasks, DiggingTask i MovingTask; konwersja rodzaju zadania je zachowuje. BoardState::auto_supports jest domyślnym wyborem kopiowanym do nowych segmentów podczas zatwierdzenia trasy. Panel `t` jest dostępny tylko w trybie zaznaczenia przez Space i korzysta z prawego obszaru istniejącego layoutu, bez okna na środku mapy; `a` zmienia opcję, Enter zmienia rodzaj aktualnej trasy przez configure_selected_task, bez zatwierdzania jej do kolejki. Jeśli wybrano Moving, a szkic zawiera kamień, resetuje szkic do początku. Resize uwzględnia task_view. Budowanie ma zakładki Mine/Support. `s` przełącza stress_view i BoardWidget rysuje komórki przez CellWidget::render_stress: koordynaty na obramowaniu, procent, gradient zielony/czerwony i dotychczasowy kolor fokusu, bez znaczników jednostek, tras i innych postępów; zwykły Stone jest wyjątkiem i zachowuje normalny wygląd, bez stresu. Model komórek nie jest mutowany przez renderowanie.
|
||||
|
||||
## Audio i pakowanie
|
||||
|
||||
@@ -153,7 +153,7 @@ To obserwacje statyczne, nie lista napraw wykonanych w tej sesji:
|
||||
- **Zaznaczenie:** wybrany górnik czeka podczas rysowania trasy; inne jednostki wykonują zadania normalnie.
|
||||
- **Audio:** usunięto aktywne odpytywanie; pomiar CPU na docelowym urządzeniu i odsłuch pozostają do wykonania. Test dekodera nie weryfikuje urządzenia audio.
|
||||
- **Granice UI:** małe terminale, resize i trzy poziomy zoomu wymagają interaktywnego sprawdzenia. Indeksowanie planszy zakłada poprawne współrzędne.
|
||||
- **Pokrycie:** 106 testów CLI, sterowania i kontekstowej legendy, renderowania, planszy, zasobów, budowania/obsadzania kopalni, rekrutacji i blokowania kolejki bazy, zadań i dekodowania audio; szczegóły w [TESTING.md](TESTING.md). Workflow Gitea sprawdza też profil release; nie obejmuje pełnej rozgrywki. Clippy ma istniejące ostrzeżenia, unused_unit jest jawnie dozwolony. Nie uruchamiać automatycznych poprawek poza zakresem zadania.
|
||||
- **Pokrycie:** 107 testów CLI, sterowania i kontekstowej legendy, renderowania, planszy, zasobów, budowania/obsadzania kopalni, rekrutacji i blokowania kolejki bazy, zadań i dekodowania audio; szczegóły w [TESTING.md](TESTING.md). Workflow Gitea sprawdza też profil release; nie obejmuje pełnej rozgrywki. Clippy ma istniejące ostrzeżenia, unused_unit jest jawnie dozwolony. Nie uruchamiać automatycznych poprawek poza zakresem zadania.
|
||||
|
||||
## Gdzie zacząć konkretną zmianę
|
||||
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
# Dziennik prac
|
||||
|
||||
## 2026-10-26 — koordynaty w mapie stresu i fokus gotowej trasy
|
||||
|
||||
CellWidget::render_stress wyświetla koordynaty na obramowaniu, w kolorze mapy stresu lub aktywnego fokusu. Kamień zachowuje zwykły wygląd. BoardWidget nie nadaje flagi marked skupionemu polu gotowej kolejki poza trybem wytyczania zadania: obramowanie jest wtedy żółte, a podczas rysowania pozostaje magenta. Podświetlenie pozostałej trasy i flagi modelu pozostają zachowane.
|
||||
|
||||
Regresje sprawdzają koordynaty przy wszystkich zoomach oraz fokus gotowej trasy przed zaznaczeniem jednostki i po Space, zarówno w zwykłym widoku, jak i mapie stresu. cargo fmt, cargo check --all-targets --locked i wszystkie 107 testów przez nix develop przeszły. Nie wykonywano ręcznej kontroli wyglądu w terminalu.
|
||||
|
||||
## 2026-10-26 — spokojniejsze kolory kratek
|
||||
|
||||
CellWidget obniża kanały RGB zwykłych, niezaznaczonych kratek o około 25%, wyłącznie podczas renderowania. Kolory jednostek, postępu, fokusu, tras, paneli i mapy stresu pozostają czytelne w dotychczasowej palecie; model struktur nie zmienia kolorów. Zastosowano cargo fmt; cargo check --all-targets --locked i wszystkie 106 testów przez nix develop przeszły. Nie oceniano wyglądu ręcznie w terminalu.
|
||||
|
||||
## 2026-10-26 — jawne kolory RGB zamiast palety terminala
|
||||
|
||||
Zastąpiono wszystkie nazwane kolory Ratatui w src/ i tests/ przez Color::Rgb, również skróty Stylize takie jak .gray(), .cyan() i .yellow(). Przyjęto standardowe wartości ANSI/xterm: podstawowe kanały 128, jasne 255, Gray (192, 192, 192), DarkGray (128, 128, 128). Kolor rudy Indexed(217) zastąpiono jego odpowiednikiem xterm (255, 175, 175). Istniejący gradient RGB stresu pozostaje bez zmian. Jawne RGB uniezależnia te kolory od palety motywu terminala, więc wygląd może różnić się od wcześniejszych kolorów nazwanych. Zmieniono wyłącznie zapis kolorów i potrzebne importy, bez dodawania warstwy motywów.
|
||||
|
||||
Zastosowano cargo fmt; cargo check --all-targets --locked i cargo test --all-targets --locked przez nix develop przeszły. git diff --check przeszedł; wyszukiwanie potwierdziło brak Color:: innych niż Rgb i nazwanych skrótów kolorowania w źródłach oraz testach. Nie sprawdzano wyglądu w interaktywnym terminalu. Zachowano zastaną zmianę użytkownika w flake.lock.
|
||||
|
||||
## 2026-10-24 — wspólny workflow Gitea i kolejność jobów
|
||||
|
||||
Odnotowano zmianę użytkownika: `.gitea/workflows/tests.yml` (`Project tests`) zastępuje osobne workflowy `rust.yml`, `nix.yml` i `packages.yml`. Po pushu i dla pull requestów wykonuje joby w kolejności `check → nix → linux → aur`, wymuszonej przez `needs`. Błąd wcześniejszego joba pomija zależne joby. `check` wykonuje kontrole Rust, `nix` buduje `.#default`, `linux` pakuje deb/rpm/AppImage/Flatpak, a `aur` buduje i instaluje paczkę Arch. Artefakty pozostają testowe, bez publikowania wydań i tagów, z retencją 7 dni.
|
||||
|
||||
+2
-2
@@ -25,7 +25,7 @@ Testy korzystają z wbudowanego mechanizmu Rust, Clap i `ratatui::backend::TestB
|
||||
| `tests/recruitment.rs` | 10 | Wyłącznie własna Base, atomowy koszt każdej pozycji i brak obciążenia przy błędzie, 10 sekund rekrutacji, oczekiwanie przy 100%, brak nadpisania jednostki, blokada kolejnych pozycji do wyjścia poprzedniego rekruta, wznowienie po ruchu, niezależne bazy i właściciele, r/Enter, ignorowanie Esc w obu panelach i kontekstowa legenda |
|
||||
| `tests/digging.rs` | 18 | Wykonywanie kopania i ruchu, kolejki, 3 sekundy na krok, wejście po wykopaniu, blokady i walidacja, kolory i procenty w TUI, podział trasy Moving/Digging, ochrona struktur, zmiana rodzaju zadania, panel Tab z postępem etapu i całego zadania |
|
||||
|
||||
Łącznie: 106 testów. Wszystkie testy znajdują się w `tests/` i sprawdzają publiczne interfejsy biblioteki lub binarkę. Funkcja `load_audio` jest eksportowana przez `app::threads`, dzięki czemu test korzysta z tego samego dekodera co odtwarzanie.
|
||||
Łącznie: 107 testów. Wszystkie testy znajdują się w `tests/` i sprawdzają publiczne interfejsy biblioteki lub binarkę. Funkcja `load_audio` jest eksportowana przez `app::threads`, dzięki czemu test korzysta z tego samego dekodera co odtwarzanie.
|
||||
|
||||
Wybrane zestawy i pojedynczy przypadek:
|
||||
|
||||
@@ -65,7 +65,7 @@ Job `check` określa obraz zadania jawnie jako `node:22-bookworm`. Kontener dzia
|
||||
|
||||
Wersję Rust w CI określa `RUST_VERSION` w workflow, niezależnie od lokalnego `flake.lock`. Formatowanie, kompilacja, testy i Clippy są oddzielnymi krokami Cargo. Polecenia kompilujące projekt mają `--locked`; Clippy nie używa `-D warnings` z powodu istniejących ostrzeżeń. `actions/cache@v4` zachowuje osobno toolchain oraz rejestr Cargo, repozytoria git i `target`. Klucze uwzględniają wersję Rust, a dla Cargo także manifest, lockfile i kod; klucze częściowe pozwalają ponownie wykorzystać wcześniejsze kompilacje. Działanie cache wymaga dostępnego serwera cache runnera. Pierwszy przebieg wypełnia cache; błędy pobierania cache mogą spowodować ponowną instalację i kompilację.
|
||||
|
||||
Release ma `overflow-checks = true`. Ten sam zestaw 106 testów można wykonać z kontrolą przepełnień w profilu produkcyjnym:
|
||||
Release ma `overflow-checks = true`. Ten sam zestaw 107 testów można wykonać z kontrolą przepełnień w profilu produkcyjnym:
|
||||
|
||||
```sh
|
||||
nix develop -c cargo test --all-targets --release --locked
|
||||
|
||||
Generated
+9
-9
@@ -8,11 +8,11 @@
|
||||
"rust-analyzer-src": "rust-analyzer-src"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1792494797,
|
||||
"narHash": "sha256-W0hLL8YLjWT/QlHcnNbON3EeDostg+GD9fw6rv4jbyY=",
|
||||
"lastModified": 1792926139,
|
||||
"narHash": "sha256-uLMpwLKdV5U1966bkbe5DzC+5Gp8O6g+wjydKmih7zQ=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "e77f56ee0521b21e5a987dd3e88b6bb367d777a7",
|
||||
"rev": "44ec3e059cf1631403a0faca34106be5fdb17631",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -46,11 +46,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1792502884,
|
||||
"narHash": "sha256-IoNisKcGbUjdd45qCqywGMCYmZ5EnkxezvLII0FWwNA=",
|
||||
"lastModified": 1792773339,
|
||||
"narHash": "sha256-rZLrzrC6i+jnTAlvPZHogKDulY7WWDEv9hJeHieO7Zw=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "02c087f3fe673c9e317f206a627cb6b910336dbe",
|
||||
"rev": "3ec636362e1816bc2f0888fa0fa2c69f1bc9e504",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -70,11 +70,11 @@
|
||||
"rust-analyzer-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1792431056,
|
||||
"narHash": "sha256-FiKlJK+NoB9J9+xIQPfJaRfK42msh55Pt6FsJ++NcxY=",
|
||||
"lastModified": 1792691653,
|
||||
"narHash": "sha256-3/DMV3Lpmthk6OV2b7bJSJ5Okouyvl755YZENyLwllo=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "7afa765037d97a62b53c59907e9f503409f2a673",
|
||||
"rev": "0c4d74686b21f2b3bd8872b6d3cf36ad2e740d49",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -14,7 +14,8 @@ pub fn block_title_helper(
|
||||
) -> Line<'static> {
|
||||
let mut line: Line<'static> = Line::default();
|
||||
|
||||
line.spans.push(Span::from("[ ").gray());
|
||||
line.spans
|
||||
.push(Span::from("[ ").fg(Color::Rgb(192, 192, 192)));
|
||||
|
||||
for (i, (text, color)) in texts.iter().enumerate() {
|
||||
let span: Span<'_> = Span::styled(text.clone(), Style::new().fg(*color));
|
||||
@@ -22,12 +23,14 @@ pub fn block_title_helper(
|
||||
|
||||
if let Some(sep) = separator {
|
||||
if i + 1 < texts.len() {
|
||||
line.spans.push(Span::from(sep).gray());
|
||||
line.spans
|
||||
.push(Span::from(sep).fg(Color::Rgb(192, 192, 192)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
line.spans.push(Span::from(" ]").gray());
|
||||
line.spans
|
||||
.push(Span::from(" ]").fg(Color::Rgb(192, 192, 192)));
|
||||
|
||||
line
|
||||
}
|
||||
|
||||
@@ -21,9 +21,9 @@ impl Players {
|
||||
|
||||
pub fn get_color(&self) -> Color {
|
||||
match self {
|
||||
Self::Player => Color::LightBlue,
|
||||
Self::Enemy => Color::LightRed,
|
||||
Self::Unclaimed => Color::White,
|
||||
Self::Player => Color::Rgb(0, 0, 255),
|
||||
Self::Enemy => Color::Rgb(255, 0, 0),
|
||||
Self::Unclaimed => Color::Rgb(255, 255, 255),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -91,9 +91,9 @@ impl Structure for BaseBuilding {
|
||||
|
||||
fn get_color(&self) -> Color {
|
||||
match self.owner {
|
||||
Players::Player => Color::LightBlue,
|
||||
Players::Enemy => Color::LightRed,
|
||||
Players::Unclaimed => Color::LightGreen,
|
||||
Players::Player => Color::Rgb(0, 0, 255),
|
||||
Players::Enemy => Color::Rgb(255, 0, 0),
|
||||
Players::Unclaimed => Color::Rgb(0, 255, 0),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ impl Structure for CollapsedTunnel {
|
||||
'#'
|
||||
}
|
||||
fn get_color(&self) -> Color {
|
||||
Color::DarkGray
|
||||
Color::Rgb(128, 128, 128)
|
||||
}
|
||||
fn get_level(&self) -> char {
|
||||
' '
|
||||
|
||||
@@ -87,9 +87,11 @@ impl Structure for Mine {
|
||||
fn text(&self) -> Vec<Line<'_>> {
|
||||
let mut lines: Vec<Line<'_>> = self.base_text();
|
||||
lines.push(Line::from_iter([
|
||||
"Ore: ".gray(),
|
||||
self.get_ore_amount().to_string().cyan(),
|
||||
format!("/{}", self.ore.get_max_ore_amount()).gray(),
|
||||
"Ore: ".fg(Color::Rgb(192, 192, 192)),
|
||||
self.get_ore_amount()
|
||||
.to_string()
|
||||
.fg(Color::Rgb(0, 128, 128)),
|
||||
format!("/{}", self.ore.get_max_ore_amount()).fg(Color::Rgb(192, 192, 192)),
|
||||
]));
|
||||
lines
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ impl Structure for Ore {
|
||||
match self.owner {
|
||||
Players::Player => self.owner.get_color(),
|
||||
Players::Enemy => self.owner.get_color(),
|
||||
Players::Unclaimed => Color::Indexed(217),
|
||||
Players::Unclaimed => Color::Rgb(255, 175, 175),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,10 +89,14 @@ impl Structure for Ore {
|
||||
let mut lines: Vec<Line<'_>> = Structure::base_text(self);
|
||||
|
||||
lines.push(Line::from_iter([
|
||||
"Ore: ".gray(),
|
||||
self.get_ore_amount().to_string().cyan(),
|
||||
"/".gray(),
|
||||
self.get_max_ore_amount().to_string().cyan(),
|
||||
"Ore: ".fg(Color::Rgb(192, 192, 192)),
|
||||
self.get_ore_amount()
|
||||
.to_string()
|
||||
.fg(Color::Rgb(0, 128, 128)),
|
||||
"/".fg(Color::Rgb(192, 192, 192)),
|
||||
self.get_max_ore_amount()
|
||||
.to_string()
|
||||
.fg(Color::Rgb(0, 128, 128)),
|
||||
]));
|
||||
|
||||
lines
|
||||
|
||||
@@ -26,7 +26,7 @@ impl Structure for Stone {
|
||||
}
|
||||
|
||||
fn get_color(&self) -> Color {
|
||||
Color::White
|
||||
Color::Rgb(255, 255, 255)
|
||||
}
|
||||
|
||||
fn get_level(&self) -> char {
|
||||
|
||||
@@ -30,21 +30,25 @@ pub trait Structure {
|
||||
|
||||
let mut lines: Vec<Line<'_>> = vec![
|
||||
Line::from_iter([
|
||||
"Durability: ".gray(),
|
||||
durability.to_string().cyan(),
|
||||
"/".gray(),
|
||||
max_durability.to_string().cyan(),
|
||||
" ( ".gray(),
|
||||
durability_percent.to_string().cyan(),
|
||||
"% )".gray(),
|
||||
"Durability: ".fg(Color::Rgb(192, 192, 192)),
|
||||
durability.to_string().fg(Color::Rgb(0, 128, 128)),
|
||||
"/".fg(Color::Rgb(192, 192, 192)),
|
||||
max_durability.to_string().fg(Color::Rgb(0, 128, 128)),
|
||||
" ( ".fg(Color::Rgb(192, 192, 192)),
|
||||
durability_percent.to_string().fg(Color::Rgb(0, 128, 128)),
|
||||
"% )".fg(Color::Rgb(192, 192, 192)),
|
||||
]),
|
||||
Line::from_iter([
|
||||
"Stress: ".fg(Color::Rgb(192, 192, 192)),
|
||||
stress.to_string().fg(Color::Rgb(0, 128, 128)),
|
||||
"%".fg(Color::Rgb(192, 192, 192)),
|
||||
]),
|
||||
Line::from_iter(["Stress: ".gray(), stress.to_string().cyan(), "%".gray()]),
|
||||
];
|
||||
|
||||
if level != ' ' {
|
||||
lines.push(Line::from_iter([
|
||||
"Level: ".gray(),
|
||||
level.to_string().cyan(),
|
||||
"Level: ".fg(Color::Rgb(192, 192, 192)),
|
||||
level.to_string().fg(Color::Rgb(0, 128, 128)),
|
||||
]));
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ impl Structure for Structures {
|
||||
let mut lines: Vec<Line<'_>> = self.s().text();
|
||||
|
||||
lines.push(Line::from_iter([
|
||||
"Owner: ".gray(),
|
||||
"Owner: ".fg(Color::Rgb(192, 192, 192)),
|
||||
self.s().get_owner().get_span(),
|
||||
]));
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ impl Structure for Tunnel {
|
||||
},
|
||||
self.support_progress().unwrap_or(0)
|
||||
))
|
||||
.cyan(),
|
||||
.fg(Color::Rgb(0, 128, 128)),
|
||||
);
|
||||
}
|
||||
lines
|
||||
@@ -111,7 +111,7 @@ impl Structure for Tunnel {
|
||||
}
|
||||
|
||||
fn get_color(&self) -> Color {
|
||||
Color::Gray
|
||||
Color::Rgb(192, 192, 192)
|
||||
}
|
||||
|
||||
fn get_level(&self) -> char {
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use ratatui::{style::Stylize, text::Line};
|
||||
use ratatui::{
|
||||
style::{Color, Stylize},
|
||||
text::Line,
|
||||
};
|
||||
|
||||
use crate::app::states::skirmish_states::{
|
||||
Players, Resources,
|
||||
@@ -107,19 +110,21 @@ impl Unit for MinerUnit {
|
||||
.flat_map(|(i, task): (usize, &Tasks)| -> [Line<'_>; 2] {
|
||||
[
|
||||
Line::from_iter([
|
||||
format!("{}. ", i + 1).gray(),
|
||||
task.get_icon().gray(),
|
||||
" ".gray(),
|
||||
self.display_coords(task.get_path_front_coords()).green(),
|
||||
" -> ".gray(),
|
||||
self.display_coords(task.get_path_back_coords()).yellow(),
|
||||
format!("{}. ", i + 1).fg(Color::Rgb(192, 192, 192)),
|
||||
task.get_icon().fg(Color::Rgb(192, 192, 192)),
|
||||
" ".fg(Color::Rgb(192, 192, 192)),
|
||||
self.display_coords(task.get_path_front_coords())
|
||||
.fg(Color::Rgb(0, 128, 0)),
|
||||
" -> ".fg(Color::Rgb(192, 192, 192)),
|
||||
self.display_coords(task.get_path_back_coords())
|
||||
.fg(Color::Rgb(128, 128, 0)),
|
||||
]),
|
||||
Line::from(format!(
|
||||
" Step: {}% | Total: {}%",
|
||||
task.get_progress() as u16,
|
||||
task.get_total_progress() as u16,
|
||||
))
|
||||
.cyan(),
|
||||
.fg(Color::Rgb(0, 128, 128)),
|
||||
]
|
||||
})
|
||||
.collect::<Vec<Line<'_>>>(),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::app::states::skirmish_states::{Players, tasks::Tasks};
|
||||
use ratatui::{
|
||||
style::Stylize,
|
||||
style::{Color, Stylize},
|
||||
text::{Line, Span},
|
||||
};
|
||||
use std::collections::VecDeque;
|
||||
@@ -51,31 +51,31 @@ pub trait Unit {
|
||||
let tasks: Vec<Line<'_>> = self.get_tasks_formatted();
|
||||
|
||||
let mut lines: Vec<Line<'_>> = Vec::from([
|
||||
Line::from_iter(["Owner: ".gray(), owner]),
|
||||
Line::from_iter(["Owner: ".fg(Color::Rgb(192, 192, 192)), owner]),
|
||||
Line::from_iter([
|
||||
"HP: ".gray(),
|
||||
hp.green(),
|
||||
"/".gray(),
|
||||
max_hp.green(),
|
||||
" ( ".gray(),
|
||||
hp_percent.green(),
|
||||
"% )".gray(),
|
||||
"HP: ".fg(Color::Rgb(192, 192, 192)),
|
||||
hp.fg(Color::Rgb(0, 128, 0)),
|
||||
"/".fg(Color::Rgb(192, 192, 192)),
|
||||
max_hp.fg(Color::Rgb(0, 128, 0)),
|
||||
" ( ".fg(Color::Rgb(192, 192, 192)),
|
||||
hp_percent.fg(Color::Rgb(0, 128, 0)),
|
||||
"% )".fg(Color::Rgb(192, 192, 192)),
|
||||
]),
|
||||
]);
|
||||
|
||||
if can_dig {
|
||||
lines.push(Line::from_iter([
|
||||
"Digging power: ".gray(),
|
||||
digging_power.green(),
|
||||
"Digging power: ".fg(Color::Rgb(192, 192, 192)),
|
||||
digging_power.fg(Color::Rgb(0, 128, 0)),
|
||||
]));
|
||||
}
|
||||
|
||||
if self.get_can_build() {
|
||||
lines.push(Line::from("Can build: Yes").green());
|
||||
lines.push(Line::from("Can build: Yes").fg(Color::Rgb(0, 128, 0)));
|
||||
}
|
||||
|
||||
if !have_any_tasks {
|
||||
lines.push(Line::from("Tasks Queue: ".gray()));
|
||||
lines.push(Line::from("Tasks Queue: ".fg(Color::Rgb(192, 192, 192))));
|
||||
for task in tasks {
|
||||
lines.push(task);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::app::{
|
||||
use ratatui::{
|
||||
buffer::Buffer,
|
||||
layout::{Alignment, Constraint, Layout, Rect},
|
||||
style::Stylize,
|
||||
style::{Color, Stylize},
|
||||
widgets::{Block, Borders, Paragraph, Widget},
|
||||
};
|
||||
|
||||
@@ -25,10 +25,10 @@ pub fn default_view(area: Rect, buf: &mut Buffer) {
|
||||
{
|
||||
Paragraph::new("Work in progress")
|
||||
.alignment(Alignment::Center)
|
||||
.yellow()
|
||||
.fg(Color::Rgb(128, 128, 0))
|
||||
.block(
|
||||
Block::new()
|
||||
.gray()
|
||||
.fg(Color::Rgb(192, 192, 192))
|
||||
.borders(Borders::LEFT | Borders::TOP | Borders::RIGHT),
|
||||
)
|
||||
.render(main_area, buf);
|
||||
|
||||
@@ -8,7 +8,7 @@ use clap::ValueEnum;
|
||||
use ratatui::{
|
||||
buffer::Buffer,
|
||||
layout::{Alignment, Constraint, Layout, Rect},
|
||||
style::Stylize,
|
||||
style::{Color, Stylize},
|
||||
text::Line,
|
||||
widgets::{Block, Borders, Paragraph, Widget},
|
||||
};
|
||||
@@ -62,8 +62,12 @@ pub fn main_menu_view(app: &App, area: Rect, buf: &mut Buffer) {
|
||||
|
||||
Paragraph::new(title_text)
|
||||
.alignment(Alignment::Center)
|
||||
.yellow()
|
||||
.block(Block::new().gray().borders(Borders::LEFT | Borders::RIGHT))
|
||||
.fg(Color::Rgb(128, 128, 0))
|
||||
.block(
|
||||
Block::new()
|
||||
.fg(Color::Rgb(192, 192, 192))
|
||||
.borders(Borders::LEFT | Borders::RIGHT),
|
||||
)
|
||||
.render(title_area, buf);
|
||||
}
|
||||
|
||||
@@ -78,9 +82,13 @@ pub fn main_menu_view(app: &App, area: Rect, buf: &mut Buffer) {
|
||||
let view_string: String = main_menu_option_helper(format!("{:?}", view));
|
||||
|
||||
let styled: Line<'_> = if states.main_menu.selected_view == i {
|
||||
Line::from_iter(["> ".cyan(), view_string.yellow()]).yellow()
|
||||
Line::from_iter([
|
||||
"> ".fg(Color::Rgb(0, 128, 128)),
|
||||
view_string.fg(Color::Rgb(128, 128, 0)),
|
||||
])
|
||||
.fg(Color::Rgb(128, 128, 0))
|
||||
} else {
|
||||
Line::from(format!(" {view_string}")).white()
|
||||
Line::from(format!(" {view_string}")).fg(Color::Rgb(255, 255, 255))
|
||||
};
|
||||
|
||||
styled
|
||||
@@ -89,8 +97,12 @@ pub fn main_menu_view(app: &App, area: Rect, buf: &mut Buffer) {
|
||||
|
||||
Paragraph::new(lines)
|
||||
.alignment(Alignment::Center)
|
||||
.green()
|
||||
.block(Block::new().gray().borders(Borders::LEFT | Borders::RIGHT))
|
||||
.fg(Color::Rgb(0, 128, 0))
|
||||
.block(
|
||||
Block::new()
|
||||
.fg(Color::Rgb(192, 192, 192))
|
||||
.borders(Borders::LEFT | Borders::RIGHT),
|
||||
)
|
||||
.render(options_area, buf);
|
||||
}
|
||||
|
||||
|
||||
+58
-48
@@ -49,7 +49,7 @@ pub fn skirmish_view(app: &App, area: Rect, buf: &mut Buffer) {
|
||||
|
||||
{
|
||||
let lines: Vec<Line<'_>> = Vec::from_iter([
|
||||
Line::raw("War in Tunnels").yellow(),
|
||||
Line::raw("War in Tunnels").fg(Color::Rgb(128, 128, 0)),
|
||||
Line::from_iter([
|
||||
format!(
|
||||
"Wood: {} (+{}/{}s) | ",
|
||||
@@ -72,7 +72,7 @@ pub fn skirmish_view(app: &App, area: Rect, buf: &mut Buffer) {
|
||||
.alignment(Alignment::Left)
|
||||
.block(
|
||||
Block::new()
|
||||
.gray()
|
||||
.fg(Color::Rgb(192, 192, 192))
|
||||
.padding(Padding {
|
||||
left: 1,
|
||||
right: 1,
|
||||
@@ -86,11 +86,11 @@ pub fn skirmish_view(app: &App, area: Rect, buf: &mut Buffer) {
|
||||
|
||||
{
|
||||
let main_block: Block = Block::new()
|
||||
.gray()
|
||||
.fg(Color::Rgb(192, 192, 192))
|
||||
.title(block_title_helper(
|
||||
&[
|
||||
("Skirmish".to_string(), Color::Magenta),
|
||||
("Map".to_string(), Color::Green),
|
||||
("Skirmish".to_string(), Color::Rgb(128, 0, 128)),
|
||||
("Map".to_string(), Color::Rgb(0, 128, 0)),
|
||||
],
|
||||
Some(" - "),
|
||||
))
|
||||
@@ -121,24 +121,24 @@ pub fn skirmish_view(app: &App, area: Rect, buf: &mut Buffer) {
|
||||
|
||||
if states.skirmish.task_view {
|
||||
let mut lines: Vec<Line<'_>> = vec![
|
||||
Line::from("Enter: draw route").green(),
|
||||
Line::from("Enter: draw route").fg(Color::Rgb(0, 128, 0)),
|
||||
Line::from(format!(
|
||||
"Auto supports: {}",
|
||||
if board.auto_supports { "ON" } else { "OFF" }
|
||||
))
|
||||
.cyan(),
|
||||
Line::from("a: toggle auto supports").yellow(),
|
||||
Line::from("Support: 10 Wood + 2 Metal").yellow(),
|
||||
Line::from("Placed at 80% stress").gray(),
|
||||
Line::from("No funds: collapse risk!").red(),
|
||||
Line::from("t: close task selection").gray(),
|
||||
.fg(Color::Rgb(0, 128, 128)),
|
||||
Line::from("a: toggle auto supports").fg(Color::Rgb(128, 128, 0)),
|
||||
Line::from("Support: 10 Wood + 2 Metal").fg(Color::Rgb(128, 128, 0)),
|
||||
Line::from("Placed at 80% stress").fg(Color::Rgb(192, 192, 192)),
|
||||
Line::from("No funds: collapse risk!").fg(Color::Rgb(128, 0, 0)),
|
||||
Line::from("t: close task selection").fg(Color::Rgb(192, 192, 192)),
|
||||
];
|
||||
if states.skirmish.selected_task == 1 {
|
||||
lines = vec![
|
||||
Line::from("Enter: draw movement route").green(),
|
||||
Line::from("Walkable cells only; no digging").cyan(),
|
||||
Line::from("Collapsed route: wait, do not dig").gray(),
|
||||
Line::from("t: close task selection").gray(),
|
||||
Line::from("Enter: draw movement route").fg(Color::Rgb(0, 128, 0)),
|
||||
Line::from("Walkable cells only; no digging").fg(Color::Rgb(0, 128, 128)),
|
||||
Line::from("Collapsed route: wait, do not dig").fg(Color::Rgb(192, 192, 192)),
|
||||
Line::from("t: close task selection").fg(Color::Rgb(192, 192, 192)),
|
||||
];
|
||||
}
|
||||
let block: Block<'_> = Block::bordered()
|
||||
@@ -150,7 +150,7 @@ pub fn skirmish_view(app: &App, area: Rect, buf: &mut Buffer) {
|
||||
block.render(side_panel_area, buf);
|
||||
Tabs::new(SkirmishState::TASK_OPTIONS.iter().copied())
|
||||
.select(states.skirmish.selected_task)
|
||||
.highlight_style(Style::default().fg(Color::LightMagenta).bold())
|
||||
.highlight_style(Style::default().fg(Color::Rgb(255, 0, 255)).bold())
|
||||
.render(tabs_area, buf);
|
||||
Paragraph::new(lines).render(details_area, buf);
|
||||
} else if states.skirmish.side_panel {
|
||||
@@ -305,25 +305,30 @@ pub fn skirmish_view(app: &App, area: Rect, buf: &mut Buffer) {
|
||||
&& site.get_owner() == Players::Player
|
||||
{
|
||||
vec![
|
||||
Line::from(format!("Construction: {}%", site.progress_percent())).cyan(),
|
||||
Line::from(format!("Construction: {}%", site.progress_percent()))
|
||||
.fg(Color::Rgb(0, 128, 128)),
|
||||
if board.has_adjacent_builder(coords, Players::Player) {
|
||||
Line::from("Builder working").green()
|
||||
Line::from("Builder working").fg(Color::Rgb(0, 128, 0))
|
||||
} else {
|
||||
Line::from("Paused: adjacent friendly builder required").yellow()
|
||||
Line::from("Paused: adjacent friendly builder required")
|
||||
.fg(Color::Rgb(128, 128, 0))
|
||||
},
|
||||
Line::from("Delete: cancel and refund full cost").yellow(),
|
||||
Line::from("Delete: cancel and refund full cost").fg(Color::Rgb(128, 128, 0)),
|
||||
]
|
||||
} else if matches!(structure, Structures::Mine(_))
|
||||
&& structure.get_owner() == Players::Player
|
||||
{
|
||||
vec![Line::from("Mine completed").green()]
|
||||
vec![Line::from("Mine completed").fg(Color::Rgb(0, 128, 0))]
|
||||
} else if states
|
||||
.skirmish
|
||||
.can_start_mine_construction(coords, Players::Player)
|
||||
{
|
||||
vec![Line::from("Ready to build: Enter").green()]
|
||||
vec![Line::from("Ready to build: Enter").fg(Color::Rgb(0, 128, 0))]
|
||||
} else {
|
||||
vec![Line::from("Construction unavailable: check site, builder and resources").red()]
|
||||
vec![
|
||||
Line::from("Construction unavailable: check site, builder and resources")
|
||||
.fg(Color::Rgb(128, 0, 0)),
|
||||
]
|
||||
};
|
||||
let mut lines: Vec<Line<'_>> = vec![
|
||||
Line::from(format!(
|
||||
@@ -331,9 +336,10 @@ pub fn skirmish_view(app: &App, area: Rect, buf: &mut Buffer) {
|
||||
Mine::COST.wood,
|
||||
Mine::COST.metal
|
||||
))
|
||||
.yellow(),
|
||||
Line::from("Requires: neutral Ore + adjacent friendly builder").gray(),
|
||||
Line::from("Produces: 1 Metal/s (2 with a Miner inside)").cyan(),
|
||||
.fg(Color::Rgb(128, 128, 0)),
|
||||
Line::from("Requires: neutral Ore + adjacent friendly builder")
|
||||
.fg(Color::Rgb(192, 192, 192)),
|
||||
Line::from("Produces: 1 Metal/s (2 with a Miner inside)").fg(Color::Rgb(0, 128, 128)),
|
||||
];
|
||||
lines.extend(status);
|
||||
if states.skirmish.selected_building == 1 {
|
||||
@@ -343,22 +349,24 @@ pub fn skirmish_view(app: &App, area: Rect, buf: &mut Buffer) {
|
||||
Tunnel::SUPPORT_COST.wood,
|
||||
Tunnel::SUPPORT_COST.metal
|
||||
))
|
||||
.yellow(),
|
||||
Line::from("Tunnel + nearby friendly builder required").gray(),
|
||||
Line::from("Stress: 20% at support, +20% per tile").cyan(),
|
||||
.fg(Color::Rgb(128, 128, 0)),
|
||||
Line::from("Tunnel + nearby friendly builder required")
|
||||
.fg(Color::Rgb(192, 192, 192)),
|
||||
Line::from("Stress: 20% at support, +20% per tile").fg(Color::Rgb(0, 128, 128)),
|
||||
if matches!(structure, Structures::Tunnel(tunnel) if tunnel.support_work().is_some())
|
||||
{
|
||||
Line::from("Builder occupied until completion").yellow()
|
||||
Line::from("Builder occupied until completion").fg(Color::Rgb(128, 128, 0))
|
||||
} else if matches!(structure, Structures::Tunnel(tunnel) if tunnel.has_support())
|
||||
&& states.skirmish.can_manage_support(coords, Players::Player)
|
||||
{
|
||||
Line::from("Delete: remove support (no refund)").yellow()
|
||||
Line::from("Delete: remove support (no refund)").fg(Color::Rgb(128, 128, 0))
|
||||
} else if states.skirmish.can_build_support(coords, Players::Player) {
|
||||
Line::from("Enter: build support").green()
|
||||
Line::from("Enter: build support").fg(Color::Rgb(0, 128, 0))
|
||||
} else {
|
||||
Line::from("Support unavailable: site, builder or resources").red()
|
||||
Line::from("Support unavailable: site, builder or resources")
|
||||
.fg(Color::Rgb(128, 0, 0))
|
||||
},
|
||||
Line::from("WARNING: removal can cause fatal collapses").red(),
|
||||
Line::from("WARNING: removal can cause fatal collapses").fg(Color::Rgb(128, 0, 0)),
|
||||
];
|
||||
if let Structures::Tunnel(tunnel) = structure
|
||||
&& let Some(work) = tunnel.support_work()
|
||||
@@ -373,23 +381,25 @@ pub fn skirmish_view(app: &App, area: Rect, buf: &mut Buffer) {
|
||||
},
|
||||
tunnel.support_progress().unwrap_or(0)
|
||||
))
|
||||
.cyan(),
|
||||
.fg(Color::Rgb(0, 128, 128)),
|
||||
);
|
||||
if board.support_worker(coords, work.owner).is_none() {
|
||||
lines.push(Line::from("Paused: friendly builder required").yellow());
|
||||
lines.push(
|
||||
Line::from("Paused: friendly builder required").fg(Color::Rgb(128, 128, 0)),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Clear.render(popup, buf);
|
||||
let block: Block<'_> = Block::bordered()
|
||||
.title(Line::from("Buildings").magenta().bold())
|
||||
.title(Line::from("Buildings").fg(Color::Rgb(128, 0, 128)).bold())
|
||||
.padding(Padding::uniform(1));
|
||||
let [tabs_area, details_area]: [Rect; 2] =
|
||||
Layout::vertical([Constraint::Length(2), Constraint::Min(0)]).areas(block.inner(popup));
|
||||
block.render(popup, buf);
|
||||
Tabs::new(SkirmishState::BUILDING_OPTIONS.iter().copied())
|
||||
.select(states.skirmish.selected_building)
|
||||
.highlight_style(Style::default().fg(Color::LightMagenta).bold())
|
||||
.highlight_style(Style::default().fg(Color::Rgb(255, 0, 255)).bold())
|
||||
.render(tabs_area, buf);
|
||||
Paragraph::new(lines).render(details_area, buf);
|
||||
}
|
||||
@@ -403,9 +413,9 @@ pub fn skirmish_view(app: &App, area: Rect, buf: &mut Buffer) {
|
||||
let status: &'static str =
|
||||
base.recruitment_status(cell.get_ref_option_unit().is_some());
|
||||
let action: Line<'_> = if states.skirmish.can_recruit_miner(coords, Players::Player) {
|
||||
Line::from("Enter: queue Miner").green()
|
||||
Line::from("Enter: queue Miner").fg(Color::Rgb(0, 128, 0))
|
||||
} else {
|
||||
Line::from("Insufficient resources or queue full").red()
|
||||
Line::from("Insufficient resources or queue full").fg(Color::Rgb(128, 0, 0))
|
||||
};
|
||||
vec![
|
||||
Line::from(format!(
|
||||
@@ -413,33 +423,33 @@ pub fn skirmish_view(app: &App, area: Rect, buf: &mut Buffer) {
|
||||
MinerUnit::RECRUIT_COST.wood,
|
||||
MinerUnit::RECRUIT_COST.metal
|
||||
))
|
||||
.yellow(),
|
||||
.fg(Color::Rgb(128, 128, 0)),
|
||||
Line::from(format!(
|
||||
"Queued Miners: {} (includes active)",
|
||||
base.queued_miners()
|
||||
))
|
||||
.cyan(),
|
||||
.fg(Color::Rgb(0, 128, 128)),
|
||||
Line::from(format!(
|
||||
"Current progress: {}%",
|
||||
base.recruitment_progress()
|
||||
))
|
||||
.cyan(),
|
||||
Line::from(status).yellow(),
|
||||
.fg(Color::Rgb(0, 128, 128)),
|
||||
Line::from(status).fg(Color::Rgb(128, 128, 0)),
|
||||
action,
|
||||
]
|
||||
} else {
|
||||
vec![Line::from("Select your Base to recruit Miners").red()]
|
||||
vec![Line::from("Select your Base to recruit Miners").fg(Color::Rgb(128, 0, 0))]
|
||||
};
|
||||
Clear.render(popup, buf);
|
||||
let block: Block<'_> = Block::bordered()
|
||||
.title(Line::from("Recruitment").magenta().bold())
|
||||
.title(Line::from("Recruitment").fg(Color::Rgb(128, 0, 128)).bold())
|
||||
.padding(Padding::uniform(1));
|
||||
let [tabs_area, details_area]: [Rect; 2] =
|
||||
Layout::vertical([Constraint::Length(2), Constraint::Min(0)]).areas(block.inner(popup));
|
||||
block.render(popup, buf);
|
||||
Tabs::new(SkirmishState::RECRUITMENT_OPTIONS.iter().copied())
|
||||
.select(states.skirmish.selected_recruit)
|
||||
.highlight_style(Style::default().fg(Color::LightMagenta).bold())
|
||||
.highlight_style(Style::default().fg(Color::Rgb(255, 0, 255)).bold())
|
||||
.render(tabs_area, buf);
|
||||
Paragraph::new(lines).render(details_area, buf);
|
||||
}
|
||||
|
||||
@@ -58,7 +58,10 @@ impl Widget for BoardWidget<'_> {
|
||||
row_idx + self.state.vertical_offset.get_value(),
|
||||
col_idx + self.state.horizontal_offset.get_value(),
|
||||
);
|
||||
if queued_path.contains(&coords) {
|
||||
if queued_path.contains(&coords)
|
||||
&& (coords != self.state.get_focused_cell().get_coords()
|
||||
|| self.state.marked_cells.marking_cells)
|
||||
{
|
||||
cell.set_marked(true);
|
||||
}
|
||||
if self.stress {
|
||||
|
||||
+19
-10
@@ -39,7 +39,10 @@ impl CellWidget {
|
||||
} else {
|
||||
Color::Rgb(red, 255 - red, 30)
|
||||
};
|
||||
let block: Block<'_> = Block::bordered().border_type(BorderType::Rounded).fg(color);
|
||||
let block: Block<'_> = Block::bordered()
|
||||
.border_type(BorderType::Rounded)
|
||||
.fg(color)
|
||||
.title(format!("{}{}", self.col_to_letters(), self.row));
|
||||
let inner: Rect = block.inner(area);
|
||||
block.render(area, buf);
|
||||
if inner.height == 0 || inner.width == 0 {
|
||||
@@ -132,7 +135,7 @@ impl CellWidget {
|
||||
|
||||
fn display_coords(&self) -> Span<'_> {
|
||||
if self.selected || self.structure != Structures::Stone(Stone::new()) || self.marked {
|
||||
format!("{}{}", self.col_to_letters(), self.row).green()
|
||||
format!("{}{}", self.col_to_letters(), self.row).fg(Color::Rgb(0, 128, 0))
|
||||
} else {
|
||||
"".to_span()
|
||||
}
|
||||
@@ -140,13 +143,18 @@ impl CellWidget {
|
||||
|
||||
fn fg_color(&self) -> Color {
|
||||
if self.marked && self.selected {
|
||||
Color::Magenta
|
||||
Color::Rgb(128, 0, 128)
|
||||
} else if self.marked && !self.selected {
|
||||
Color::LightMagenta
|
||||
Color::Rgb(255, 0, 255)
|
||||
} else if !self.marked && self.selected {
|
||||
Color::LightYellow
|
||||
Color::Rgb(255, 255, 0)
|
||||
} else {
|
||||
self.structure.get_color()
|
||||
match self.structure.get_color() {
|
||||
Color::Rgb(red, green, blue) => {
|
||||
Color::Rgb(red - red / 4, green - green / 4, blue - blue / 4)
|
||||
}
|
||||
color => color,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,11 +175,12 @@ impl CellWidget {
|
||||
let percent: u32 = u32::from(self.structure.get_durability()) * 100
|
||||
/ u32::from(self.structure.get_max_durability());
|
||||
let middle: usize = lines.len() / 2;
|
||||
lines[middle] = Line::from(format!("{percent}%")).cyan();
|
||||
lines[middle] = Line::from(format!("{percent}%")).fg(Color::Rgb(0, 128, 128));
|
||||
}
|
||||
if let Structures::MineConstruction(site) = self.structure {
|
||||
let middle: usize = lines.len() / 2;
|
||||
lines[middle] = Line::from(format!("{}%", site.progress_percent())).cyan();
|
||||
lines[middle] =
|
||||
Line::from(format!("{}%", site.progress_percent())).fg(Color::Rgb(0, 128, 128));
|
||||
}
|
||||
if let Some(unit) = &self.unit
|
||||
&& let Some(Tasks::Moving(task)) = unit.get_ref_tasks().front()
|
||||
@@ -190,13 +199,13 @@ impl CellWidget {
|
||||
} else {
|
||||
format!("{percent}%")
|
||||
};
|
||||
lines[middle] = Line::from(label).cyan();
|
||||
lines[middle] = Line::from(label).fg(Color::Rgb(0, 128, 128));
|
||||
}
|
||||
if let Structures::Tunnel(tunnel) = self.structure
|
||||
&& let Some(percent) = tunnel.support_progress()
|
||||
{
|
||||
let middle: usize = lines.len() / 2;
|
||||
lines[middle] = Line::from(format!("{percent}%")).cyan();
|
||||
lines[middle] = Line::from(format!("{percent}%")).fg(Color::Rgb(0, 128, 128));
|
||||
}
|
||||
lines
|
||||
}
|
||||
|
||||
@@ -83,7 +83,11 @@ impl KeybindingsWidget {
|
||||
description
|
||||
},
|
||||
);
|
||||
Line::from_iter([kb.symbol.red().bold(), " - ".into(), description.into()])
|
||||
Line::from_iter([
|
||||
kb.symbol.fg(Color::Rgb(128, 0, 0)).bold(),
|
||||
" - ".into(),
|
||||
description.into(),
|
||||
])
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
@@ -140,7 +144,7 @@ impl Widget for KeybindingsWidget {
|
||||
.borders(Borders::ALL)
|
||||
.title(block_single_title_helper(
|
||||
"Keybindings".to_string(),
|
||||
Color::Magenta,
|
||||
Color::Rgb(128, 0, 128),
|
||||
));
|
||||
|
||||
let inner: Rect = block.inner(area);
|
||||
|
||||
@@ -54,7 +54,7 @@ impl<'a> SidePanelWidget<'a> {
|
||||
.border_type(BorderType::Double)
|
||||
.title(block_single_title_helper(
|
||||
format!("{}{}", self.col_to_letters(), self.coords.0),
|
||||
Color::Yellow,
|
||||
Color::Rgb(128, 128, 0),
|
||||
))
|
||||
.title_alignment(Alignment::Center)
|
||||
}
|
||||
@@ -108,7 +108,10 @@ impl Widget for SidePanelWidget<'_> {
|
||||
}
|
||||
Paragraph::new(structure_text)
|
||||
.alignment(Alignment::Left)
|
||||
.block(self.get_inner_block(self.structure.get_name().to_string(), Color::Cyan))
|
||||
.block(self.get_inner_block(
|
||||
self.structure.get_name().to_string(),
|
||||
Color::Rgb(0, 128, 128),
|
||||
))
|
||||
.render(structure_area, buf);
|
||||
|
||||
if self.unit.is_unit() {
|
||||
@@ -120,7 +123,7 @@ impl Widget for SidePanelWidget<'_> {
|
||||
|
||||
Paragraph::new(self.unit.text())
|
||||
.alignment(Alignment::Left)
|
||||
.block(self.get_inner_block(unit_name, Color::Green))
|
||||
.block(self.get_inner_block(unit_name, Color::Rgb(0, 128, 0)))
|
||||
.render(unit_area, buf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,8 +178,13 @@ fn contextual_help_fits_normal_terminal_and_changes_when_route_is_selected() ->
|
||||
#[test]
|
||||
fn construction_and_recruitment_popups_render_semantic_text_colors() -> () {
|
||||
for (key, name, status, status_color) in [
|
||||
('b', "Mine", "Construction unavailable", Color::Red),
|
||||
('r', "Miner", "Enter: queue Miner", Color::Green),
|
||||
(
|
||||
'b',
|
||||
"Mine",
|
||||
"Construction unavailable",
|
||||
Color::Rgb(128, 0, 0),
|
||||
),
|
||||
('r', "Miner", "Enter: queue Miner", Color::Rgb(0, 128, 0)),
|
||||
] {
|
||||
let mut app: App = app();
|
||||
if key == 'r' {
|
||||
@@ -194,8 +199,8 @@ fn construction_and_recruitment_popups_render_semantic_text_colors() -> () {
|
||||
.unwrap();
|
||||
let cells: &[Cell] = &terminal.backend().buffer().content;
|
||||
for (text, color) in [
|
||||
(name, Color::LightMagenta),
|
||||
("Cost:", Color::Yellow),
|
||||
(name, Color::Rgb(255, 0, 255)),
|
||||
("Cost:", Color::Rgb(128, 128, 0)),
|
||||
(status, status_color),
|
||||
] {
|
||||
assert!(
|
||||
|
||||
@@ -92,7 +92,7 @@ fn base_cell_shows_recruitment_progress_until_spawn_at_every_zoom() -> () {
|
||||
.find(|cell: &&Cell| -> bool { cell.symbol() == "%" })
|
||||
.unwrap()
|
||||
.fg,
|
||||
Color::Cyan
|
||||
Color::Rgb(0, 128, 128)
|
||||
);
|
||||
if zoom != ZoomLevel::ZoomedOut {
|
||||
assert!(text(&buffer).contains('M'));
|
||||
|
||||
@@ -53,10 +53,56 @@ fn route_color_count(app: &mut App) -> usize {
|
||||
.buffer()
|
||||
.content
|
||||
.iter()
|
||||
.filter(|cell: &&Cell| -> bool { matches!(cell.fg, Color::Magenta | Color::LightMagenta) })
|
||||
.filter(|cell: &&Cell| -> bool {
|
||||
matches!(cell.fg, Color::Rgb(128, 0, 128) | Color::Rgb(255, 0, 255))
|
||||
})
|
||||
.count()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn focused_queued_route_is_yellow_until_drawing_a_task() -> () {
|
||||
let mut app: App = app();
|
||||
let board: &mut BoardState = &mut app.states_mut().unwrap().skirmish.board;
|
||||
board.cells[5][3].set_structure(Structures::Tunnel(Tunnel::new()));
|
||||
board.cells[5][2]
|
||||
.get_mut_option_unit()
|
||||
.set_task(Tasks::Moving(MovingTask::new([(5, 3)].into())));
|
||||
board.change_focused_cell(MoveFocusedCell::Right);
|
||||
for drawing in [false, true] {
|
||||
if drawing {
|
||||
press(&mut app, KeyCode::Left);
|
||||
press(&mut app, KeyCode::Char(' '));
|
||||
}
|
||||
let board: &BoardState = &app.states_ref().unwrap().skirmish.board;
|
||||
assert_eq!(board.get_focused_cell().get_coords(), (5, 3));
|
||||
for stress in [false, true] {
|
||||
app.states_mut().unwrap().skirmish.stress_view = stress;
|
||||
let mut terminal: Terminal<TestBackend> =
|
||||
Terminal::new(TestBackend::new(160, 50)).unwrap();
|
||||
terminal
|
||||
.draw(|frame: &mut ratatui::Frame<'_>| -> () {
|
||||
frame.render_widget(&mut app, frame.area());
|
||||
})
|
||||
.unwrap();
|
||||
let corner: &Cell = &terminal
|
||||
.backend()
|
||||
.buffer()
|
||||
.content
|
||||
.windows(3)
|
||||
.find(|cells: &&[Cell]| -> bool {
|
||||
cells[0].symbol() == "╭" && cells[1].symbol() == "D" && cells[2].symbol() == "5"
|
||||
})
|
||||
.unwrap()[0];
|
||||
let expected: Color = if drawing {
|
||||
Color::Rgb(128, 0, 128)
|
||||
} else {
|
||||
Color::Rgb(255, 255, 0)
|
||||
};
|
||||
assert_eq!(corner.fg, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn queued_route_colors_follow_progress_and_cancellation_without_marking_model() -> () {
|
||||
let mut app: App = app();
|
||||
|
||||
@@ -447,7 +447,7 @@ fn rubble_can_be_dug_again_and_auto_setting_survives_task_conversion() -> () {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stress_view_hides_all_other_text_and_colors_but_keeps_focused_color() -> () {
|
||||
fn stress_view_shows_coordinates_and_stress_but_keeps_focused_color() -> () {
|
||||
let mut app: App = app();
|
||||
let game: &mut SkirmishState = &mut app.states_mut().unwrap().skirmish;
|
||||
put_tunnel(&mut game.board, (5, 3), true);
|
||||
@@ -477,21 +477,25 @@ fn stress_view_hides_all_other_text_and_colors_but_keeps_focused_color() -> () {
|
||||
.map(|cell: &Cell| -> &str { cell.symbol() })
|
||||
.collect();
|
||||
assert!(text.contains("20%"));
|
||||
assert!(text.contains("D5"));
|
||||
assert!(!text.contains('M') && !text.contains('T'));
|
||||
assert!(!buffer.content.iter().any(|cell: &Cell| -> bool {
|
||||
matches!(cell.fg, Color::Magenta | Color::LightMagenta | Color::Blue)
|
||||
matches!(
|
||||
cell.fg,
|
||||
Color::Rgb(128, 0, 128) | Color::Rgb(255, 0, 255) | Color::Rgb(0, 0, 128)
|
||||
)
|
||||
}));
|
||||
game.board.cells[5][3]
|
||||
.clone()
|
||||
.set_selected(true)
|
||||
.render_stress(area, &mut buffer);
|
||||
assert_eq!(buffer[(0, 0)].fg, Color::LightYellow);
|
||||
assert_eq!(buffer[(0, 0)].fg, Color::Rgb(255, 255, 0));
|
||||
game.board.cells[5][3]
|
||||
.clone()
|
||||
.set_selected(true)
|
||||
.set_marked(true)
|
||||
.render_stress(area, &mut buffer);
|
||||
assert_eq!(buffer[(0, 0)].fg, Color::Magenta);
|
||||
assert_eq!(buffer[(0, 0)].fg, Color::Rgb(128, 0, 128));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user