Versus teams, gold for allies, fallen hearts as spectators, multi-mission editor co-op
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
811c955bad
commit
fc9c49d4ca
16 files changed
+1896
-49
No files matched your search
@@ -346,6 +346,8 @@ enum TBtn {
|
||||
Overview,
|
||||
OvRow(u32),
|
||||
OvScroll(i32),
|
||||
GoldTo, // the next ally to receive gold
|
||||
Gold(u32), // send that much gold to him
|
||||
}
|
||||
|
||||
pub enum UiAction {
|
||||
@@ -362,6 +364,7 @@ pub enum UiAction {
|
||||
SelectLanguage(String),
|
||||
ChatSetTeam(bool),
|
||||
ChatSend,
|
||||
SendGold(u8, u32), // gold for an ally of a match (side, amount)
|
||||
Consumed,
|
||||
}
|
||||
|
||||
@@ -369,6 +372,8 @@ pub struct Ui {
|
||||
pub tool: Tool,
|
||||
pub show_help: bool,
|
||||
pub show_overview: bool, // list of all creatures
|
||||
pub coop_end: Option<(bool, bool, bool)>, // end of an editor co-op mission: (host, a next mission, asked for it)
|
||||
gold_to: usize, // the ally chosen in the creature overview
|
||||
ov_scroll: usize,
|
||||
ov_rect: Option<Rect>, // where the creature overview is (mouse wheel, swipe)
|
||||
pub show_langsel: bool,
|
||||
@@ -431,6 +436,8 @@ impl Ui {
|
||||
tool: Tool::Dig,
|
||||
show_help: true,
|
||||
show_overview: false,
|
||||
coop_end: None,
|
||||
gold_to: 0,
|
||||
ov_scroll: 0,
|
||||
ov_rect: None,
|
||||
show_langsel: false,
|
||||
@@ -527,6 +534,17 @@ impl Ui {
|
||||
self.ov_scroll = (self.ov_scroll as i32 + d).max(0) as usize;
|
||||
UiAction::Consumed
|
||||
}
|
||||
TBtn::GoldTo => {
|
||||
self.gold_to += 1;
|
||||
UiAction::Consumed
|
||||
}
|
||||
TBtn::Gold(amount) => {
|
||||
let allies = g.gold_allies();
|
||||
match allies.get(self.gold_to % allies.len().max(1)) {
|
||||
Some(&to) => UiAction::SendGold(to, amount),
|
||||
None => UiAction::Consumed,
|
||||
}
|
||||
}
|
||||
TBtn::OvRow(id) => match g.ents.iter().find(|e| e.id == id) {
|
||||
Some(e) => UiAction::MinimapJump(e.disp_x, e.disp_y),
|
||||
None => UiAction::Consumed,
|
||||
@@ -1036,6 +1054,32 @@ impl Ui {
|
||||
let mood = if mine.is_empty() { 0.0 } else { mine.iter().map(|e| e.happy.clamp(0.0, 1.0)).sum::<f32>() / mine.len() as f32 };
|
||||
let head = trf("ov.summary", &[mine.len().to_string(), (wage as i32).to_string(), ((mood * 100.0) as i32).to_string()]);
|
||||
gfx.text(&head, x + CW() * 2.0, y + CH(), S(), GOLD);
|
||||
// a match with allies: a row to send them gold (the name switches between the allies)
|
||||
let allies = g.gold_allies();
|
||||
let gold_row = !allies.is_empty();
|
||||
if gold_row {
|
||||
let to = allies[self.gold_to % allies.len()];
|
||||
let gy = y + CH() * 2.2;
|
||||
let name = trf("gold.send_to", &[tr(&format!("net.side{to}"))]);
|
||||
let mut bx = x + CW() * 2.0;
|
||||
let r = Rect::new(bx, gy, gfx.measure(&name, SMALL()) + CW() * 2.0, CH() * 1.6);
|
||||
let hov = r.contains(vec2(mx, my));
|
||||
draw_rectangle(r.x, r.y, r.w, r.h, if hov { Color::new(0.35, 0.22, 0.1, 1.0) } else { Color::new(0.15, 0.1, 0.08, 1.0) });
|
||||
draw_rectangle_lines(r.x, r.y, r.w, r.h, 2.0, side_color(Some(to)));
|
||||
gfx.text(&name, r.x + CW(), r.y + (r.h - GH * SMALL()) * 0.5, SMALL(), side_color(Some(to)));
|
||||
self.touch_btns.push((r, TBtn::GoldTo));
|
||||
bx += r.w + CW();
|
||||
for amount in crate::netplay::GOLD_AMOUNTS {
|
||||
let label = if amount == crate::netplay::GOLD_ALL { tr("gold.all") } else { amount.to_string() };
|
||||
let r = Rect::new(bx, gy, gfx.measure(&label, SMALL()) + CW() * 2.0, CH() * 1.6);
|
||||
let hov = r.contains(vec2(mx, my));
|
||||
draw_rectangle(r.x, r.y, r.w, r.h, if hov { Color::new(0.35, 0.22, 0.1, 1.0) } else { Color::new(0.15, 0.1, 0.08, 1.0) });
|
||||
draw_rectangle_lines(r.x, r.y, r.w, r.h, 2.0, GOLD);
|
||||
gfx.text(&label, r.x + CW(), r.y + (r.h - GH * SMALL()) * 0.5, SMALL(), GOLD);
|
||||
self.touch_btns.push((r, TBtn::Gold(amount)));
|
||||
bx += r.w + CW() * 0.5;
|
||||
}
|
||||
}
|
||||
// lines: kind headers and creatures
|
||||
let mut kinds: Vec<EK> = Vec::new();
|
||||
for e in &mine {
|
||||
@@ -1059,8 +1103,8 @@ impl Ui {
|
||||
lines.push((line, col, Some(e.id), e.hp / e.max_hp));
|
||||
}
|
||||
}
|
||||
let first = y + CH() * 3.0;
|
||||
let visible = (rows - 5).max(1) as usize;
|
||||
let first = y + CH() * if gold_row { 4.2 } else { 3.0 };
|
||||
let visible = (rows - if gold_row { 7 } else { 5 }).max(1) as usize;
|
||||
self.ov_scroll = self.ov_scroll.min(lines.len().saturating_sub(visible));
|
||||
let lw = (cols - 4) as f32 * CW();
|
||||
for (n, (text, col, id, hp)) in lines.iter().enumerate().skip(self.ov_scroll).take(visible) {
|
||||
@@ -1094,6 +1138,15 @@ impl Ui {
|
||||
pub fn draw_dialogs(&mut self, g: &Game, gfx: &Gfx) {
|
||||
let sw = sw();
|
||||
let sh = sh();
|
||||
if g.spectating() && g.state == 0 && !self.show_langsel {
|
||||
// the heart fell: the player watches the rest of the match
|
||||
let t = tr("net.spectating");
|
||||
let w = ((gfx.measure(&t, S()) / CW()).ceil() as i32 + 4).min((sw / CW()) as i32);
|
||||
let x = grid_center(sw, w as f32 * CW());
|
||||
let y = self.hud_h + CH() * 0.5;
|
||||
gfx.window(x, y, w, 3, S(), false, RED, BG);
|
||||
gfx.text(&t, grid_center(sw, gfx.measure(&t, S())), y + CH(), S(), RED);
|
||||
}
|
||||
if self.show_langsel {
|
||||
self.draw_langsel(gfx);
|
||||
} else if g.state != 0 {
|
||||
@@ -1258,10 +1311,20 @@ impl Ui {
|
||||
let st = trf("end.stats", &[mmss(g.time), g.wave.to_string(), (g.army_value() as i32).to_string()]);
|
||||
gfx.text(&st, grid_center(sw, gfx.measure(&st, S())), y + CH() * (4.5 + lines.len() as f32), S(), DIM);
|
||||
// buttons: free game: new game; mission: next / again and back to the campaign
|
||||
let labels: Vec<(String, u8)> = match mission {
|
||||
None => vec![(tr("end.new"), 0)],
|
||||
Some(_) => vec![(tr(if !win { "end.again" } else if last { "end.to_campaign" } else { "end.next" }), 1), (tr("end.campaign"), 2)],
|
||||
let labels: Vec<(String, u8)> = match (mission, self.coop_end) {
|
||||
// an editor campaign in co-op: the host goes on for everybody, the others wait or leave
|
||||
(_, Some((true, true, false))) => vec![(tr(if win { "end.next" } else { "end.again" }), 1), (tr("net.leave"), 2)],
|
||||
(_, Some((true, true, true))) | (_, Some((false, true, _))) => vec![(tr("net.leave"), 2)],
|
||||
(_, Some((_, false, _))) => vec![(tr("net.coop_run_over"), 2)],
|
||||
(None, None) => vec![(tr("end.new"), 0)],
|
||||
(Some(_), None) => vec![(tr(if !win { "end.again" } else if last { "end.to_campaign" } else { "end.next" }), 1), (tr("end.campaign"), 2)],
|
||||
};
|
||||
if let Some((host, true, sent)) = self.coop_end {
|
||||
if !host || sent {
|
||||
let t = tr("net.coop_wait_host");
|
||||
gfx.text(&t, grid_center(sw, gfx.measure(&t, SMALL())), y + CH() * (5.3 + lines.len() as f32), SMALL(), GOLD);
|
||||
}
|
||||
}
|
||||
let by = y + CH() * (6.0 + lines.len() as f32);
|
||||
let widths: Vec<f32> = labels.iter().map(|(l, _)| gfx.measure(l, S()) + CW() * 4.0).collect();
|
||||
let total: f32 = widths.iter().sum::<f32>() + CW() * 2.0 * (labels.len() as f32 - 1.0);
|
||||
|
||||
Reference in new issue
Block a user