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:
Richard ZinkandClaude Opus 5.5 committed 2026-11-05 19:59:43 +01:00
1 parent 811c955bad
commit fc9c49d4ca
16 files changed
+1896 -49

No files matched your search

+53
View File
@@ -734,6 +734,20 @@ pub fn editor_fort(g: &mut Game, x: i32, y: i32, level: u32, shard: bool) {
g.recount();
}
// an island in a lake (water or lava) at a map fraction, with a mana spring and/or treasure
pub fn editor_island(g: &mut Game, at: (f32, f32), lava: bool, spring: bool, treasure: i32, seed: u32) {
let (w, h) = (g.map.w, g.map.h);
place_island(g, &island(at, lava, spring, treasure), w, h, seed);
g.recount();
}
// a sealed cave at a map fraction, with a chained creature and/or treasure
pub fn editor_cave(g: &mut Game, at: (f32, f32), chained: Option<(EK, u32)>, treasure: i32) {
let (w, h) = (g.map.w, g.map.h);
place_cave(g, &cave(at, chained, treasure), w, h);
g.recount();
}
// a painted map: the game state saved by the map editor
pub fn load_fixed_map(json: &str) -> Option<Game> {
let mut g: Game = serde_json::from_str(json).ok()?;
@@ -774,6 +788,45 @@ pub fn carry_from(g: &Game) -> Carry {
Carry { creatures: c.iter().take(CARRY_CREATURES).map(|e| (e.kind, e.level, e.xp)).collect(), gold: (g.gold * CARRY_GOLD).floor(), rune_free: g.rune_free, rune_final: g.rune_final + g.rune_next }
}
// a co-op match of an editor campaign: what every master takes into the next mission - his
// strongest creatures and a fifth of his gold. It comes from the shared world, so it is the same on
// every client (the host sends it along with the next mission anyway).
pub fn coop_carry_from(g: &Game) -> Vec<(u8, Carry)> {
let power = |e: &Ent| e.max_hp * e.atk() / st(e.kind).interval;
g.master_sides()
.into_iter()
.map(|side| {
let mut c: Vec<&Ent> = g.ents.iter().filter(|e| e.alive && !e.hero && e.side == side && e.kind != EK::Worker && !e.chained && e.captive == 0).collect();
c.sort_by(|a, b| power(b).partial_cmp(&power(a)).unwrap_or(std::cmp::Ordering::Equal).then(a.id.cmp(&b.id)));
let creatures = c.iter().take(CARRY_CREATURES).map(|e| (e.kind, e.level, e.xp)).collect();
(side, Carry { creatures, gold: (g.gold_of(side).max(0.0) * CARRY_GOLD).floor(), rune_free: 0, rune_final: 0 })
})
.collect()
}
// the carry of every master put into a new co-op mission: gold for him, his creatures around his heart
pub fn apply_coop_carry(g: &mut Game, carry: &[(u8, Carry)]) {
let local = g.local_side;
for (side, c) in carry {
if !g.is_master(*side) {
continue; // the seat is played by the AI now
}
g.switch_to(*side);
g.gold += c.gold.max(0.0);
let (cx, cy) = g.map.core;
for (k, &(kind, level, xp)) in c.creatures.iter().take(CARRY_CREATURES).enumerate() {
let a = k as f32 * 1.1;
let (x, y) = (cx as f32 + 1.5 + a.cos() * 3.0, cy as f32 + 1.5 + a.sin() * 3.0);
let id = g.spawn(kind, false, x, y, level.clamp(1, 10));
if let Some(e) = g.ents.iter_mut().find(|e| e.id == id) {
e.xp = xp;
e.happy = 1.0;
}
}
}
g.switch_to(local);
}
#[cfg(test)]
mod tests {
use super::*;