Room levels 2 and 3, researched in the library: a quarter better each, brighter, with gold trim

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard ZinkandClaude Opus 5.5 committed 2026-11-05 23:44:03 +01:00
1 parent f7b550a6b1
commit 9b49bc2c9d
23 files changed
+171 -10

No files matched your search

+1
View File
@@ -939,6 +939,7 @@ research.now = Zkoumá se: {0} ({1} %)
research.next = pak: {0} research.next = pak: {0}
research.done = Tady už nezbývá nic ke zkoumání. research.done = Tady už nezbývá nic ke zkoumání.
msg.researched = Vyzkoumáno: {0}! Je to teď v nabídce stavby. msg.researched = Vyzkoumáno: {0}! Je to teď v nabídce stavby.
msg.room_upgraded = Výzkum: {0} dosahuje úrovně {1} – funguje o čtvrtinu lépe a je to vidět.
msg.tool_research = Ještě nevyzkoumáno - pracují na tom tvorové studující v knihovně. msg.tool_research = Ještě nevyzkoumáno - pracují na tom tvorové studující v knihovně.
msg.script = {0} msg.script = {0}
+1
View File
@@ -938,6 +938,7 @@ research.now = Forsker i: {0} ({1}%)
research.next = derefter: {0} research.next = derefter: {0}
research.done = Intet mere at forske i her. research.done = Intet mere at forske i her.
msg.researched = Udforsket: {0}! Det findes nu i byggemenuen. msg.researched = Udforsket: {0}! Det findes nu i byggemenuen.
msg.room_upgraded = Forskning: {0} når niveau {1} – virker en fjerdedel bedre, og det kan ses.
msg.tool_research = Endnu ikke udforsket - væsner, der studerer i biblioteket, arbejder på det. msg.tool_research = Endnu ikke udforsket - væsner, der studerer i biblioteket, arbejder på det.
msg.script = {0} msg.script = {0}
+1
View File
@@ -938,6 +938,7 @@ research.now = Erforscht: {0} ({1}%)
research.next = danach: {0} research.next = danach: {0}
research.done = Hier gibt es nichts mehr zu erforschen. research.done = Hier gibt es nichts mehr zu erforschen.
msg.researched = Erforscht: {0}! Jetzt im Baumenü. msg.researched = Erforscht: {0}! Jetzt im Baumenü.
msg.room_upgraded = Forschung: {0} erreicht Stufe {1} – arbeitet ein Viertel besser, und man sieht es.
msg.tool_research = Noch nicht erforscht - Kreaturen in der Bibliothek arbeiten daran. msg.tool_research = Noch nicht erforscht - Kreaturen in der Bibliothek arbeiten daran.
msg.script = {0} msg.script = {0}
+1
View File
@@ -939,6 +939,7 @@ research.now = Έρευνα: {0} ({1}%)
research.next = μετά: {0} research.next = μετά: {0}
research.done = Δεν μένει τίποτα για έρευνα εδώ. research.done = Δεν μένει τίποτα για έρευνα εδώ.
msg.researched = Ερευνήθηκε: {0}! Είναι πλέον στο μενού κατασκευής. msg.researched = Ερευνήθηκε: {0}! Είναι πλέον στο μενού κατασκευής.
msg.room_upgraded = Έρευνα: {0} φτάνει στο επίπεδο {1} – δουλεύει ένα τέταρτο καλύτερα, και φαίνεται.
msg.tool_research = Δεν έχει ερευνηθεί ακόμη - τα πλάσματα που μελετούν στη βιβλιοθήκη δουλεύουν πάνω του. msg.tool_research = Δεν έχει ερευνηθεί ακόμη - τα πλάσματα που μελετούν στη βιβλιοθήκη δουλεύουν πάνω του.
msg.script = {0} msg.script = {0}
+1
View File
@@ -939,6 +939,7 @@ research.now = Researching: {0} ({1}%)
research.next = then: {0} research.next = then: {0}
research.done = Nothing left to research here. research.done = Nothing left to research here.
msg.researched = Researched: {0}! It is in the build menu now. msg.researched = Researched: {0}! It is in the build menu now.
msg.room_upgraded = Research: {0} reaches level {1} – it works a quarter better, and it shows.
msg.tool_research = Not researched yet - creatures studying in the library work on it. msg.tool_research = Not researched yet - creatures studying in the library work on it.
msg.script = {0} msg.script = {0}
+1
View File
@@ -931,6 +931,7 @@ research.now = Investigando: {0} ({1}%)
research.next = después: {0} research.next = después: {0}
research.done = Aquí no queda nada por investigar. research.done = Aquí no queda nada por investigar.
msg.researched = Investigado: ¡{0}! Ya está en el menú de construcción. msg.researched = Investigado: ¡{0}! Ya está en el menú de construcción.
msg.room_upgraded = Investigación: {0} alcanza el nivel {1}: funciona un cuarto mejor, y se nota.
msg.tool_research = Aún no investigado: las criaturas que estudian en la biblioteca trabajan en ello. msg.tool_research = Aún no investigado: las criaturas que estudian en la biblioteca trabajan en ello.
msg.script = {0} msg.script = {0}
+1
View File
@@ -939,6 +939,7 @@ research.now = Tutkitaan: {0} ({1}%)
research.next = sitten: {0} research.next = sitten: {0}
research.done = Täällä ei ole enää mitään tutkittavaa. research.done = Täällä ei ole enää mitään tutkittavaa.
msg.researched = Tutkittu: {0}! Se on nyt rakennusvalikossa. msg.researched = Tutkittu: {0}! Se on nyt rakennusvalikossa.
msg.room_upgraded = Tutkimus: {0} saavuttaa tason {1} – toimii neljänneksen paremmin, ja sen näkee.
msg.tool_research = Ei vielä tutkittu - kirjastossa opiskelevat olennot työstävät sitä. msg.tool_research = Ei vielä tutkittu - kirjastossa opiskelevat olennot työstävät sitä.
msg.script = {0} msg.script = {0}
+1
View File
@@ -939,6 +939,7 @@ research.now = Istražuje se: {0} ({1}%)
research.next = zatim: {0} research.next = zatim: {0}
research.done = Ovdje više nema što istraživati. research.done = Ovdje više nema što istraživati.
msg.researched = Istraženo: {0}! Sad je u izborniku gradnje. msg.researched = Istraženo: {0}! Sad je u izborniku gradnje.
msg.room_upgraded = Istraživanje: {0} doseže razinu {1} – radi četvrtinu bolje, i to se vidi.
msg.tool_research = Još nije istraženo - stvorenja koja uče u knjižnici rade na tome. msg.tool_research = Još nije istraženo - stvorenja koja uče u knjižnici rade na tome.
msg.script = {0} msg.script = {0}
+1
View File
@@ -939,6 +939,7 @@ research.now = Kutatás: {0} ({1}%)
research.next = utána: {0} research.next = utána: {0}
research.done = Itt már nincs mit kutatni. research.done = Itt már nincs mit kutatni.
msg.researched = Kikutatva: {0}! Már az építési menüben van. msg.researched = Kikutatva: {0}! Már az építési menüben van.
msg.room_upgraded = Kutatás: {0} eléri a(z) {1}. szintet – negyedével jobban működik, és látszik is.
msg.tool_research = Még nincs kikutatva - a könyvtárban tanuló lények dolgoznak rajta. msg.tool_research = Még nincs kikutatva - a könyvtárban tanuló lények dolgoznak rajta.
msg.script = {0} msg.script = {0}
+1
View File
@@ -931,6 +931,7 @@ research.now = In ricerca: {0} ({1}%)
research.next = poi: {0} research.next = poi: {0}
research.done = Qui non resta niente da ricercare. research.done = Qui non resta niente da ricercare.
msg.researched = Ricerca completata: {0}! Ora è nel menu di costruzione. msg.researched = Ricerca completata: {0}! Ora è nel menu di costruzione.
msg.room_upgraded = Ricerca: {0} raggiunge il livello {1}: funziona un quarto meglio, e si vede.
msg.tool_research = Non ancora ricercato - ci lavorano le creature che studiano in biblioteca. msg.tool_research = Non ancora ricercato - ci lavorano le creature che studiano in biblioteca.
msg.script = {0} msg.script = {0}
+1
View File
@@ -939,6 +939,7 @@ research.now = Onderzoekt: {0} ({1}%)
research.next = daarna: {0} research.next = daarna: {0}
research.done = Hier valt niets meer te onderzoeken. research.done = Hier valt niets meer te onderzoeken.
msg.researched = Onderzocht: {0}! Het staat nu in het bouwmenu. msg.researched = Onderzocht: {0}! Het staat nu in het bouwmenu.
msg.room_upgraded = Onderzoek: {0} bereikt niveau {1} – werkt een kwart beter, en dat zie je.
msg.tool_research = Nog niet onderzocht - wezens die in de bibliotheek studeren, werken eraan. msg.tool_research = Nog niet onderzocht - wezens die in de bibliotheek studeren, werken eraan.
msg.script = {0} msg.script = {0}
+1
View File
@@ -938,6 +938,7 @@ research.now = Forsker på: {0} ({1}%)
research.next = deretter: {0} research.next = deretter: {0}
research.done = Ingenting mer å forske på her. research.done = Ingenting mer å forske på her.
msg.researched = Utforsket: {0}! Det finnes nå i byggemenyen. msg.researched = Utforsket: {0}! Det finnes nå i byggemenyen.
msg.room_upgraded = Forskning: {0} når nivå {1} – virker en fjerdedel bedre, og det synes.
msg.tool_research = Ikke utforsket ennå - skapninger som studerer i biblioteket, jobber med det. msg.tool_research = Ikke utforsket ennå - skapninger som studerer i biblioteket, jobber med det.
msg.script = {0} msg.script = {0}
+1
View File
@@ -939,6 +939,7 @@ research.now = A investigar: {0} ({1}%)
research.next = depois: {0} research.next = depois: {0}
research.done = Já não há nada para investigar aqui. research.done = Já não há nada para investigar aqui.
msg.researched = Investigado: {0}! Já está no menu de construção. msg.researched = Investigado: {0}! Já está no menu de construção.
msg.room_upgraded = Investigação: {0} atinge o nível {1} – funciona um quarto melhor, e nota-se.
msg.tool_research = Ainda não investigado - as criaturas que estudam na biblioteca estão a tratar disso. msg.tool_research = Ainda não investigado - as criaturas que estudam na biblioteca estão a tratar disso.
msg.script = {0} msg.script = {0}
+1
View File
@@ -939,6 +939,7 @@ research.now = Se cercetează: {0} ({1}%)
research.next = apoi: {0} research.next = apoi: {0}
research.done = Nu mai e nimic de cercetat aici. research.done = Nu mai e nimic de cercetat aici.
msg.researched = Cercetat: {0}! E acum în meniul de construcție. msg.researched = Cercetat: {0}! E acum în meniul de construcție.
msg.room_upgraded = Cercetare: {0} atinge nivelul {1} – funcționează cu un sfert mai bine, și se vede.
msg.tool_research = Încă necercetat - creaturile care studiază în bibliotecă lucrează la asta. msg.tool_research = Încă necercetat - creaturile care studiază în bibliotecă lucrează la asta.
msg.script = {0} msg.script = {0}
+1
View File
@@ -931,6 +931,7 @@ research.now = Исследуется: {0} ({1}%)
research.next = затем: {0} research.next = затем: {0}
research.done = Здесь больше нечего исследовать. research.done = Здесь больше нечего исследовать.
msg.researched = Исследовано: {0}! Теперь это в меню строительства. msg.researched = Исследовано: {0}! Теперь это в меню строительства.
msg.room_upgraded = Исследование: {0} достигает уровня {1} — работает на четверть лучше, и это видно.
msg.tool_research = Ещё не исследовано - над этим работают существа, что учатся в библиотеке. msg.tool_research = Ещё не исследовано - над этим работают существа, что учатся в библиотеке.
msg.script = {0} msg.script = {0}
+1
View File
@@ -939,6 +939,7 @@ research.now = Skúma sa: {0} ({1} %)
research.next = potom: {0} research.next = potom: {0}
research.done = Tu už nezostáva nič na skúmanie. research.done = Tu už nezostáva nič na skúmanie.
msg.researched = Preskúmané: {0}! Je to teraz v ponuke stavby. msg.researched = Preskúmané: {0}! Je to teraz v ponuke stavby.
msg.room_upgraded = Výskum: {0} dosahuje úroveň {1} – funguje o štvrtinu lepšie a je to vidieť.
msg.tool_research = Ešte nepreskúmané - pracujú na tom tvory študujúce v knižnici. msg.tool_research = Ešte nepreskúmané - pracujú na tom tvory študujúce v knižnici.
msg.script = {0} msg.script = {0}
+1
View File
@@ -939,6 +939,7 @@ research.now = Истражује се: {0} ({1}%)
research.next = затим: {0} research.next = затим: {0}
research.done = Овде више нема шта да се истражи. research.done = Овде више нема шта да се истражи.
msg.researched = Истражено: {0}! Сад је у менију градње. msg.researched = Истражено: {0}! Сад је у менију градње.
msg.room_upgraded = Истраживање: {0} достиже ниво {1} – ради четвртину боље, и то се види.
msg.tool_research = Још није истражено - створења која уче у библиотеци раде на томе. msg.tool_research = Још није истражено - створења која уче у библиотеци раде на томе.
msg.script = {0} msg.script = {0}
+1
View File
@@ -939,6 +939,7 @@ research.now = Forskar: {0} ({1}%)
research.next = sedan: {0} research.next = sedan: {0}
research.done = Inget kvar att forska på här. research.done = Inget kvar att forska på här.
msg.researched = Utforskat: {0}! Det finns nu i byggmenyn. msg.researched = Utforskat: {0}! Det finns nu i byggmenyn.
msg.room_upgraded = Forskning: {0} når nivå {1} – fungerar en fjärdedel bättre, och det syns.
msg.tool_research = Inte utforskat än - varelser som studerar i biblioteket arbetar på det. msg.tool_research = Inte utforskat än - varelser som studerar i biblioteket arbetar på det.
msg.script = {0} msg.script = {0}
+35 -8
View File
@@ -486,6 +486,7 @@ pub struct MasterState {
pub incoming: Vec<(u8, f32, Option<usize>)>, pub incoming: Vec<(u8, f32, Option<usize>)>,
pub training_bill: f32, pub training_bill: f32,
pub counts: [usize; N_ROOMS], pub counts: [usize; N_ROOMS],
pub room_level: Vec<u8>,
pub springs: usize, pub springs: usize,
pub known: Vec<bool>, pub known: Vec<bool>,
pub researchable: Vec<bool>, pub researchable: Vec<bool>,
@@ -522,6 +523,8 @@ pub struct Game {
pub hand: Vec<u32>, pub hand: Vec<u32>,
#[serde(skip)] #[serde(skip)]
pub counts: [usize; N_ROOMS], // room tiles per room kind (ROOM_KINDS order, recounted) pub counts: [usize; N_ROOMS], // room tiles per room kind (ROOM_KINDS order, recounted)
#[serde(default)]
pub room_level: Vec<u8>, // level of every room kind (ROOM_KINDS order; 1 when missing), researched
pub gate_hp: f32, pub gate_hp: f32,
pub gate_hit_t: f32, pub gate_hit_t: f32,
pub gate_stage: u32, // defender thresholds triggered (0..3) pub gate_stage: u32, // defender thresholds triggered (0..3)
@@ -783,6 +786,18 @@ pub fn room_index(k: Kind) -> Option<usize> {
ROOM_KINDS.iter().position(|&r| r == k) ROOM_KINDS.iter().position(|&r| r == k)
} }
impl Game {
// the researched level of a room kind of the master being processed (1, 2 or 3)
pub fn room_level_of(&self, k: Kind) -> u8 {
room_index(k).and_then(|r| self.room_level.get(r).copied()).unwrap_or(1).max(1)
}
// how much better a room works at its level: +25% per level above the first
pub fn room_bonus(&self, k: Kind) -> f32 {
1.0 + 0.25 * (self.room_level_of(k) - 1) as f32
}
}
pub(crate) fn adj4(a: usize, b: usize) -> bool { pub(crate) fn adj4(a: usize, b: usize) -> bool {
let (ax, ay) = xy(a); let (ax, ay) = xy(a);
let (bx, by) = xy(b); let (bx, by) = xy(b);
@@ -866,6 +881,7 @@ impl Game {
paused: false, paused: false,
hand: Vec::new(), hand: Vec::new(),
counts: [0; N_ROOMS], counts: [0; N_ROOMS],
room_level: Vec::new(),
gate_hp: GATE_HP, gate_hp: GATE_HP,
gate_hit_t: -100.0, gate_hit_t: -100.0,
gate_stage: 0, gate_stage: 0,
@@ -1126,7 +1142,7 @@ impl Game {
} }
pub fn gold_cap(&self) -> f32 { pub fn gold_cap(&self) -> f32 {
CORE_STORE + TREASURY_TILE * self.counts[0] as f32 CORE_STORE + TREASURY_TILE * self.counts[0] as f32 * self.room_bonus(Kind::Treasury)
} }
pub fn add_gold(&mut self, amount: f32) -> f32 { pub fn add_gold(&mut self, amount: f32) -> f32 {
@@ -1433,6 +1449,7 @@ impl Game {
incoming: std::mem::take(&mut self.incoming), incoming: std::mem::take(&mut self.incoming),
training_bill: self.training_bill, training_bill: self.training_bill,
counts: self.counts, counts: self.counts,
room_level: self.room_level.clone(),
springs: self.springs, springs: self.springs,
known: std::mem::take(&mut self.known), known: std::mem::take(&mut self.known),
researchable: std::mem::take(&mut self.researchable), researchable: std::mem::take(&mut self.researchable),
@@ -1463,6 +1480,7 @@ impl Game {
self.incoming = m.incoming; self.incoming = m.incoming;
self.training_bill = m.training_bill; self.training_bill = m.training_bill;
self.counts = m.counts; self.counts = m.counts;
self.room_level = m.room_level;
self.springs = m.springs; self.springs = m.springs;
self.known = m.known; self.known = m.known;
self.researchable = m.researchable; self.researchable = m.researchable;
@@ -1606,9 +1624,17 @@ impl Game {
return; return;
} }
self.time += dt; self.time += dt;
// mushroom gardens grow faster at a higher level (of the master who owns them)
let farm = Kind::Farm;
let lv: Vec<(Owner, f32)> = self.master_sides().into_iter().map(|s| (Owner::of_side(s), {
let r = room_index(farm).unwrap_or(0);
let l = if s == self.me_side { self.room_level.get(r).copied() } else { self.masters.iter().find(|m| m.side == s).and_then(|m| m.room_level.get(r).copied()) };
1.0 + 0.25 * (l.unwrap_or(1).max(1) - 1) as f32
})).collect();
for t in self.map.t.iter_mut() { for t in self.map.t.iter_mut() {
if t.kind == Kind::Farm { if t.kind == Kind::Farm {
t.food = (t.food + dt / 18.0).min(3.0); let f = lv.iter().find(|x| x.0 == t.owner).map_or(1.0, |x| x.1);
t.food = (t.food + dt * f / 18.0).min(3.0);
} }
} }
for side in self.master_sides() { for side in self.master_sides() {
@@ -3798,8 +3824,9 @@ impl Game {
} }
// resting heals: quickly in a bed room, slower next to the core; back to work at 75% // resting heals: quickly in a bed room, slower next to the core; back to work at 75%
let bed_room = matches!(self.map.t[b].kind, Kind::Lair | Kind::Aerie); let bed_room = matches!(self.map.t[b].kind, Kind::Lair | Kind::Aerie);
e.hp = (e.hp + e.max_hp * dt / if bed_room { 12.0 } else { 24.0 }).min(e.max_hp); let rest = if bed_room { self.room_bonus(self.map.t[b].kind) } else { 1.0 };
e.energy = (e.energy + dt / 14.0).min(1.0); e.hp = (e.hp + e.max_hp * dt * rest / if bed_room { 12.0 } else { 24.0 }).min(e.max_hp);
e.energy = (e.energy + dt * rest / 14.0).min(1.0);
if e.hp >= e.max_hp * 0.75 { if e.hp >= e.max_hp * 0.75 {
e.job = Job::None; e.job = Job::None;
} }
@@ -3857,7 +3884,7 @@ impl Game {
if tl.food >= 1.0 { if tl.food >= 1.0 {
tl.food -= 1.0; tl.food -= 1.0;
e.hunger = 0.0; e.hunger = 0.0;
e.hp = (e.hp + e.max_hp * 0.2).min(e.max_hp); e.hp = (e.hp + e.max_hp * 0.2 * self.room_bonus(Kind::Temple)).min(e.max_hp);
} }
self.unreserve(me); self.unreserve(me);
e.job = Job::None; e.job = Job::None;
@@ -3887,7 +3914,7 @@ impl Game {
} }
e.working = true; e.working = true;
self.training_bill += TRAIN_COST * dt; self.training_bill += TRAIN_COST * dt;
e.xp += 7.0 * dt; e.xp += 7.0 * dt * self.room_bonus(Kind::Training);
e.timer -= dt; e.timer -= dt;
if e.timer <= 0.0 { if e.timer <= 0.0 {
self.unreserve(me); self.unreserve(me);
@@ -3916,7 +3943,7 @@ impl Game {
} }
e.working = true; e.working = true;
let rate = if e.kind == EK::Cogling { 2.5 } else { 1.0 } * (1.0 + 0.1 * (e.level - 1) as f32); let rate = if e.kind == EK::Cogling { 2.5 } else { 1.0 } * (1.0 + 0.1 * (e.level - 1) as f32);
self.forge_work += rate * dt; self.forge_work += rate * dt * self.room_bonus(Kind::Forge);
e.xp += 2.5 * dt; e.xp += 2.5 * dt;
e.timer -= dt; e.timer -= dt;
if e.timer <= 0.0 { if e.timer <= 0.0 {
@@ -3939,7 +3966,7 @@ impl Game {
EK::Owl => 1.3, EK::Owl => 1.3,
_ => 0.5, _ => 0.5,
} * (1.0 + 0.12 * (e.level - 1) as f32); } * (1.0 + 0.12 * (e.level - 1) as f32);
self.add_research(points * dt); self.add_research(points * dt * self.room_bonus(Kind::Library));
e.xp += 3.0 * dt; e.xp += 3.0 * dt;
e.timer -= dt; e.timer -= dt;
if e.timer <= 0.0 { if e.timer <= 0.0 {
+3 -1
View File
@@ -352,6 +352,8 @@ pub struct Map {
pub visible: Vec<bool>, // fog of war: tiles in sight right now pub visible: Vec<bool>, // fog of war: tiles in sight right now
#[serde(default, with = "crate::fog::bits")] #[serde(default, with = "crate::fog::bits")]
pub sky: Vec<bool>, // tiles above ground (daylight, grass); empty: all underground pub sky: Vec<bool>, // tiles above ground (daylight, grass); empty: all underground
#[serde(default)]
pub upgrades: Vec<(u8, u8, u8)>, // researched room levels for the look: (master side, room index, level)
} }
fn default_size() -> usize { fn default_size() -> usize {
@@ -604,7 +606,7 @@ impl Map {
tl.hp = 6.0; tl.hp = 6.0;
} }
} }
Map { w, h, t, core, portals, legacy_portal: None, gate, treasures, explored: Vec::new(), visible: Vec::new(), sky: Vec::new() } Map { w, h, t, core, portals, legacy_portal: None, gate, treasures, explored: Vec::new(), visible: Vec::new(), sky: Vec::new(), upgrades: Vec::new() }
} }
// Carves a meandering river; the player's area, the core and portals stay dry. // Carves a meandering river; the player's area, the core and portals stay dry.
+38
View File
@@ -440,6 +440,15 @@ impl MB {
} }
} }
// the researched level of the room on tile t (1: none)
fn room_level_at(map: &Map, t: &Tile) -> u8 {
if map.upgrades.is_empty() {
return 1;
}
let (Some(r), side) = (room_index(t.kind), t.owner.side()) else { return 1 };
map.upgrades.iter().find(|u| u.0 == side && u.1 as usize == r).map_or(1, |u| u.2)
}
// Ambient light field: own territory is lit, foreign areas are dim // Ambient light field: own territory is lit, foreign areas are dim
fn ambient_field(map: &Map) -> Vec<f32> { fn ambient_field(map: &Map) -> Vec<f32> {
let mut f = vec![0.0f32; n()]; let mut f = vec![0.0f32; n()];
@@ -453,6 +462,11 @@ fn ambient_field(map: &Map) -> Vec<f32> {
if map.sky(i) { if map.sky(i) {
f[i] = 1.6; f[i] = 1.6;
} }
// rooms of a higher level shine brighter
let lv = room_level_at(map, t);
if lv > 1 && f[i] > 0.0 {
f[i] += 0.25 * (lv - 1) as f32;
}
if t.river() == Some(Kind::Lava) { if t.river() == Some(Kind::Lava) {
f[i] = f[i].max(0.8); // lava lights up its surroundings f[i] = f[i].max(0.8); // lava lights up its surroundings
} }
@@ -853,6 +867,26 @@ fn build_chunk(map: &Map, amb: &[f32], glow: &[f32], cx: i32, cz: i32, atlas: &T
if !solid_at(map, x - 1, z) && !outdoors { if !solid_at(map, x - 1, z) && !outdoors {
ln.strip(vec3(xf, 0.0, zf), vec3(xf, 0.0, zf + 1.0), Vec3::Y, OUTLINE_W, OUTLINE_C); ln.strip(vec3(xf, 0.0, zf), vec3(xf, 0.0, zf + 1.0), Vec3::Y, OUTLINE_W, OUTLINE_C);
} }
// a room of a higher level: gold trim along its border (twice at level 3)
let lv = room_level_at(map, &t);
if lv > 1 {
let gold = col(vec3(1.0, 0.78, 0.25), 1.0);
for (d, &(dx, dz)) in DIR4.iter().enumerate() {
if map.get(x + dx, z + dz).map_or(false, |o| o.kind == t.kind && o.owner == t.owner) {
continue;
}
for k in 0..(lv - 1) {
let m = 0.08 + 0.12 * k as f32;
let (p, q) = match d {
0 => (vec3(xf + m, 0.012, zf + m), vec3(xf + 1.0 - m, 0.012, zf + m)),
1 => (vec3(xf + 1.0 - m, 0.012, zf + m), vec3(xf + 1.0 - m, 0.012, zf + 1.0 - m)),
2 => (vec3(xf + 1.0 - m, 0.012, zf + 1.0 - m), vec3(xf + m, 0.012, zf + 1.0 - m)),
_ => (vec3(xf + m, 0.012, zf + 1.0 - m), vec3(xf + m, 0.012, zf + m)),
};
ln.strip(p, q, Vec3::Y, OUTLINE_W * 1.5, gold);
}
}
}
// room decor // room decor
let dc = col(lava_lit(Vec3::splat(amb_at(amb, xf + 0.5, zf + 0.5)), lava_at(glow, xf + 0.5, zf + 0.5)), 1.0); let dc = col(lava_lit(Vec3::splat(amb_at(amb, xf + 0.5, zf + 0.5)), lava_at(glow, xf + 0.5, zf + 0.5)), 1.0);
if t.plant() { if t.plant() {
@@ -1083,6 +1117,10 @@ fn rgba(u: u32) -> Color {
fn chunk_sig(map: &Map, cx: i32, cz: i32) -> u64 { fn chunk_sig(map: &Map, cx: i32, cz: i32) -> u64 {
let mut h: u64 = 1469598103934665603; let mut h: u64 = 1469598103934665603;
// researched room levels change the light and the trim of every room
for u in &map.upgrades {
h = (h ^ (u.0 as u64 | (u.1 as u64) << 8 | (u.2 as u64) << 16)).wrapping_mul(1099511628211);
}
for z in cz * CHUNK - 3..(cz + 1) * CHUNK + 3 { for z in cz * CHUNK - 3..(cz + 1) * CHUNK + 3 {
for x in cx * CHUNK - 3..(cx + 1) * CHUNK + 3 { for x in cx * CHUNK - 3..(cx + 1) * CHUNK + 3 {
let v = match map.get(x, z) { let v = match map.get(x, z) {
+72 -1
View File
@@ -46,6 +46,26 @@ pub const RESEARCH: &[(usize, f32)] = &[
(51, 1000.0), // catapult (51, 1000.0), // catapult
]; ];
// room levels, researched once everything else is known: (index in ROOM_KINDS, level, points)
pub const UPGRADES: &[(usize, u8, f32)] = &[
(1, 2, 500.0), // lair
(2, 2, 500.0), // mushroom garden
(0, 2, 550.0), // treasury
(4, 2, 600.0), // library
(3, 2, 600.0), // training hall
(8, 2, 650.0), // forge
(6, 2, 650.0), // temple
(7, 2, 650.0), // aerie
(1, 3, 1000.0), // lair
(2, 3, 1000.0), // mushroom garden
(0, 3, 1100.0), // treasury
(4, 3, 1200.0), // library
(3, 3, 1200.0), // training hall
(8, 3, 1300.0), // forge
(6, 3, 1300.0), // temple
(7, 3, 1300.0), // aerie
];
// known from the start in free play // known from the start in free play
pub const BASE_TOOLS: &[usize] = &[0, 1, 2, 3, 4, 6, 7, 8, 9, 14, 17, 20, 45, 46, 49]; pub const BASE_TOOLS: &[usize] = &[0, 1, 2, 3, 4, 6, 7, 8, 9, 14, 17, 20, 45, 46, 49];
@@ -92,13 +112,45 @@ impl Game {
!self.known(tool) && self.researchable.get(tool).copied().unwrap_or(false) && RESEARCH.iter().any(|&(t, _)| t == tool) !self.known(tool) && self.researchable.get(tool).copied().unwrap_or(false) && RESEARCH.iter().any(|&(t, _)| t == tool)
} }
// the room level being researched once no tool is left: index in UPGRADES
pub fn upgrade_target(&self) -> Option<usize> {
if self.research_target().is_some() || self.known.is_empty() {
return None;
}
UPGRADES.iter().position(|&(r, lv, _)| self.room_level.get(r).copied().unwrap_or(1).max(1) < lv)
}
pub(crate) fn add_research(&mut self, points: f32) { pub(crate) fn add_research(&mut self, points: f32) {
if self.research_target().is_some() { if self.research_target().is_some() || self.upgrade_target().is_some() {
self.research += points; self.research += points;
} }
} }
// a room kind reached level `lv` (the map keeps it for the look of the rooms)
pub fn set_room_level(&mut self, r: usize, lv: u8) {
if self.room_level.len() < crate::game::N_ROOMS {
self.room_level.resize(crate::game::N_ROOMS, 1);
}
self.room_level[r] = lv;
let side = self.me_side;
self.map.upgrades.retain(|u| !(u.0 == side && u.1 as usize == r));
if lv > 1 {
self.map.upgrades.push((side, r as u8, lv));
}
}
pub(crate) fn update_research(&mut self) { pub(crate) fn update_research(&mut self) {
if let Some(u) = self.upgrade_target() {
let (r, lv, cost) = UPGRADES[u];
if self.research >= cost {
self.research -= cost;
self.set_room_level(r, lv);
let roman = if lv == 2 { "II" } else { "III" };
self.msg("msg.room_upgraded", vec![format!("@{}", crate::game::ROOM_NAMES[r]), roman.to_string()]);
self.sfx_ui(Sfx::LevelUp);
}
return;
}
let Some(k) = self.research_target() else { return }; let Some(k) = self.research_target() else { return };
let (tool, cost) = RESEARCH[k]; let (tool, cost) = RESEARCH[k];
if self.research >= cost { if self.research >= cost {
@@ -154,4 +206,23 @@ mod tests {
assert!(g.can_research(10), "heal comes soon and can be researched"); assert!(g.can_research(10), "heal comes soon and can be researched");
assert!(!g.can_research(31), "magic doors are far away"); assert!(!g.can_research(31), "magic doors are far away");
} }
#[test]
fn once_everything_is_known_the_library_raises_room_levels() {
let mut g = Game::new(9, 64, 64);
assert!(g.upgrade_target().is_none(), "tools first");
for v in g.known.iter_mut() {
*v = true;
}
let u = g.upgrade_target().expect("a room level to research");
let (r, lv, cost) = UPGRADES[u];
assert_eq!(lv, 2);
let before = g.room_bonus(ROOM_KINDS[r]);
g.research = cost + 1.0;
g.update_research();
assert_eq!(g.room_level_of(ROOM_KINDS[r]), 2);
assert!(g.room_bonus(ROOM_KINDS[r]) > before);
assert!(g.map.upgrades.iter().any(|x| x.1 as usize == r && x.2 == 2), "the map shows it");
assert_ne!(g.upgrade_target(), Some(u), "the next one");
}
} }
+5
View File
@@ -667,6 +667,11 @@ impl Ui {
let (tool, cost) = crate::research::RESEARCH[k]; let (tool, cost) = crate::research::RESEARCH[k];
let name: String = tool_info(TOOLS[tool]).name.chars().take(18).collect(); let name: String = tool_info(TOOLS[tool]).name.chars().take(18).collect();
segs.push(vec![txt(tr("hud.research"), BLUE), Part::Gap, txt(name, TXT), Part::Gap, Part::Bar(g.research / cost, BLUE)]); segs.push(vec![txt(tr("hud.research"), BLUE), Part::Gap, txt(name, TXT), Part::Gap, Part::Bar(g.research / cost, BLUE)]);
} else if let Some(u) = g.upgrade_target().filter(|_| g.counts[4] > 0) {
// everything known: the library works on room levels
let (r, lv, cost) = crate::research::UPGRADES[u];
let name: String = format!("{} {}", tr(ROOM_NAMES[r]), if lv == 2 { "II" } else { "III" }).chars().take(20).collect();
segs.push(vec![txt(tr("hud.research"), BLUE), Part::Gap, txt(name, TXT), Part::Gap, Part::Bar(g.research / cost, BLUE)]);
} }
segs.push(vec![txt(tr("hud.payday"), if g.payday <= PAYDAY_WARN { RED } else { GOLD }), Part::Gap, txt(mmss(g.payday), TXT)]); segs.push(vec![txt(tr("hud.payday"), if g.payday <= PAYDAY_WARN { RED } else { GOLD }), Part::Gap, txt(mmss(g.payday), TXT)]);
segs.push(vec![txt(tr("hud.army"), TXT), Part::Gap, txt((g.army_value() as i32).to_string(), TXT)]); segs.push(vec![txt(tr("hud.army"), TXT), Part::Gap, txt((g.army_value() as i32).to_string(), TXT)]);