Debug demo map: four allied masters with every room and creature against an endless hero gate
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5f70992cfb
commit
210f17773a
23 files changed
+536
-3
No files matched your search
@@ -390,6 +390,7 @@ set.debug_trigger_zones = Zobrazit zóny spouštěčů
|
|||||||
set.debug_command_markers = Zobrazit ladicí značky rozkazů
|
set.debug_command_markers = Zobrazit ladicí značky rozkazů
|
||||||
set.debug_path_lines = Zobrazit čáry cest
|
set.debug_path_lines = Zobrazit čáry cest
|
||||||
set.debug_holiday = Svátek
|
set.debug_holiday = Svátek
|
||||||
|
set.debug_demo_map = Spustit ukázkovou mapu
|
||||||
val.halloween = Halloween
|
val.halloween = Halloween
|
||||||
val.christmas = Vánoce
|
val.christmas = Vánoce
|
||||||
val.easter = Velikonoce
|
val.easter = Velikonoce
|
||||||
|
|||||||
@@ -389,6 +389,7 @@ set.debug_trigger_zones = Vis udløserzoner
|
|||||||
set.debug_command_markers = Vis debug-ordremarkører
|
set.debug_command_markers = Vis debug-ordremarkører
|
||||||
set.debug_path_lines = Vis stilinjer
|
set.debug_path_lines = Vis stilinjer
|
||||||
set.debug_holiday = Højtid
|
set.debug_holiday = Højtid
|
||||||
|
set.debug_demo_map = Start demokort
|
||||||
val.halloween = Halloween
|
val.halloween = Halloween
|
||||||
val.christmas = Jul
|
val.christmas = Jul
|
||||||
val.easter = Påske
|
val.easter = Påske
|
||||||
|
|||||||
@@ -389,6 +389,7 @@ set.debug_trigger_zones = Triggerzonen anzeigen
|
|||||||
set.debug_command_markers = Debug-Befehlsmarker anzeigen
|
set.debug_command_markers = Debug-Befehlsmarker anzeigen
|
||||||
set.debug_path_lines = Pfadlinien anzeigen
|
set.debug_path_lines = Pfadlinien anzeigen
|
||||||
set.debug_holiday = Festzeit
|
set.debug_holiday = Festzeit
|
||||||
|
set.debug_demo_map = Demokarte starten
|
||||||
val.halloween = Halloween
|
val.halloween = Halloween
|
||||||
val.christmas = Weihnachten
|
val.christmas = Weihnachten
|
||||||
val.easter = Ostern
|
val.easter = Ostern
|
||||||
|
|||||||
@@ -390,6 +390,7 @@ set.debug_trigger_zones = Εμφάνιση ζωνών ενεργοποίησης
|
|||||||
set.debug_command_markers = Εμφάνιση δεικτών εντολών debug
|
set.debug_command_markers = Εμφάνιση δεικτών εντολών debug
|
||||||
set.debug_path_lines = Εμφάνιση γραμμών διαδρομής
|
set.debug_path_lines = Εμφάνιση γραμμών διαδρομής
|
||||||
set.debug_holiday = Γιορτή
|
set.debug_holiday = Γιορτή
|
||||||
|
set.debug_demo_map = Έναρξη χάρτη επίδειξης
|
||||||
val.halloween = Halloween
|
val.halloween = Halloween
|
||||||
val.christmas = Χριστούγεννα
|
val.christmas = Χριστούγεννα
|
||||||
val.easter = Πάσχα
|
val.easter = Πάσχα
|
||||||
|
|||||||
@@ -390,6 +390,7 @@ set.debug_trigger_zones = Show trigger zones
|
|||||||
set.debug_command_markers = Show debug command markers
|
set.debug_command_markers = Show debug command markers
|
||||||
set.debug_path_lines = Show path lines
|
set.debug_path_lines = Show path lines
|
||||||
set.debug_holiday = Holiday
|
set.debug_holiday = Holiday
|
||||||
|
set.debug_demo_map = Start demo map
|
||||||
val.halloween = Halloween
|
val.halloween = Halloween
|
||||||
val.christmas = Christmas
|
val.christmas = Christmas
|
||||||
val.easter = Easter
|
val.easter = Easter
|
||||||
|
|||||||
@@ -390,6 +390,7 @@ set.debug_trigger_zones = Mostrar zonas de activación
|
|||||||
set.debug_command_markers = Mostrar marcadores de órdenes
|
set.debug_command_markers = Mostrar marcadores de órdenes
|
||||||
set.debug_path_lines = Mostrar líneas de ruta
|
set.debug_path_lines = Mostrar líneas de ruta
|
||||||
set.debug_holiday = Festividad
|
set.debug_holiday = Festividad
|
||||||
|
set.debug_demo_map = Iniciar mapa de demostración
|
||||||
val.halloween = Halloween
|
val.halloween = Halloween
|
||||||
val.christmas = Navidad
|
val.christmas = Navidad
|
||||||
val.easter = Pascua
|
val.easter = Pascua
|
||||||
|
|||||||
@@ -390,6 +390,7 @@ set.debug_trigger_zones = Näytä laukaisualueet
|
|||||||
set.debug_command_markers = Näytä komentomerkit
|
set.debug_command_markers = Näytä komentomerkit
|
||||||
set.debug_path_lines = Näytä reittiviivat
|
set.debug_path_lines = Näytä reittiviivat
|
||||||
set.debug_holiday = Juhlakausi
|
set.debug_holiday = Juhlakausi
|
||||||
|
set.debug_demo_map = Aloita esittelykartta
|
||||||
val.halloween = Halloween
|
val.halloween = Halloween
|
||||||
val.christmas = Joulu
|
val.christmas = Joulu
|
||||||
val.easter = Pääsiäinen
|
val.easter = Pääsiäinen
|
||||||
|
|||||||
@@ -390,6 +390,7 @@ set.debug_trigger_zones = Prikaži zone okidača
|
|||||||
set.debug_command_markers = Prikaži debug oznake naredbi
|
set.debug_command_markers = Prikaži debug oznake naredbi
|
||||||
set.debug_path_lines = Prikaži linije putanja
|
set.debug_path_lines = Prikaži linije putanja
|
||||||
set.debug_holiday = Blagdan
|
set.debug_holiday = Blagdan
|
||||||
|
set.debug_demo_map = Pokreni demo kartu
|
||||||
val.halloween = Halloween
|
val.halloween = Halloween
|
||||||
val.christmas = Božić
|
val.christmas = Božić
|
||||||
val.easter = Uskrs
|
val.easter = Uskrs
|
||||||
|
|||||||
@@ -390,6 +390,7 @@ set.debug_trigger_zones = Indítózónák mutatása
|
|||||||
set.debug_command_markers = Debug parancsjelölők mutatása
|
set.debug_command_markers = Debug parancsjelölők mutatása
|
||||||
set.debug_path_lines = Útvonalak mutatása
|
set.debug_path_lines = Útvonalak mutatása
|
||||||
set.debug_holiday = Ünnep
|
set.debug_holiday = Ünnep
|
||||||
|
set.debug_demo_map = Bemutató térkép indítása
|
||||||
val.halloween = Halloween
|
val.halloween = Halloween
|
||||||
val.christmas = Karácsony
|
val.christmas = Karácsony
|
||||||
val.easter = Húsvét
|
val.easter = Húsvét
|
||||||
|
|||||||
@@ -390,6 +390,7 @@ set.debug_trigger_zones = Mostra zone trigger
|
|||||||
set.debug_command_markers = Mostra marcatori comandi
|
set.debug_command_markers = Mostra marcatori comandi
|
||||||
set.debug_path_lines = Mostra percorsi
|
set.debug_path_lines = Mostra percorsi
|
||||||
set.debug_holiday = Festività
|
set.debug_holiday = Festività
|
||||||
|
set.debug_demo_map = Avvia mappa demo
|
||||||
val.halloween = Halloween
|
val.halloween = Halloween
|
||||||
val.christmas = Natale
|
val.christmas = Natale
|
||||||
val.easter = Pasqua
|
val.easter = Pasqua
|
||||||
|
|||||||
@@ -390,6 +390,7 @@ set.debug_trigger_zones = Triggerzones tonen
|
|||||||
set.debug_command_markers = Debug-commandomarkeringen tonen
|
set.debug_command_markers = Debug-commandomarkeringen tonen
|
||||||
set.debug_path_lines = Padlijnen tonen
|
set.debug_path_lines = Padlijnen tonen
|
||||||
set.debug_holiday = Feestdag
|
set.debug_holiday = Feestdag
|
||||||
|
set.debug_demo_map = Demokaart starten
|
||||||
val.halloween = Halloween
|
val.halloween = Halloween
|
||||||
val.christmas = Kerstmis
|
val.christmas = Kerstmis
|
||||||
val.easter = Pasen
|
val.easter = Pasen
|
||||||
|
|||||||
@@ -389,6 +389,7 @@ set.debug_trigger_zones = Vis utløsersoner
|
|||||||
set.debug_command_markers = Vis debug-ordremarkører
|
set.debug_command_markers = Vis debug-ordremarkører
|
||||||
set.debug_path_lines = Vis stilinjer
|
set.debug_path_lines = Vis stilinjer
|
||||||
set.debug_holiday = Høytid
|
set.debug_holiday = Høytid
|
||||||
|
set.debug_demo_map = Start demokart
|
||||||
val.halloween = Halloween
|
val.halloween = Halloween
|
||||||
val.christmas = Jul
|
val.christmas = Jul
|
||||||
val.easter = Påske
|
val.easter = Påske
|
||||||
|
|||||||
@@ -390,6 +390,7 @@ set.debug_trigger_zones = Mostrar zonas de ativação
|
|||||||
set.debug_command_markers = Mostrar marcadores de comando
|
set.debug_command_markers = Mostrar marcadores de comando
|
||||||
set.debug_path_lines = Mostrar linhas de caminho
|
set.debug_path_lines = Mostrar linhas de caminho
|
||||||
set.debug_holiday = Festividade
|
set.debug_holiday = Festividade
|
||||||
|
set.debug_demo_map = Iniciar mapa de demonstração
|
||||||
val.halloween = Halloween
|
val.halloween = Halloween
|
||||||
val.christmas = Natal
|
val.christmas = Natal
|
||||||
val.easter = Páscoa
|
val.easter = Páscoa
|
||||||
|
|||||||
@@ -390,6 +390,7 @@ set.debug_trigger_zones = Arată zonele declanșatoare
|
|||||||
set.debug_command_markers = Arată marcajele de comenzi (depanare)
|
set.debug_command_markers = Arată marcajele de comenzi (depanare)
|
||||||
set.debug_path_lines = Arată liniile de traseu
|
set.debug_path_lines = Arată liniile de traseu
|
||||||
set.debug_holiday = Sărbătoare
|
set.debug_holiday = Sărbătoare
|
||||||
|
set.debug_demo_map = Pornește harta demo
|
||||||
val.halloween = Halloween
|
val.halloween = Halloween
|
||||||
val.christmas = Crăciun
|
val.christmas = Crăciun
|
||||||
val.easter = Paște
|
val.easter = Paște
|
||||||
|
|||||||
@@ -390,6 +390,7 @@ set.debug_trigger_zones = Зоны триггеров
|
|||||||
set.debug_command_markers = Маркеры отладочных команд
|
set.debug_command_markers = Маркеры отладочных команд
|
||||||
set.debug_path_lines = Линии путей
|
set.debug_path_lines = Линии путей
|
||||||
set.debug_holiday = Праздник
|
set.debug_holiday = Праздник
|
||||||
|
set.debug_demo_map = Запустить демо-карту
|
||||||
val.halloween = Хэллоуин
|
val.halloween = Хэллоуин
|
||||||
val.christmas = Рождество
|
val.christmas = Рождество
|
||||||
val.easter = Пасха
|
val.easter = Пасха
|
||||||
|
|||||||
@@ -390,6 +390,7 @@ set.debug_trigger_zones = Zobraziť zóny spúšťačov
|
|||||||
set.debug_command_markers = Zobraziť ladiace značky rozkazov
|
set.debug_command_markers = Zobraziť ladiace značky rozkazov
|
||||||
set.debug_path_lines = Zobraziť čiary ciest
|
set.debug_path_lines = Zobraziť čiary ciest
|
||||||
set.debug_holiday = Sviatok
|
set.debug_holiday = Sviatok
|
||||||
|
set.debug_demo_map = Spustiť ukážkovú mapu
|
||||||
val.halloween = Halloween
|
val.halloween = Halloween
|
||||||
val.christmas = Vianoce
|
val.christmas = Vianoce
|
||||||
val.easter = Veľká noc
|
val.easter = Veľká noc
|
||||||
|
|||||||
@@ -390,6 +390,7 @@ set.debug_trigger_zones = Прикажи зоне окидача
|
|||||||
set.debug_command_markers = Прикажи дебаг ознаке наредби
|
set.debug_command_markers = Прикажи дебаг ознаке наредби
|
||||||
set.debug_path_lines = Прикажи линије путања
|
set.debug_path_lines = Прикажи линије путања
|
||||||
set.debug_holiday = Празник
|
set.debug_holiday = Празник
|
||||||
|
set.debug_demo_map = Покрени демо мапу
|
||||||
val.halloween = Ноћ вештица
|
val.halloween = Ноћ вештица
|
||||||
val.christmas = Божић
|
val.christmas = Божић
|
||||||
val.easter = Ускрс
|
val.easter = Ускрс
|
||||||
|
|||||||
@@ -390,6 +390,7 @@ set.debug_trigger_zones = Visa triggerzoner
|
|||||||
set.debug_command_markers = Visa debug-ordermarkörer
|
set.debug_command_markers = Visa debug-ordermarkörer
|
||||||
set.debug_path_lines = Visa stiglinjer
|
set.debug_path_lines = Visa stiglinjer
|
||||||
set.debug_holiday = Högtid
|
set.debug_holiday = Högtid
|
||||||
|
set.debug_demo_map = Starta demokarta
|
||||||
val.halloween = Halloween
|
val.halloween = Halloween
|
||||||
val.christmas = Jul
|
val.christmas = Jul
|
||||||
val.easter = Påsk
|
val.easter = Påsk
|
||||||
|
|||||||
+1
-1
@@ -153,7 +153,7 @@ impl Tracker {
|
|||||||
|
|
||||||
// called every frame; returns achievements unlocked just now
|
// called every frame; returns achievements unlocked just now
|
||||||
pub fn update(&mut self, g: &Game, ctx: &Context, dt: f32, now: u64) -> Vec<String> {
|
pub fn update(&mut self, g: &Game, ctx: &Context, dt: f32, now: u64) -> Vec<String> {
|
||||||
if g.demo.is_some() || ctx.editor_test {
|
if g.demo.is_some() || g.demo_map.is_some() || ctx.editor_test {
|
||||||
self.last_time = 0.0;
|
self.last_time = 0.0;
|
||||||
return Vec::new();
|
return Vec::new();
|
||||||
}
|
}
|
||||||
|
|||||||
+471
@@ -0,0 +1,471 @@
|
|||||||
|
// The demo map of the debug menu: all four dungeon masters (the player and three AI partners, all
|
||||||
|
// allied) each have a walled dungeon with every room kind and every dungeon creature kind. Their
|
||||||
|
// dungeons lie in the four corners around the humans' gate in the middle; the attack flag goes up
|
||||||
|
// on the gate now and then and all four armies march on it together, in between the creatures do
|
||||||
|
// their work in the rooms. The gate never falls and keeps sending heroes of every kind, the soul
|
||||||
|
// cores never fall, the treasuries never run dry. Meant to watch every animation; nothing of it
|
||||||
|
// counts for achievements or overwrites the autosave (see main.rs, achievements.rs).
|
||||||
|
|
||||||
|
use crate::game::*;
|
||||||
|
use crate::map::*;
|
||||||
|
use crate::render3d::Cam;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
const W: usize = 74;
|
||||||
|
const H: usize = 74;
|
||||||
|
const PLAZA: (i32, i32) = (37, 37); // middle of the humans' plaza (the gate stands on it)
|
||||||
|
const PLAZA_R: f32 = 8.5;
|
||||||
|
const HALF: i32 = 10; // a dungeon's floor reaches this far from the middle of its soul core
|
||||||
|
// the masters and the middle of their dungeons: player north-west, then clockwise
|
||||||
|
pub const MASTERS: [(u8, (i32, i32)); 4] = [(0, (13, 13)), (2, (60, 13)), (3, (60, 60)), (4, (13, 60))];
|
||||||
|
// every creature kind a dungeon can have (imps come with every master)
|
||||||
|
pub const CREATURES: [EK; 17] = [
|
||||||
|
EK::Kobold,
|
||||||
|
EK::Spider,
|
||||||
|
EK::Mage,
|
||||||
|
EK::Ogre,
|
||||||
|
EK::Jailer,
|
||||||
|
EK::Priestess,
|
||||||
|
EK::Chainbreaker,
|
||||||
|
EK::Bat,
|
||||||
|
EK::Gargoyle,
|
||||||
|
EK::Owl,
|
||||||
|
EK::Wyrm,
|
||||||
|
EK::Cogling,
|
||||||
|
EK::Revenant,
|
||||||
|
EK::CaveBear,
|
||||||
|
EK::Beetle,
|
||||||
|
EK::Ram,
|
||||||
|
EK::Catapult,
|
||||||
|
];
|
||||||
|
// the gate sends them in this order, over and over
|
||||||
|
pub const HEROES: [EK; 14] = [
|
||||||
|
EK::Knight,
|
||||||
|
EK::Archer,
|
||||||
|
EK::Priest,
|
||||||
|
EK::Dwarf,
|
||||||
|
EK::Fairy,
|
||||||
|
EK::Thief,
|
||||||
|
EK::BattleMage,
|
||||||
|
EK::Monk,
|
||||||
|
EK::Paladin,
|
||||||
|
EK::Ranger,
|
||||||
|
EK::Giant,
|
||||||
|
EK::Inquisitor,
|
||||||
|
EK::Ram,
|
||||||
|
EK::Catapult,
|
||||||
|
];
|
||||||
|
const HERO_EVERY: f32 = 1.2; // seconds between two heroes at the gate
|
||||||
|
const MAX_HEROES: usize = 30; // fighting heroes on the map at most
|
||||||
|
const RESTOCK_EVERY: f32 = 15.0; // seconds between two looks for creature kinds that died out
|
||||||
|
const ATTACK_FOR: f32 = 75.0; // the flag stays on the gate this long ...
|
||||||
|
const HOME_FOR: f32 = 40.0; // ... then the creatures are free for their rooms this long
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||||
|
pub struct DemoMap {
|
||||||
|
pub hero_t: f32,
|
||||||
|
pub next_hero: u32,
|
||||||
|
pub heroes_sent: u32,
|
||||||
|
pub restock_t: f32,
|
||||||
|
pub phase_t: f32, // seconds until the flag goes up (or down)
|
||||||
|
pub attacking: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
// the 3x3 room slots of a dungeon around its core, one tile of corridor between them (5 x 5
|
||||||
|
// slots, the middle one is the core): top-left corners
|
||||||
|
fn slots(c: (i32, i32)) -> Vec<(i32, i32)> {
|
||||||
|
let mut v = Vec::new();
|
||||||
|
for ky in -2..=2 {
|
||||||
|
for kx in -2..=2 {
|
||||||
|
if kx != 0 || ky != 0 {
|
||||||
|
v.push((c.0 - 1 + 4 * kx, c.1 - 1 + 4 * ky));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v
|
||||||
|
}
|
||||||
|
|
||||||
|
fn in_square(c: (i32, i32), x: i32, y: i32, r: i32) -> bool {
|
||||||
|
(x - c.0).abs() <= r && (y - c.1).abs() <= r
|
||||||
|
}
|
||||||
|
|
||||||
|
// the spot of the attack flag: on the plaza right before the gate
|
||||||
|
fn rally_tile() -> usize {
|
||||||
|
idx(PLAZA.0, PLAZA.1 + 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Game {
|
||||||
|
pub fn new_demo_map(seed: u32) -> (Game, Cam) {
|
||||||
|
let opts = GenOpts { portals: Some(0), treasures: Some(0), gate: false, core_y: None };
|
||||||
|
let mut map = Map::generate_with(seed, W, H, &opts);
|
||||||
|
let (wi, hi) = (W as i32, H as i32);
|
||||||
|
// solid earth everywhere, with a few gold veins between the dungeons
|
||||||
|
for y in 2..hi - 2 {
|
||||||
|
for x in 2..wi - 2 {
|
||||||
|
let t = &mut map.t[idx(x, y)];
|
||||||
|
let var = t.var;
|
||||||
|
*t = Tile::new(Kind::Earth);
|
||||||
|
t.var = var;
|
||||||
|
t.hp = 6.0;
|
||||||
|
let h = ((x * 73 + y * 151) as u32).wrapping_mul(2654435761) >> 26;
|
||||||
|
let between = MASTERS.iter().all(|&(_, c)| !in_square(c, x, y, HALF + 1)) && ((x - PLAZA.0).pow(2) + (y - PLAZA.1).pow(2)) as f32 > (PLAZA_R + 2.0).powi(2);
|
||||||
|
if between && h % 17 == 0 {
|
||||||
|
t.kind = Kind::Gold;
|
||||||
|
t.gold = 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// the humans' plaza with the gate in the middle
|
||||||
|
for y in 2..hi - 2 {
|
||||||
|
for x in 2..wi - 2 {
|
||||||
|
if (((x - PLAZA.0).pow(2) + (y - PLAZA.1).pow(2)) as f32) <= PLAZA_R * PLAZA_R {
|
||||||
|
let t = &mut map.t[idx(x, y)];
|
||||||
|
t.kind = Kind::Floor;
|
||||||
|
t.owner = Owner::Hero;
|
||||||
|
t.gold = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let gate = (PLAZA.0 - 1, PLAZA.1 - 1);
|
||||||
|
for y in gate.1..gate.1 + 3 {
|
||||||
|
for x in gate.0..gate.0 + 3 {
|
||||||
|
let t = &mut map.t[idx(x, y)];
|
||||||
|
t.kind = Kind::Gate;
|
||||||
|
t.owner = Owner::Hero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
map.gate = gate;
|
||||||
|
// the dungeons: a square of own floor in a reinforced wall, the core in the middle, the
|
||||||
|
// rooms around it
|
||||||
|
map.portals.clear();
|
||||||
|
map.treasures.clear();
|
||||||
|
for &(side, c) in MASTERS.iter() {
|
||||||
|
let owner = Owner::of_side(side);
|
||||||
|
for y in c.1 - HALF - 1..=c.1 + HALF + 1 {
|
||||||
|
for x in c.0 - HALF - 1..=c.0 + HALF + 1 {
|
||||||
|
let t = &mut map.t[idx(x, y)];
|
||||||
|
t.owner = owner;
|
||||||
|
t.gold = 0;
|
||||||
|
if in_square(c, x, y, HALF) {
|
||||||
|
t.kind = Kind::Floor;
|
||||||
|
} else {
|
||||||
|
t.kind = Kind::Earth;
|
||||||
|
t.reinforced = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for y in c.1 - 1..=c.1 + 1 {
|
||||||
|
for x in c.0 - 1..=c.0 + 1 {
|
||||||
|
map.t[idx(x, y)].kind = Kind::Core;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// every room kind, more beds and food, the portal on the far side; slots left over
|
||||||
|
// stay plain floor for the master's own plans
|
||||||
|
let mut rooms: Vec<Kind> = ROOM_KINDS.to_vec();
|
||||||
|
rooms.extend([Kind::Lair, Kind::Lair, Kind::Farm, Kind::Aerie]);
|
||||||
|
let mut list = slots(c);
|
||||||
|
// the slots nearest the plaza first: the busy rooms are what the camera sees
|
||||||
|
list.sort_by_key(|&(x, y)| (x + 1 - PLAZA.0).pow(2) + (y + 1 - PLAZA.1).pow(2));
|
||||||
|
let portal = list.pop().unwrap();
|
||||||
|
for y in portal.1..portal.1 + 3 {
|
||||||
|
for x in portal.0..portal.0 + 3 {
|
||||||
|
map.t[idx(x, y)].kind = Kind::Portal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
map.portals.push(portal);
|
||||||
|
for (&(sx, sy), &kind) in list.iter().zip(rooms.iter()) {
|
||||||
|
for y in sy..sy + 3 {
|
||||||
|
for x in sx..sx + 3 {
|
||||||
|
map.t[idx(x, y)].kind = kind;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// corridors from every dungeon to the plaza (through the wall)
|
||||||
|
for &(side, c) in MASTERS.iter() {
|
||||||
|
let owner = Owner::of_side(side);
|
||||||
|
let (dx, dy) = ((PLAZA.0 - c.0) as f32, (PLAZA.1 - c.1) as f32);
|
||||||
|
let n = (dx.abs().max(dy.abs()) * 2.0) as i32;
|
||||||
|
for k in 0..=n {
|
||||||
|
let (px, py) = (c.0 as f32 + 0.5 + dx * k as f32 / n as f32, c.1 as f32 + 0.5 + dy * k as f32 / n as f32);
|
||||||
|
for y in (py - 1.5) as i32..=(py + 1.5) as i32 {
|
||||||
|
for x in (px - 1.5) as i32..=(px + 1.5) as i32 {
|
||||||
|
if (x as f32 + 0.5 - px).powi(2) + (y as f32 + 0.5 - py).powi(2) > 1.6 * 1.6 || x < 2 || y < 2 || x >= wi - 2 || y >= hi - 2 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let t = &mut map.t[idx(x, y)];
|
||||||
|
if in_square(c, x, y, HALF) || t.owner == Owner::Hero {
|
||||||
|
continue; // the dungeon's rooms and the plaza stay as they are
|
||||||
|
}
|
||||||
|
let wall = in_square(c, x, y, HALF + 1);
|
||||||
|
t.kind = Kind::Floor;
|
||||||
|
t.reinforced = false;
|
||||||
|
t.gold = 0;
|
||||||
|
t.owner = if wall { owner } else { Owner::None };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let player = MASTERS[0].1;
|
||||||
|
map.core = (player.0 - 1, player.1 - 1);
|
||||||
|
let mut g = Game::from_map(map, seed);
|
||||||
|
// from_map put a treasury ring around the player's core, on the corridors between the
|
||||||
|
// rooms: back to floor (his treasury is one of the rooms, like everybody's)
|
||||||
|
for y in player.1 - 2..=player.1 + 2 {
|
||||||
|
for x in player.0 - 2..=player.0 + 2 {
|
||||||
|
let t = &mut g.map.t[idx(x, y)];
|
||||||
|
if t.kind == Kind::Treasury && ((x - player.0).abs() == 2 || (y - player.1).abs() == 2) {
|
||||||
|
t.kind = Kind::Floor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.demo_map = Some(DemoMap { hero_t: 3.0, next_hero: 0, heroes_sent: 0, restock_t: RESTOCK_EVERY, phase_t: 15.0, attacking: false });
|
||||||
|
g.gate_on = true;
|
||||||
|
g.gate_hp = GATE_HP;
|
||||||
|
g.wave_timer = f32::MAX;
|
||||||
|
g.coop = true;
|
||||||
|
g.ai_sides = vec![2, 3, 4];
|
||||||
|
// the three AI partners: real masters with the brain of ai.rs (hard: they think fast)
|
||||||
|
for &(side, c) in MASTERS.iter().skip(1) {
|
||||||
|
let core = (c.0 - 1, c.1 - 1);
|
||||||
|
g.rivals.push(crate::rival::Rival {
|
||||||
|
side,
|
||||||
|
core,
|
||||||
|
hp: crate::rival::RIVAL_CORE_HP,
|
||||||
|
alive: true,
|
||||||
|
radius: HALF + 1,
|
||||||
|
grow_t: 20.0,
|
||||||
|
spawn_t: 5.0,
|
||||||
|
attack_t: 0.0,
|
||||||
|
difficulty: 2,
|
||||||
|
power: 0.0,
|
||||||
|
gift_t: crate::rival::PARTNER_GIFT_EVERY,
|
||||||
|
think_t: 2.0,
|
||||||
|
attacking: false,
|
||||||
|
army0: 0.0,
|
||||||
|
focus: None,
|
||||||
|
defending: false,
|
||||||
|
});
|
||||||
|
g.adopt_master(side, core, 2, true);
|
||||||
|
}
|
||||||
|
// every creature kind for every master, gold in the treasuries
|
||||||
|
for &(side, _) in MASTERS.iter() {
|
||||||
|
g.switch_to(side);
|
||||||
|
g.recount();
|
||||||
|
for &kind in CREATURES.iter() {
|
||||||
|
g.demo_map_creature(side, kind);
|
||||||
|
}
|
||||||
|
let fill = g.gold_cap() * 0.7 - g.gold;
|
||||||
|
g.add_gold(fill.max(0.0));
|
||||||
|
g.mana = g.mana_max();
|
||||||
|
g.wood = g.wood.max(200.0);
|
||||||
|
}
|
||||||
|
g.switch_to(0);
|
||||||
|
g.place_all_torches();
|
||||||
|
g.msgs.clear();
|
||||||
|
// the camera on the plaza, where the four armies meet
|
||||||
|
let mut cam = Cam::new(PLAZA.0 as f32 + 0.5, PLAZA.1 as f32 + 0.5);
|
||||||
|
cam.zoom = 30.0;
|
||||||
|
(g, cam)
|
||||||
|
}
|
||||||
|
|
||||||
|
// a creature of `kind` for the master on `side` (the master being processed), somewhere on
|
||||||
|
// the floor of his dungeon
|
||||||
|
fn demo_map_creature(&mut self, side: u8, kind: EK) {
|
||||||
|
let Some(&(_, c)) = MASTERS.iter().find(|m| m.0 == side) else { return };
|
||||||
|
let owner = Owner::of_side(side);
|
||||||
|
let spots: Vec<usize> = (0..self.map.t.len())
|
||||||
|
.filter(|&i| {
|
||||||
|
let (x, y) = xy(i);
|
||||||
|
let t = &self.map.t[i];
|
||||||
|
in_square(c, x, y, HALF) && t.owner == owner && t.walkable() && t.kind != Kind::Portal
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
if spots.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let i = spots[self.rng.next() as usize % spots.len()];
|
||||||
|
let (x, y) = xy(i);
|
||||||
|
let level = 2 + self.rng.next() % 5;
|
||||||
|
let id = self.spawn(kind, false, x as f32 + 0.5, y as f32 + 0.5, level);
|
||||||
|
if let Some(e) = self.ents.iter_mut().find(|e| e.id == id) {
|
||||||
|
e.side = side;
|
||||||
|
e.settled = true;
|
||||||
|
e.happy = 1.0;
|
||||||
|
if crate::siege::siege(kind) {
|
||||||
|
e.home = Some((x as f32 + 0.5, y as f32 + 0.5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the demo map's rules, once per step from the first master's side: the gate and the cores
|
||||||
|
// never fall, gold never runs out, heroes keep coming, the flag goes up and down
|
||||||
|
pub(crate) fn demo_map_tick(&mut self, dt: f32) {
|
||||||
|
let Some(mut d) = self.demo_map.take() else { return };
|
||||||
|
let back = self.me_side;
|
||||||
|
self.gate_hp = GATE_HP;
|
||||||
|
self.gate_stage = 0;
|
||||||
|
self.wave_timer = f32::MAX;
|
||||||
|
self.warned = true;
|
||||||
|
self.out_sides.clear();
|
||||||
|
// the attack flag of the player (the partners follow it, see ai.rs)
|
||||||
|
d.phase_t -= dt;
|
||||||
|
if d.phase_t <= 0.0 {
|
||||||
|
d.attacking = !d.attacking;
|
||||||
|
d.phase_t = if d.attacking { ATTACK_FOR } else { HOME_FOR };
|
||||||
|
}
|
||||||
|
d.restock_t -= dt;
|
||||||
|
let restock = d.restock_t <= 0.0;
|
||||||
|
if restock {
|
||||||
|
d.restock_t = RESTOCK_EVERY;
|
||||||
|
}
|
||||||
|
for &(side, _) in MASTERS.iter() {
|
||||||
|
self.switch_to(side);
|
||||||
|
self.core_hp = CORE_HP;
|
||||||
|
if self.gold < self.gold_cap() * 0.4 {
|
||||||
|
let fill = self.gold_cap() * 0.7 - self.gold;
|
||||||
|
self.add_gold(fill.max(0.0));
|
||||||
|
}
|
||||||
|
if side == 0 {
|
||||||
|
self.flag = if d.attacking { Some(rally_tile()) } else { None };
|
||||||
|
}
|
||||||
|
// kinds that died out (or left) come back
|
||||||
|
if restock {
|
||||||
|
for &kind in CREATURES.iter() {
|
||||||
|
if !self.ents.iter().any(|e| e.alive && !e.hero && e.side == side && e.kind == kind) {
|
||||||
|
self.demo_map_creature(side, kind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for r in self.rivals.iter_mut() {
|
||||||
|
r.alive = true;
|
||||||
|
r.hp = crate::rival::RIVAL_CORE_HP;
|
||||||
|
}
|
||||||
|
self.switch_to(back);
|
||||||
|
// heroes of every kind from the gate: half of them guard the plaza, the others march on
|
||||||
|
// the dungeons
|
||||||
|
d.hero_t -= dt;
|
||||||
|
let fighting = self.ents.iter().filter(|e| e.alive && e.active_hero()).count();
|
||||||
|
if d.hero_t <= 0.0 && fighting < MAX_HEROES {
|
||||||
|
d.hero_t = HERO_EVERY;
|
||||||
|
let n = d.next_hero;
|
||||||
|
d.next_hero += 1;
|
||||||
|
d.heroes_sent += 1;
|
||||||
|
let kind = HEROES[n as usize % HEROES.len()];
|
||||||
|
let level = 3 + (n / HEROES.len() as u32) % 6;
|
||||||
|
let (gx, gy) = self.map.gate;
|
||||||
|
let x = gx as f32 + 0.5 + self.rng.f() * 2.0;
|
||||||
|
let y = gy as f32 + 3.2 + self.rng.f() * 0.6;
|
||||||
|
let id = self.spawn(kind, true, x, y, level);
|
||||||
|
let guard = n % 2 == 0 && !crate::siege::siege(kind);
|
||||||
|
let a = self.rng.f() * std::f32::consts::TAU;
|
||||||
|
let r = 2.5 + self.rng.f() * 3.0;
|
||||||
|
let home = (PLAZA.0 as f32 + 0.5 + a.cos() * r, PLAZA.1 as f32 + 0.5 + a.sin() * r);
|
||||||
|
let target = [0u8, 2, 3, 4][(n / 2) as usize % 4];
|
||||||
|
if let Some(e) = self.ents.iter_mut().find(|e| e.id == id) {
|
||||||
|
if guard {
|
||||||
|
e.guard = true;
|
||||||
|
e.home = Some(home);
|
||||||
|
} else if target != 0 {
|
||||||
|
e.target = Some(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.fx(3, gx as f32 + 1.5, gy as f32 + 1.5, 0.0, 0.0, 0.6, 0xffffeecc);
|
||||||
|
}
|
||||||
|
self.demo_map = Some(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn kinds_of(g: &Game, side: u8) -> Vec<EK> {
|
||||||
|
g.ents.iter().filter(|e| e.alive && !e.hero && e.side == side).map(|e| e.kind).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn four_allied_masters_with_every_room_and_creature() {
|
||||||
|
let (mut g, _) = Game::new_demo_map(5);
|
||||||
|
for y in 0..H as i32 {
|
||||||
|
let row: String = (0..W as i32)
|
||||||
|
.map(|x| {
|
||||||
|
let t = g.map.t[idx(x, y)];
|
||||||
|
match t.kind {
|
||||||
|
Kind::Gate => 'G',
|
||||||
|
Kind::Core => 'C',
|
||||||
|
Kind::Portal => 'P',
|
||||||
|
Kind::Gold => '$',
|
||||||
|
Kind::Floor => if t.owner == Owner::None { '.' } else { ',' },
|
||||||
|
k if room_index(k).is_some() => (b'a' + room_index(k).unwrap() as u8) as char,
|
||||||
|
_ if t.solid() => if t.reinforced { '#' } else { ' ' },
|
||||||
|
_ => '?',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
println!("{}", row);
|
||||||
|
}
|
||||||
|
assert_eq!(g.master_sides(), vec![0, 2, 3, 4]);
|
||||||
|
for &(a, _) in MASTERS.iter() {
|
||||||
|
for &(b, _) in MASTERS.iter() {
|
||||||
|
assert!(g.allied(a, b), "{a} and {b} are allies");
|
||||||
|
}
|
||||||
|
assert!(!g.allied(a, 1), "the heroes are the enemy");
|
||||||
|
}
|
||||||
|
for &(side, _) in MASTERS.iter() {
|
||||||
|
g.switch_to(side);
|
||||||
|
g.recount();
|
||||||
|
for (r, &k) in ROOM_KINDS.iter().enumerate() {
|
||||||
|
assert!(g.counts[r] >= 9, "side {side} has a {:?}", k);
|
||||||
|
}
|
||||||
|
assert!(g.portals_owned() > 0, "side {side} has a portal");
|
||||||
|
assert!(g.gold > 1000.0, "side {side} has gold");
|
||||||
|
let have = kinds_of(&g, side);
|
||||||
|
for k in CREATURES.iter().chain([EK::Worker].iter()) {
|
||||||
|
assert!(have.contains(k), "side {side} has a {:?}", k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.switch_to(0);
|
||||||
|
assert!(g.has_gate() && g.gate_hp > 0.0);
|
||||||
|
assert!(g.is_partner(2) && g.is_partner(3) && g.is_partner(4));
|
||||||
|
// every dungeon reaches the gate
|
||||||
|
let gate = rally_tile();
|
||||||
|
for &(_, c) in MASTERS.iter() {
|
||||||
|
assert!(g.map.path_to(idx(c.0 + 2, c.1 + 2), gate).is_some(), "the way from {:?} to the gate", c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn the_gate_never_falls_and_keeps_sending_heroes() {
|
||||||
|
let (mut g, _) = Game::new_demo_map(5);
|
||||||
|
let mut kinds = Vec::new();
|
||||||
|
let mut rallied = false;
|
||||||
|
for k in 0..(20 * 120) {
|
||||||
|
g.update(0.05);
|
||||||
|
if k % (20 * 20) == 0 {
|
||||||
|
let c: Vec<usize> = MASTERS.iter().map(|m| g.ents.iter().filter(|e| e.alive && !e.hero && e.side == m.0).count()).collect();
|
||||||
|
let h = g.ents.iter().filter(|e| e.alive && e.active_hero()).count();
|
||||||
|
let rally = g.ents.iter().filter(|e| e.alive && e.job == Job::Rally).count();
|
||||||
|
println!("{:>3} s: creatures {:?}, heroes {}, rallying {}, gate {}", k / 20, c, h, rally, g.gate_hp);
|
||||||
|
}
|
||||||
|
for e in g.ents.iter().filter(|e| e.alive && e.hero) {
|
||||||
|
if !kinds.contains(&e.kind) {
|
||||||
|
kinds.push(e.kind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rallied |= g.ents.iter().any(|e| e.alive && !e.hero && e.side != 0 && e.job == Job::Rally);
|
||||||
|
assert_eq!(g.state, 0, "the demo map never ends");
|
||||||
|
}
|
||||||
|
let d = g.demo_map.as_ref().unwrap();
|
||||||
|
assert!(d.heroes_sent >= 20, "heroes keep coming: {}", d.heroes_sent);
|
||||||
|
assert!(kinds.len() >= 12, "every kind of hero: {:?}", kinds);
|
||||||
|
assert!(g.gate_hp > 0.0 && g.has_gate());
|
||||||
|
assert_eq!(g.master_sides(), vec![0, 2, 3, 4]);
|
||||||
|
assert!(g.rivals.iter().all(|r| r.alive), "no master falls");
|
||||||
|
assert!(rallied, "the partners' creatures follow the flag to the gate");
|
||||||
|
for &(side, _) in MASTERS.iter() {
|
||||||
|
assert!(g.core_hp_of(side) > 0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -652,6 +652,8 @@ pub struct Game {
|
|||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub demo: Option<crate::demo::Demo>, // the endless bridge battle behind the title menu
|
pub demo: Option<crate::demo::Demo>, // the endless bridge battle behind the title menu
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
pub demo_map: Option<crate::demo_map::DemoMap>, // the debug demo map: four allied masters against an endless gate
|
||||||
|
#[serde(default)]
|
||||||
pub dwarf_caves: Vec<crate::dwarves::DwarfCave>,
|
pub dwarf_caves: Vec<crate::dwarves::DwarfCave>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub bridgework: crate::bridges::BridgeWork, // burning and worn bridges
|
pub bridgework: crate::bridges::BridgeWork, // burning and worn bridges
|
||||||
@@ -1001,6 +1003,7 @@ impl Game {
|
|||||||
springs: 0,
|
springs: 0,
|
||||||
freed: 0,
|
freed: 0,
|
||||||
demo: None,
|
demo: None,
|
||||||
|
demo_map: None,
|
||||||
traps: Vec::new(),
|
traps: Vec::new(),
|
||||||
rollers: Vec::new(),
|
rollers: Vec::new(),
|
||||||
clouds: Vec::new(),
|
clouds: Vec::new(),
|
||||||
@@ -1843,6 +1846,9 @@ impl Game {
|
|||||||
self.update_wood(dt);
|
self.update_wood(dt);
|
||||||
self.update_events(dt);
|
self.update_events(dt);
|
||||||
self.update_traders(dt);
|
self.update_traders(dt);
|
||||||
|
if self.demo_map.is_some() {
|
||||||
|
self.demo_map_tick(dt);
|
||||||
|
}
|
||||||
// fallen hearts of a match are shared state: every client marks them in the same step
|
// fallen hearts of a match are shared state: every client marks them in the same step
|
||||||
self.update_fallen_masters();
|
self.update_fallen_masters();
|
||||||
// the end of the game and the fog are about the master at this computer
|
// the end of the game and the fog are about the master at this computer
|
||||||
|
|||||||
+26
-2
@@ -12,6 +12,7 @@ mod campaign_doc;
|
|||||||
mod cloud;
|
mod cloud;
|
||||||
mod commands;
|
mod commands;
|
||||||
mod demo;
|
mod demo;
|
||||||
|
mod demo_map;
|
||||||
mod editor;
|
mod editor;
|
||||||
mod events;
|
mod events;
|
||||||
mod dwarves;
|
mod dwarves;
|
||||||
@@ -1660,6 +1661,28 @@ app.pending_briefing = briefing_of(&menu.campaign_doc, i);
|
|||||||
ui.show_help = false;
|
ui.show_help = false;
|
||||||
autosave_t = 0.0;
|
autosave_t = 0.0;
|
||||||
}
|
}
|
||||||
|
MenuAction::DemoMap => {
|
||||||
|
// debug: four allied masters with every room and creature against an
|
||||||
|
// endless gate (never autosaved, counts for no achievement)
|
||||||
|
if app.match_mode || app.game.in_match() {
|
||||||
|
app.leave_match();
|
||||||
|
}
|
||||||
|
app.seed = next_seed(app.seed);
|
||||||
|
(app.game, app.cam) = Game::new_demo_map(app.seed);
|
||||||
|
apply_game_settings(&mut app.game, &app.settings);
|
||||||
|
app.coop = false;
|
||||||
|
app.recorded = false;
|
||||||
|
app.tutorial = false;
|
||||||
|
app.custom_campaign = None;
|
||||||
|
app.custom_progress = None;
|
||||||
|
app.custom_mission_index = None;
|
||||||
|
app.custom_next_index = None;
|
||||||
|
menu.page = None;
|
||||||
|
r3d.invalidate();
|
||||||
|
ui.log.clear();
|
||||||
|
ui.show_help = false;
|
||||||
|
autosave_t = 0.0;
|
||||||
|
}
|
||||||
MenuAction::OpenRepo => platform::open_url(menu::REPO_URL),
|
MenuAction::OpenRepo => platform::open_url(menu::REPO_URL),
|
||||||
MenuAction::OpenClaudeCode => platform::open_url(menu::CLAUDE_CODE_URL),
|
MenuAction::OpenClaudeCode => platform::open_url(menu::CLAUDE_CODE_URL),
|
||||||
MenuAction::OpenOpenCode => platform::open_url(menu::OPENCODE_URL),
|
MenuAction::OpenOpenCode => platform::open_url(menu::OPENCODE_URL),
|
||||||
@@ -1700,7 +1723,7 @@ app.pending_briefing = briefing_of(&menu.campaign_doc, i);
|
|||||||
app.tutorial = false;
|
app.tutorial = false;
|
||||||
if app.match_mode || app.game.in_match() {
|
if app.match_mode || app.game.in_match() {
|
||||||
app.leave_match();
|
app.leave_match();
|
||||||
} else if app.game.state == 0 {
|
} else if app.game.state == 0 && app.game.demo_map.is_none() {
|
||||||
platform::storage_set(save::AUTOSAVE_KEY, &app.autosave_json());
|
platform::storage_set(save::AUTOSAVE_KEY, &app.autosave_json());
|
||||||
menu.has_autosave = true;
|
menu.has_autosave = true;
|
||||||
}
|
}
|
||||||
@@ -1980,7 +2003,8 @@ app.pending_briefing = briefing_of(&campaign, i);
|
|||||||
// the world runs in fixed steps: the speed setting only feeds more time into them
|
// the world runs in fixed steps: the speed setting only feeds more time into them
|
||||||
app.game.update(dt * app.settings.game_speed.max(1.0));
|
app.game.update(dt * app.settings.game_speed.max(1.0));
|
||||||
// autosave: snapshot for leaving the tab + regular autosave
|
// autosave: snapshot for leaving the tab + regular autosave
|
||||||
if app.game.state == 0 && !app.match_mode {
|
// (the debug demo map never replaces the autosave)
|
||||||
|
if app.game.state == 0 && !app.match_mode && app.game.demo_map.is_none() {
|
||||||
cache_t += dt;
|
cache_t += dt;
|
||||||
autosave_t += dt;
|
autosave_t += dt;
|
||||||
if cache_t >= AUTOSAVE_CACHE_EVERY {
|
if cache_t >= AUTOSAVE_CACHE_EVERY {
|
||||||
|
|||||||
+14
@@ -252,6 +252,7 @@ enum Btn {
|
|||||||
Start,
|
Start,
|
||||||
Key(usize),
|
Key(usize),
|
||||||
ResetKeys,
|
ResetKeys,
|
||||||
|
DemoMap, // debug tab: start the demo map
|
||||||
SaveNew,
|
SaveNew,
|
||||||
Slot(usize), // load / overwrite
|
Slot(usize), // load / overwrite
|
||||||
Delete(usize),
|
Delete(usize),
|
||||||
@@ -512,6 +513,7 @@ pub enum MenuAction {
|
|||||||
OpenRepo,
|
OpenRepo,
|
||||||
OpenClaudeCode,
|
OpenClaudeCode,
|
||||||
Tutorial, // start the tutorial mission
|
Tutorial, // start the tutorial mission
|
||||||
|
DemoMap, // debug: the demo map with all four masters against an endless gate
|
||||||
BackToEditor,
|
BackToEditor,
|
||||||
OpenOpenCode,
|
OpenOpenCode,
|
||||||
Login(String, String),
|
Login(String, String),
|
||||||
@@ -854,6 +856,10 @@ impl Menu {
|
|||||||
self.page = Some(Page::KeyCapture { action: a, from_title });
|
self.page = Some(Page::KeyCapture { action: a, from_title });
|
||||||
MenuAction::Consumed
|
MenuAction::Consumed
|
||||||
}
|
}
|
||||||
|
Some(Btn::DemoMap) => {
|
||||||
|
self.page = None;
|
||||||
|
MenuAction::DemoMap
|
||||||
|
}
|
||||||
Some(Btn::ResetKeys) => {
|
Some(Btn::ResetKeys) => {
|
||||||
settings.reset_keys();
|
settings.reset_keys();
|
||||||
MenuAction::SettingsChanged
|
MenuAction::SettingsChanged
|
||||||
@@ -1523,6 +1529,14 @@ impl Menu {
|
|||||||
self.buttons.push((right, Btn::Change(i, 1)));
|
self.buttons.push((right, Btn::Change(i, 1)));
|
||||||
self.buttons.push((mid, Btn::Change(i, 1)));
|
self.buttons.push((mid, Btn::Change(i, 1)));
|
||||||
}
|
}
|
||||||
|
if tab == 4 {
|
||||||
|
// the demo map: all four masters with every room and creature against an endless gate
|
||||||
|
let label = tr("set.debug_demo_map");
|
||||||
|
let rw = gfx.measure(&label, S()) + CW() * 4.0;
|
||||||
|
let rr = Rect::new(x + cols as f32 * CW() - rw - CW() * 2.0, y + (rows - 4) as f32 * CH(), rw, CH() * 2.0);
|
||||||
|
button(gfx, rr, &label, rr.contains(vec2(mx, my)), FRAME);
|
||||||
|
self.buttons.push((rr, Btn::DemoMap));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let bw = gfx.measure(&tr("menu.back"), S()) + CW() * 6.0;
|
let bw = gfx.measure(&tr("menu.back"), S()) + CW() * 6.0;
|
||||||
let br = Rect::new(x + CW() * 2.0, y + (rows - 4) as f32 * CH(), bw, CH() * 2.0);
|
let br = Rect::new(x + CW() * 2.0, y + (rows - 4) as f32 * CH(), bw, CH() * 2.0);
|
||||||
|
|||||||
Reference in new issue
Block a user