Script blocks for weather and talent experience, groves as ground; the co-op campaign brings rogues and a storm
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4e3158cc19
commit
eb219f6b01
23 files changed
+233
-8
No files matched your search
+26
-5
@@ -16,7 +16,7 @@ pub const KINDS: [&str; 30] = [
|
||||
];
|
||||
|
||||
// ground a Terrain block can make
|
||||
pub const TERRAIN: [&str; 6] = ["floor", "earth", "rock", "water", "lava", "gold"];
|
||||
pub const TERRAIN: [&str; 7] = ["floor", "earth", "rock", "water", "lava", "gold", "grove"];
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(tag = "b")]
|
||||
@@ -42,6 +42,8 @@ pub enum Block {
|
||||
Terrain { zone: String, kind: String },
|
||||
Kill { zone: String, side: i32 },
|
||||
Trigger { name: String, on: bool },
|
||||
Weather { kind: String, secs: Val }, // the weather above ground (secs 0: until changed again)
|
||||
TalentXp { amount: Val }, // experience for the player's talents
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
@@ -70,6 +72,7 @@ pub enum Val {
|
||||
Or { a: Box<Val>, b: Box<Val> },
|
||||
Not { a: Box<Val> },
|
||||
EventKind { kind: String }, // the unit that set off the trigger is of this kind
|
||||
WeatherIs { kind: String }, // the weather above ground is ...
|
||||
}
|
||||
|
||||
pub const MATH_OPS: [&str; 4] = ["+", "-", "*", "/"];
|
||||
@@ -89,7 +92,7 @@ impl Val {
|
||||
|
||||
pub fn ty(&self) -> Ty {
|
||||
match self {
|
||||
Val::Bool { .. } | Val::Cmp { .. } | Val::And { .. } | Val::Or { .. } | Val::Not { .. } | Val::EventKind { .. } => Ty::Bool,
|
||||
Val::Bool { .. } | Val::Cmp { .. } | Val::And { .. } | Val::Or { .. } | Val::Not { .. } | Val::EventKind { .. } | Val::WeatherIs { .. } => Ty::Bool,
|
||||
_ => Ty::Num,
|
||||
}
|
||||
}
|
||||
@@ -113,6 +116,7 @@ impl Val {
|
||||
"or" => Val::Or { a: Box::new(Val::Bool { b: true }), b: Box::new(Val::Bool { b: false }) },
|
||||
"not" => Val::Not { a: Box::new(Val::Bool { b: true }) },
|
||||
"eventkind" => Val::EventKind { kind: "Knight".into() },
|
||||
"weatheris" => Val::WeatherIs { kind: "rain".into() },
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
@@ -135,16 +139,20 @@ impl Val {
|
||||
Val::Or { .. } => "or",
|
||||
Val::Not { .. } => "not",
|
||||
Val::EventKind { .. } => "eventkind",
|
||||
Val::WeatherIs { .. } => "weatheris",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// value kinds by type, for the value picker
|
||||
pub const NUM_VALUES: [&str; 9] = ["num", "var", "gold", "mana", "time", "creatures", "inzone", "random", "math"];
|
||||
pub const BOOL_VALUES: [&str; 6] = ["cmp", "and", "or", "not", "bool", "eventkind"];
|
||||
pub const BOOL_VALUES: [&str; 7] = ["cmp", "and", "or", "not", "bool", "eventkind", "weatheris"];
|
||||
|
||||
// the weather a block can set or ask for (weather.rs: FAIR, RAIN, FOG, STORM)
|
||||
pub const WEATHER: [&str; 4] = ["fair", "rain", "fog", "storm"];
|
||||
|
||||
// statement blocks in the palette: (category, kind)
|
||||
pub const PALETTE: [(&str, &str); 21] = [
|
||||
pub const PALETTE: [(&str, &str); 23] = [
|
||||
("say", "message"),
|
||||
("say", "objective"),
|
||||
("say", "hint"),
|
||||
@@ -156,6 +164,8 @@ pub const PALETTE: [(&str, &str); 21] = [
|
||||
("world", "camera"),
|
||||
("world", "gold"),
|
||||
("world", "mana"),
|
||||
("world", "weather"),
|
||||
("world", "talentxp"),
|
||||
("logic", "if"),
|
||||
("logic", "repeat"),
|
||||
("logic", "until"),
|
||||
@@ -185,6 +195,8 @@ impl Block {
|
||||
"camera" => Block::Camera { zone: String::new() },
|
||||
"gold" => Block::Gold { amount: n(500.0) },
|
||||
"mana" => Block::Mana { amount: n(100.0) },
|
||||
"weather" => Block::Weather { kind: "storm".into(), secs: n(0.0) },
|
||||
"talentxp" => Block::TalentXp { amount: n(300.0) },
|
||||
"if" => Block::If { cond: Val::template("cmp").unwrap(), then: Vec::new(), els: Vec::new() },
|
||||
"repeat" => Block::Repeat { times: n(3.0), body: Vec::new() },
|
||||
"until" => Block::Until { cond: Val::template("cmp").unwrap(), body: Vec::new() },
|
||||
@@ -212,6 +224,8 @@ impl Block {
|
||||
Block::Camera { .. } => "camera",
|
||||
Block::Gold { .. } => "gold",
|
||||
Block::Mana { .. } => "mana",
|
||||
Block::Weather { .. } => "weather",
|
||||
Block::TalentXp { .. } => "talentxp",
|
||||
Block::If { .. } => "if",
|
||||
Block::Repeat { .. } => "repeat",
|
||||
Block::Until { .. } => "until",
|
||||
@@ -258,6 +272,7 @@ fn check_val(v: &Val, want: Ty, n: &Names, path: &[usize], out: &mut Vec<Problem
|
||||
Val::Creatures { kind, .. } if !kind.is_empty() && !KINDS.contains(&kind.as_str()) => out.push(p("blk.err_kind")),
|
||||
Val::InZone { zone, .. } if !n.zones.iter().any(|z| z == zone) => out.push(p("blk.err_zone")),
|
||||
Val::EventKind { kind } if !KINDS.contains(&kind.as_str()) => out.push(p("blk.err_kind")),
|
||||
Val::WeatherIs { kind } if !WEATHER.contains(&kind.as_str()) => out.push(p("blk.err_weather")),
|
||||
Val::Random { a, b } | Val::Math { a, b, .. } => {
|
||||
check_val(a, Ty::Num, n, path, out);
|
||||
check_val(b, Ty::Num, n, path, out);
|
||||
@@ -295,7 +310,13 @@ fn check_list(list: &[Block], n: &Names, path: &mut Vec<usize>, out: &mut Vec<Pr
|
||||
}
|
||||
}
|
||||
Block::Wave { count } => check_val(count, Ty::Num, n, path, out),
|
||||
Block::Gold { amount } | Block::Mana { amount } => check_val(amount, Ty::Num, n, path, out),
|
||||
Block::Gold { amount } | Block::Mana { amount } | Block::TalentXp { amount } => check_val(amount, Ty::Num, n, path, out),
|
||||
Block::Weather { kind, secs } => {
|
||||
if !WEATHER.contains(&kind.as_str()) {
|
||||
out.push(p("blk.err_weather", path));
|
||||
}
|
||||
check_val(secs, Ty::Num, n, path, out);
|
||||
}
|
||||
Block::SetVar { name, value } | Block::AddVar { name, value } => {
|
||||
if !valid_var(name) {
|
||||
out.push(p("blk.err_var", path));
|
||||
|
||||
Reference in new issue
Block a user