Master talents: experience, points and four branches (Builder, Warlord, Warlock, Merchant) with a toolbar window
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b93bcd89c4
commit
bd956a4f57
28 files changed
+720
-22
No files matched your search
+29
-14
@@ -523,6 +523,8 @@ pub struct MasterState {
|
||||
pub rune_next: u32,
|
||||
pub portal_timer: f32,
|
||||
pub punch_ready: f32,
|
||||
#[serde(default)]
|
||||
pub talents: crate::talents::Talents,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
@@ -640,6 +642,8 @@ pub struct Game {
|
||||
#[serde(default)]
|
||||
pub snares: Vec<usize>, // tiles with a ranger's snare (rogues.rs)
|
||||
#[serde(default)]
|
||||
pub talents: crate::talents::Talents, // of the master being processed (talents.rs)
|
||||
#[serde(default)]
|
||||
pub guard_marks: Vec<usize>, // guard markers (shields) of the master being processed (orders.rs)
|
||||
#[serde(default)]
|
||||
pub attack_marks: Vec<usize>, // attack markers (swords)
|
||||
@@ -990,6 +994,7 @@ impl Game {
|
||||
trading: Default::default(),
|
||||
happenings: None,
|
||||
snares: Vec::new(),
|
||||
talents: Default::default(),
|
||||
guard_marks: Vec::new(),
|
||||
attack_marks: Vec::new(),
|
||||
marks_t: 0.0,
|
||||
@@ -1218,7 +1223,7 @@ impl Game {
|
||||
|
||||
// what the next payday costs: wages of all creatures plus the training bill
|
||||
pub fn next_payday_cost(&self) -> f32 {
|
||||
let wages: f32 = self.ents.iter().filter(|e| e.alive && e.creature()).map(|e| st(e.kind).wage as f32 * (1.0 + 0.1 * (e.level - 1) as f32)).sum();
|
||||
let wages: f32 = self.ents.iter().filter(|e| e.alive && e.creature()).map(|e| st(e.kind).wage as f32 * (1.0 + 0.1 * (e.level - 1) as f32)).sum::<f32>() * self.talents.wages();
|
||||
wages + self.training_bill
|
||||
}
|
||||
|
||||
@@ -1514,6 +1519,7 @@ impl Game {
|
||||
rune_next: self.rune_next,
|
||||
portal_timer: self.portal_timer,
|
||||
punch_ready: self.punch_ready,
|
||||
talents: self.talents.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1549,6 +1555,7 @@ impl Game {
|
||||
self.rune_next = m.rune_next;
|
||||
self.portal_timer = m.portal_timer;
|
||||
self.punch_ready = m.punch_ready;
|
||||
self.talents = m.talents;
|
||||
}
|
||||
|
||||
// make `side` the master being processed (no-op for sides that are no masters)
|
||||
@@ -1734,7 +1741,7 @@ impl Game {
|
||||
// a master's household: mana, core, portals, payday
|
||||
fn economy(&mut self, dt: f32) {
|
||||
self.recount();
|
||||
self.mana = (self.mana + (1.0 + SPRING_MANA * self.springs as f32) * dt).min(self.mana_max());
|
||||
self.mana = (self.mana + (1.0 + SPRING_MANA * self.springs as f32) * self.talents.mana_rate() * dt).min(self.mana_max());
|
||||
self.core_hp = (self.core_hp + 0.5 * dt).min(CORE_HP);
|
||||
|
||||
let owned = self.portals_owned();
|
||||
@@ -2081,13 +2088,14 @@ impl Game {
|
||||
self.training_bill = 0.0;
|
||||
let mut n = 0;
|
||||
let mut total = bill;
|
||||
let merchant = self.talents.wages();
|
||||
for i in 0..self.ents.len() {
|
||||
if !self.ents[i].alive || !self.ents[i].creature() {
|
||||
continue;
|
||||
}
|
||||
let r = self.rng.f();
|
||||
let e = &mut self.ents[i];
|
||||
let w = st(e.kind).wage as f32 * (1.0 + 0.1 * (e.level - 1) as f32);
|
||||
let w = st(e.kind).wage as f32 * (1.0 + 0.1 * (e.level - 1) as f32) * merchant;
|
||||
e.pay_due += w;
|
||||
e.pay_t = r * 55.0;
|
||||
n += 1;
|
||||
@@ -2761,7 +2769,9 @@ impl Game {
|
||||
}
|
||||
|
||||
fn hit(&mut self, e: &mut Ent, j: usize) {
|
||||
let dmg = e.atk() * (0.85 + self.rng.f() * 0.3);
|
||||
// the Warlord talent of the attacker's master
|
||||
let boost = if !e.hero && Owner::MASTER_SIDES.contains(&e.side) { self.talents_of(e.side).damage() } else { 1.0 };
|
||||
let dmg = e.atk() * (0.85 + self.rng.f() * 0.3) * boost;
|
||||
let (tx, ty) = (self.ents[j].x, self.ents[j].y);
|
||||
let s = st(e.kind);
|
||||
// the higher the level, the bigger the attack looks (up to almost twice at Lv 10)
|
||||
@@ -2870,8 +2880,12 @@ impl Game {
|
||||
}
|
||||
let my_id = e.id;
|
||||
e.invis = 0.0; // attacking breaks invisibility
|
||||
let armour = {
|
||||
let t = &self.ents[j];
|
||||
if !t.hero && Owner::MASTER_SIDES.contains(&t.side) { self.talents_of(t.side).armour() } else { 1.0 }
|
||||
};
|
||||
let t = &mut self.ents[j];
|
||||
t.hp -= if t.shield > 0.0 { dmg * 0.5 } else { dmg };
|
||||
t.hp -= if t.shield > 0.0 { dmg * 0.5 } else { dmg } * armour;
|
||||
t.flash = 0.15;
|
||||
if t.creature() && !matches!(t.job, Job::Attack(_)) {
|
||||
t.job = Job::Attack(my_id);
|
||||
@@ -2946,6 +2960,7 @@ impl Game {
|
||||
}
|
||||
if hero {
|
||||
let b = s.bounty as f32 + if kind == EK::Thief { self.thief_loot(id) } else { 0.0 };
|
||||
self.add_master_xp(s.bounty as f32 * crate::talents::HERO_XP);
|
||||
let got = self.add_gold(b);
|
||||
self.fx(5, x, y, 0.0, 0.0, 1.0, 0xff30d0ff);
|
||||
self.sfx(Sfx::HeroDeath, x, y);
|
||||
@@ -3495,7 +3510,7 @@ impl Game {
|
||||
e.face = sgn(tx as f32 + 0.5 - e.x);
|
||||
e.working = true;
|
||||
let skilled = if crate::personality::knows(e, "dig") { 1.25 } else { 1.0 };
|
||||
e.timer += dt * self.help_speed(t) * skilled;
|
||||
e.timer += dt * self.help_speed(t) * skilled * self.talents.dig_speed();
|
||||
if e.timer >= 0.45 {
|
||||
e.timer = 0.0;
|
||||
let fxx = (e.x + tx as f32 + 0.5) * 0.5;
|
||||
@@ -3655,7 +3670,7 @@ impl Game {
|
||||
}
|
||||
Job::Deliver => {
|
||||
if self.is_deposit(cur) {
|
||||
let amount = e.carry as f32;
|
||||
let amount = e.carry as f32 * self.talents.treasure();
|
||||
let got = self.add_res_at(amount, e.carry_res, Some(cur));
|
||||
if got < amount {
|
||||
self.hint(3, "hint.treasury_full");
|
||||
@@ -4939,7 +4954,7 @@ impl Game {
|
||||
|
||||
pub fn build_rect(&mut self, room: usize, x0: i32, y0: i32, x1: i32, y1: i32) {
|
||||
let kind = ROOM_KINDS[room];
|
||||
let cost = ROOM_COST[room] as f32;
|
||||
let cost = (ROOM_COST[room] as f32 * self.talents.room_cost()).round();
|
||||
let mut built = 0;
|
||||
let mut broke = false;
|
||||
for y in y0.min(y1)..=y0.max(y1) {
|
||||
@@ -5693,13 +5708,13 @@ impl Game {
|
||||
}
|
||||
|
||||
pub fn lightning(&mut self, wx: f32, wy: f32) {
|
||||
const COST: f32 = 50.0;
|
||||
if self.mana < COST {
|
||||
let cost = 50.0 * self.talents.spell_cost();
|
||||
if self.mana < cost {
|
||||
self.msg("msg.no_mana_bolt", vec![]);
|
||||
self.sfx_ui(Sfx::Error);
|
||||
return;
|
||||
}
|
||||
self.mana -= COST;
|
||||
self.mana -= cost;
|
||||
self.count(crate::stats::SPELLS, 1.0);
|
||||
self.sfx(Sfx::Lightning, wx, wy);
|
||||
self.fx(1, wx, wy, 0.0, 0.0, 0.5, 0xffffeeaa);
|
||||
@@ -5720,13 +5735,13 @@ impl Game {
|
||||
}
|
||||
|
||||
pub fn heal(&mut self, wx: f32, wy: f32) {
|
||||
const COST: f32 = 60.0;
|
||||
if self.mana < COST {
|
||||
let cost = 60.0 * self.talents.spell_cost();
|
||||
if self.mana < cost {
|
||||
self.msg("msg.no_mana_heal", vec![]);
|
||||
self.sfx_ui(Sfx::Error);
|
||||
return;
|
||||
}
|
||||
self.mana -= COST;
|
||||
self.mana -= cost;
|
||||
self.count(crate::stats::SPELLS, 1.0);
|
||||
self.sfx(Sfx::Heal, wx, wy);
|
||||
let mut fxs = Vec::new();
|
||||
|
||||
Reference in new issue
Block a user