Research in the library: rooms, spells, towers, traps and doors are discovered in a fixed order

- studying creatures collect research points (mages and owls best, higher levels faster); studying gives less mana than before
- free play starts with the basics; campaign missions know what their story allows and can research what the next four missions would bring
- research shown in the top bar; the library's info lists the current item and what comes next; locked tools say whether they can be researched

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard ZinkandClaude Opus 5.5 committed 2026-11-04 07:00:33 +01:00
1 parent 4f20223c93
commit a54316c86e
8 files changed
+210 -3

No files matched your search

+27 -1
View File
@@ -327,6 +327,7 @@ pub struct Ui {
minimap_tex: Texture2D,
minimap_t: f64,
minimap_rect: Rect,
pub last_locked: Option<usize>, // the locked tool clicked last
end_buttons: Vec<(Rect, u8)>,
goals_rect: Rect, // mission goals panel (click: briefing) // end dialog: 0 new game, 1 next/again, 2 campaign
lang_rects: Vec<(Rect, String)>,
@@ -378,6 +379,7 @@ impl Ui {
minimap_tex: tex,
minimap_t: -1.0,
minimap_rect: Rect::new(0.0, 0.0, 0.0, 0.0),
last_locked: None,
end_buttons: Vec::new(),
goals_rect: Rect::new(0.0, 0.0, 0.0, 0.0),
lang_rects: Vec::new(),
@@ -433,7 +435,10 @@ impl Ui {
self.open_cat = None;
UiAction::OpenMenu
}
TBtn::Tool(i) if !g.tool_allowed(i) => UiAction::Locked,
TBtn::Tool(i) if !g.tool_allowed(i) => {
self.last_locked = Some(i);
UiAction::Locked
}
TBtn::Tool(i) => {
self.open_cat = None;
self.tip = Some((i, get_time()));
@@ -442,6 +447,7 @@ impl Ui {
TBtn::Cat(c) => {
let tools = CATS[c].1;
if tools.len() == 1 && !g.tool_allowed(tools[0]) {
self.last_locked = Some(tools[0]);
UiAction::Locked
} else if tools.len() == 1 {
self.open_cat = None;
@@ -518,6 +524,11 @@ impl Ui {
let left = (limit - g.time).max(0.0);
segs.insert(0, vec![txt(tr("hud.time_left"), if left < 120.0 { RED } else { GOLD }), Part::Gap, txt(mmss(left), TXT)]);
}
if let Some(k) = g.research_target().filter(|_| g.counts[4] > 0) {
let (tool, cost) = crate::research::RESEARCH[k];
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.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)]);
if !g.hand.is_empty() {
@@ -1215,6 +1226,21 @@ pub fn hover_info(g: &Game, ent: Option<usize>, tile: Option<(i32, i32)>) -> Vec
out.push((tr(ROOM_NAMES[r]), FRAME_HI));
match k {
Kind::Farm => out.push((trf("farm.food", &[(t.food as i32).to_string()]), GREEN)),
Kind::Library => {
let q = g.research_queue(4);
if q.is_empty() {
out.push((tr("research.done"), DIM));
}
for (n, k) in q.iter().enumerate() {
let (tool, cost) = crate::research::RESEARCH[*k];
let name = tool_info(TOOLS[tool]).name;
if n == 0 {
out.push((trf("research.now", &[name, ((g.research / cost * 100.0).min(99.0) as i32).to_string()]), BLUE));
} else {
out.push((trf("research.next", &[name]), DIM));
}
}
}
Kind::Treasury if t.gold > 0 => {
let what = ["res.gold", "res.silver", "res.ruby", "res.diamond"][(t.res & 3) as usize];
out.push((trf("treasury.content", &[t.gold.to_string(), tr(what)]), GOLD));