Champions of the Order lead every fifth wave: four bosses with abilities, a health bar and loot
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9debc08a0a
commit
9535e68df0
23 files changed
+303
-1
No files matched your search
@@ -53,6 +53,12 @@ msg.creature_arrived = Portálem přišel nový tvor: {0}.
|
||||
msg.payday_partial = Výplata! {0} tvorů dostalo zaplaceno ({1} zlata), {2} nedostalo nic a zuří!
|
||||
msg.payday = Výplata! {0} tvorů dostalo {1} zlata.
|
||||
msg.wave_boss = Vlna {0}: paladin světla vede do tvé říše hrdiny ({1})!
|
||||
boss.aldric = Sir Aldric Neoblomný
|
||||
boss.seraphine = Dáma Seraphine z Úsvitu
|
||||
boss.halvard = Bratr Halvard Zbožný
|
||||
boss.rothgar = Kapitán Rothgar Železný Bok
|
||||
msg.boss_comes = Vlnu vede šampion řádu: {0}!
|
||||
msg.boss_slain = {0} padl! Kořist: {1} zlata a plány věže runové kovárny.
|
||||
msg.wave = Vlna {0}: bránou se valí hrdinové ({1})!
|
||||
msg.gate_boss = Brána se hroutí! Objevuje se strážce brány s obránci ({0})!
|
||||
msg.gate_defenders = Brána povolává obránce ({0})!
|
||||
|
||||
@@ -53,6 +53,12 @@ msg.creature_arrived = En {0} kom gennem portalen.
|
||||
msg.payday_partial = Lønningsdag! {0} væsner fik løn ({1} guld), {2} fik intet og er vrede!
|
||||
msg.payday = Lønningsdag! {0} væsner fik {1} guld.
|
||||
msg.wave_boss = Bølge {0}: en lysets paladin fører {1} helte ind i dit rige!
|
||||
boss.aldric = Sir Aldric den Ubøjelige
|
||||
boss.seraphine = Dame Seraphine af Daggry
|
||||
boss.halvard = Broder Halvard den Fromme
|
||||
boss.rothgar = Kaptajn Rothgar Jernflanke
|
||||
msg.boss_comes = En af ordenens kæmper fører bølgen: {0}!
|
||||
msg.boss_slain = {0} er faldet! Bytte: {1} guld og tegningerne til et runesmedjetårn.
|
||||
msg.wave = Bølge {0}: {1} helte bryder gennem porten!
|
||||
msg.gate_boss = Porten smuldrer! Portvogteren dukker op med {0} forsvarere!
|
||||
msg.gate_defenders = Porten tilkalder {0} forsvarere!
|
||||
|
||||
@@ -52,6 +52,12 @@ msg.creature_arrived = Ein {0} ist durch das Portal gekommen.
|
||||
msg.payday_partial = Zahltag! {0} Kreaturen bezahlt ({1} Gold), {2} gingen leer aus und sind wütend!
|
||||
msg.payday = Zahltag! {0} Kreaturen erhielten {1} Gold.
|
||||
msg.wave_boss = Welle {0}: Ein Lichtpaladin führt {1} Helden in dein Reich!
|
||||
boss.aldric = Sir Aldric der Unbeugsame
|
||||
boss.seraphine = Dame Seraphine von der Morgenröte
|
||||
boss.halvard = Bruder Halvard der Fromme
|
||||
boss.rothgar = Hauptmann Rothgar Eisenflanke
|
||||
msg.boss_comes = Ein Champion des Ordens führt die Welle an: {0}!
|
||||
msg.boss_slain = {0} ist gefallen! Beute: {1} Gold und die Pläne eines Runenschmiede-Turms.
|
||||
msg.wave = Welle {0}: {1} Helden dringen durch das Tor!
|
||||
msg.gate_boss = Das Tor wankt! Der Torwächter erscheint mit {0} Verteidigern!
|
||||
msg.gate_defenders = Das Tor ruft {0} Verteidiger herbei!
|
||||
|
||||
@@ -53,6 +53,12 @@ msg.creature_arrived = Ήρθε από την πύλη: {0}.
|
||||
msg.payday_partial = Μέρα πληρωμής! Πληρώθηκαν {0} πλάσματα ({1} χρυσός), {2} δεν πήραν τίποτα και είναι έξαλλα!
|
||||
msg.payday = Μέρα πληρωμής! {0} πλάσματα πήραν {1} χρυσό.
|
||||
msg.wave_boss = Κύμα {0}: ένας Παλαδίνος του Φωτός οδηγεί {1} ήρωες στο βασίλειό σου!
|
||||
boss.aldric = Σερ Άλντρικ ο Αλύγιστος
|
||||
boss.seraphine = Κυρία Σεραφίνα της Αυγής
|
||||
boss.halvard = Αδελφός Χάλβαρντ ο Ευσεβής
|
||||
boss.rothgar = Λοχαγός Ρόθγκαρ Σιδερόπλευρος
|
||||
msg.boss_comes = Ένας πρωταθλητής του Τάγματος οδηγεί το κύμα: {0}!
|
||||
msg.boss_slain = {0} νικήθηκε! Λάφυρα: {1} χρυσός και τα σχέδια ενός πύργου ρουνικού σιδηρουργείου.
|
||||
msg.wave = Κύμα {0}: {1} ήρωες διασχίζουν την πύλη!
|
||||
msg.gate_boss = Η πύλη καταρρέει! Ο Φύλακας της Πύλης εμφανίζεται με {0} υπερασπιστές!
|
||||
msg.gate_defenders = Η πύλη καλεί {0} υπερασπιστές!
|
||||
|
||||
@@ -53,6 +53,12 @@ msg.creature_arrived = A {0} came through the portal.
|
||||
msg.payday_partial = Payday! {0} creatures paid ({1} gold), {2} got nothing and are angry!
|
||||
msg.payday = Payday! {0} creatures received {1} gold.
|
||||
msg.wave_boss = Wave {0}: a Paladin of Light leads {1} heroes into your realm!
|
||||
boss.aldric = Sir Aldric the Unbending
|
||||
boss.seraphine = Dame Seraphine of the Dawn
|
||||
boss.halvard = Brother Halvard the Pious
|
||||
boss.rothgar = Captain Rothgar Ironside
|
||||
msg.boss_comes = A champion of the Order leads the wave: {0}!
|
||||
msg.boss_slain = {0} has fallen! Loot: {1} gold and the plans of a rune forge tower.
|
||||
msg.wave = Wave {0}: {1} heroes break through the gate!
|
||||
msg.gate_boss = The gate is crumbling! The Gate Warden appears with {0} defenders!
|
||||
msg.gate_defenders = The gate summons {0} defenders!
|
||||
|
||||
@@ -53,6 +53,12 @@ msg.creature_arrived = Un {0} ha cruzado el portal.
|
||||
msg.payday_partial = ¡Día de paga! {0} criaturas cobran ({1} de oro), ¡{2} no reciben nada y están furiosas!
|
||||
msg.payday = ¡Día de paga! {0} criaturas reciben {1} de oro.
|
||||
msg.wave_boss = Oleada {0}: ¡un Paladín de la Luz guía a {1} héroes hacia tu reino!
|
||||
boss.aldric = Sir Aldric el Inflexible
|
||||
boss.seraphine = Dama Seraphine del Alba
|
||||
boss.halvard = Hermano Halvard el Piadoso
|
||||
boss.rothgar = Capitán Rothgar Flanco de Hierro
|
||||
msg.boss_comes = Un campeón de la Orden encabeza la oleada: ¡{0}!
|
||||
msg.boss_slain = ¡{0} ha caído! Botín: {1} de oro y los planos de una torre de forja rúnica.
|
||||
msg.wave = Oleada {0}: ¡{1} héroes atraviesan la puerta!
|
||||
msg.gate_boss = ¡La puerta se desmorona! ¡El Guardián de la Puerta aparece con {0} defensores!
|
||||
msg.gate_defenders = ¡La puerta invoca a {0} defensores!
|
||||
|
||||
@@ -53,6 +53,12 @@ msg.creature_arrived = Portaalista tuli olento: {0}.
|
||||
msg.payday_partial = Palkkapäivä! {0} olentoa sai palkan ({1} kultaa), {2} jäi ilman ja on vihainen!
|
||||
msg.payday = Palkkapäivä! {0} olentoa sai yhteensä {1} kultaa.
|
||||
msg.wave_boss = Aalto {0}: Valon paladiini johtaa {1} sankaria valtakuntaasi!
|
||||
boss.aldric = Ser Aldric Taipumaton
|
||||
boss.seraphine = Rouva Seraphine Aamunkoitosta
|
||||
boss.halvard = Veli Halvard Hurskas
|
||||
boss.rothgar = Kapteeni Rothgar Rautakylki
|
||||
msg.boss_comes = Ritarikunnan mestari johtaa aaltoa: {0}!
|
||||
msg.boss_slain = {0} on kaatunut! Saalis: {1} kultaa ja riimupajatornin piirustukset.
|
||||
msg.wave = Aalto {0}: {1} sankaria murtautuu portista!
|
||||
msg.gate_boss = Portti horjuu! Portinvartija ilmestyy, mukanaan {0} puolustajaa!
|
||||
msg.gate_defenders = Portti kutsuu {0} puolustajaa!
|
||||
|
||||
@@ -53,6 +53,12 @@ msg.creature_arrived = Kroz portal je stiglo stvorenje: {0}.
|
||||
msg.payday_partial = Dan isplate! Plaćeno stvorenja: {0} ({1} zlata), {2} nisu dobila ništa i bijesna su!
|
||||
msg.payday = Dan isplate! Stvorenja ({0}) primila su {1} zlata.
|
||||
msg.wave_boss = Val {0}: Paladin svjetla vodi junake ({1}) u tvoje carstvo!
|
||||
boss.aldric = Sir Aldric Nepokolebljivi
|
||||
boss.seraphine = Dama Seraphine od Zore
|
||||
boss.halvard = Brat Halvard Pobožni
|
||||
boss.rothgar = Kapetan Rothgar Željezni Bok
|
||||
msg.boss_comes = Prvak reda predvodi val: {0}!
|
||||
msg.boss_slain = {0} je pao! Plijen: {1} zlata i nacrti tornja runske kovačnice.
|
||||
msg.wave = Val {0}: junaci ({1}) probijaju vrata!
|
||||
msg.gate_boss = Vrata se urušavaju! Pojavljuje se Čuvar vrata s braniteljima ({0})!
|
||||
msg.gate_defenders = Vrata dozivaju branitelje: {0}!
|
||||
|
||||
@@ -53,6 +53,12 @@ msg.creature_arrived = Új lény érkezett a portálon át: {0}.
|
||||
msg.payday_partial = Fizetésnap! {0} lény kapott bért ({1} arany), {2} semmit sem kapott, és dühös!
|
||||
msg.payday = Fizetésnap! {0} lény összesen {1} aranyat kapott.
|
||||
msg.wave_boss = {0}. hullám: a Fény egyik paladinja {1} hőst vezet a birodalmadba!
|
||||
boss.aldric = Aldric lovag, a Hajthatatlan
|
||||
boss.seraphine = Seraphine úrnő, a Hajnal
|
||||
boss.halvard = Halvard testvér, a Jámbor
|
||||
boss.rothgar = Rothgar kapitány, a Vasoldalú
|
||||
msg.boss_comes = A rend bajnoka vezeti a rohamot: {0}!
|
||||
msg.boss_slain = {0} elesett! Zsákmány: {1} arany és egy rúnakovács-torony tervrajza.
|
||||
msg.wave = {0}. hullám: {1} hős tör át a kapun!
|
||||
msg.gate_boss = A kapu omladozik! Megjelent a Kapuőr {0} védelmezővel!
|
||||
msg.gate_defenders = A kapu {0} védelmezőt idéz!
|
||||
|
||||
@@ -53,6 +53,12 @@ msg.creature_arrived = Nuovo arrivo dal portale: {0}.
|
||||
msg.payday_partial = Giorno di paga! {0} creature pagate ({1} oro), {2} a mani vuote e furiose!
|
||||
msg.payday = Giorno di paga! {0} creature hanno ricevuto {1} oro.
|
||||
msg.wave_boss = Ondata {0}: un Paladino della Luce guida {1} eroi nel tuo regno!
|
||||
boss.aldric = Sir Aldric l'Inflessibile
|
||||
boss.seraphine = Dama Seraphine dell'Aurora
|
||||
boss.halvard = Fratello Halvard il Pio
|
||||
boss.rothgar = Capitano Rothgar Fianco di Ferro
|
||||
msg.boss_comes = Un campione dell'Ordine guida l'ondata: {0}!
|
||||
msg.boss_slain = {0} è caduto! Bottino: {1} oro e i piani di una torre della forgia runica.
|
||||
msg.wave = Ondata {0}: {1} eroi sfondano la porta!
|
||||
msg.gate_boss = La porta si sgretola! Appare il Guardiano della Porta con {0} difensori!
|
||||
msg.gate_defenders = La porta evoca {0} difensori!
|
||||
|
||||
@@ -53,6 +53,12 @@ msg.creature_arrived = Er kwam een {0} door het portaal.
|
||||
msg.payday_partial = Betaaldag! {0} wezens betaald ({1} goud), {2} kregen niets en zijn woedend!
|
||||
msg.payday = Betaaldag! {0} wezens kregen {1} goud.
|
||||
msg.wave_boss = Golf {0}: een Lichtpaladijn leidt {1} helden je rijk binnen!
|
||||
boss.aldric = Sir Aldric de Onbuigzame
|
||||
boss.seraphine = Dame Seraphine van de Dageraad
|
||||
boss.halvard = Broeder Halvard de Vrome
|
||||
boss.rothgar = Kapitein Rothgar IJzerflank
|
||||
msg.boss_comes = Een kampioen van de Orde leidt de golf: {0}!
|
||||
msg.boss_slain = {0} is gevallen! Buit: {1} goud en de plannen van een runensmidstoren.
|
||||
msg.wave = Golf {0}: {1} helden breken door de poort!
|
||||
msg.gate_boss = De poort brokkelt af! De Poortwachter verschijnt met {0} verdedigers!
|
||||
msg.gate_defenders = De poort roept {0} verdedigers op!
|
||||
|
||||
@@ -53,6 +53,12 @@ msg.creature_arrived = En {0} kom gjennom portalen.
|
||||
msg.payday_partial = Lønningsdag! {0} skapninger fikk lønn ({1} gull), {2} fikk ingenting og er sinte!
|
||||
msg.payday = Lønningsdag! {0} skapninger fikk {1} gull.
|
||||
msg.wave_boss = Bølge {0}: en lysets paladin leder {1} helter inn i riket ditt!
|
||||
boss.aldric = Sir Aldric den Ubøyelige
|
||||
boss.seraphine = Dame Seraphine av Daggry
|
||||
boss.halvard = Bror Halvard den Fromme
|
||||
boss.rothgar = Kaptein Rothgar Jernflanke
|
||||
msg.boss_comes = En av ordenens forkjempere leder bølgen: {0}!
|
||||
msg.boss_slain = {0} har falt! Bytte: {1} gull og tegningene til et runesmietårn.
|
||||
msg.wave = Bølge {0}: {1} helter bryter gjennom porten!
|
||||
msg.gate_boss = Porten smuldrer! Portvokteren dukker opp med {0} forsvarere!
|
||||
msg.gate_defenders = Porten tilkaller {0} forsvarere!
|
||||
|
||||
@@ -53,6 +53,12 @@ msg.creature_arrived = Um {0} atravessou o portal.
|
||||
msg.payday_partial = Dia de pagamento! {0} criaturas pagas ({1} de ouro), {2} ficaram sem nada e estão furiosas!
|
||||
msg.payday = Dia de pagamento! {0} criaturas receberam {1} de ouro.
|
||||
msg.wave_boss = Vaga {0}: um Paladino da Luz conduz {1} heróis ao teu reino!
|
||||
boss.aldric = Sir Aldric, o Inflexível
|
||||
boss.seraphine = Dama Seraphine da Aurora
|
||||
boss.halvard = Irmão Halvard, o Pio
|
||||
boss.rothgar = Capitão Rothgar Flanco-de-Ferro
|
||||
msg.boss_comes = Um campeão da Ordem lidera a onda: {0}!
|
||||
msg.boss_slain = {0} caiu! Saque: {1} de ouro e os planos de uma torre da forja rúnica.
|
||||
msg.wave = Vaga {0}: {1} heróis irrompem pelo portão!
|
||||
msg.gate_boss = O portão está a ruir! Surge o Guardião do Portão com {0} defensores!
|
||||
msg.gate_defenders = O portão invoca {0} defensores!
|
||||
|
||||
@@ -53,6 +53,12 @@ msg.creature_arrived = Un {0} a venit prin portal.
|
||||
msg.payday_partial = Ziua de plată! {0} creaturi plătite ({1} aur), {2} n-au primit nimic și sunt furioase!
|
||||
msg.payday = Ziua de plată! {0} creaturi au primit {1} aur.
|
||||
msg.wave_boss = Valul {0}: un Paladin al Luminii conduce {1} eroi în tărâmul tău!
|
||||
boss.aldric = Sir Aldric cel Neînduplecat
|
||||
boss.seraphine = Dama Seraphine a Zorilor
|
||||
boss.halvard = Fratele Halvard cel Evlavios
|
||||
boss.rothgar = Căpitanul Rothgar Flanc-de-Fier
|
||||
msg.boss_comes = Un campion al Ordinului conduce valul: {0}!
|
||||
msg.boss_slain = {0} a căzut! Pradă: {1} aur și planurile unui turn al forjei runice.
|
||||
msg.wave = Valul {0}: {1} eroi sparg poarta!
|
||||
msg.gate_boss = Poarta se năruie! Paznicul Porții apare cu {0} apărători!
|
||||
msg.gate_defenders = Poarta cheamă {0} apărători!
|
||||
|
||||
@@ -53,6 +53,12 @@ msg.creature_arrived = Через портал пришёл новичок: {0}.
|
||||
msg.payday_partial = День выплат! {0} существ получили жалованье ({1} золота), {2} остались ни с чем и злятся!
|
||||
msg.payday = День выплат! {0} существ получили {1} золота.
|
||||
msg.wave_boss = Волна {0}: Паладин Света ведёт в твои владения {1} героев!
|
||||
boss.aldric = Сэр Алдрик Непреклонный
|
||||
boss.seraphine = Дама Серафина Рассветная
|
||||
boss.halvard = Брат Халвард Благочестивый
|
||||
boss.rothgar = Капитан Ротгар Железный Бок
|
||||
msg.boss_comes = Волну ведёт чемпион ордена: {0}!
|
||||
msg.boss_slain = {0} пал! Добыча: {1} золота и чертежи башни рунной кузницы.
|
||||
msg.wave = Волна {0}: {1} героев прорываются через врата!
|
||||
msg.gate_boss = Врата рушатся! Появляется Страж врат и {0} защитников!
|
||||
msg.gate_defenders = Врата призывают {0} защитников!
|
||||
|
||||
@@ -53,6 +53,12 @@ msg.creature_arrived = Portálom prišiel nový tvor: {0}.
|
||||
msg.payday_partial = Výplata! {0} tvorov dostalo zaplatené ({1} zlata), {2} nedostalo nič a zúri!
|
||||
msg.payday = Výplata! {0} tvorov dostalo {1} zlata.
|
||||
msg.wave_boss = Vlna {0}: paladin svetla vedie do tvojej ríše hrdinov ({1})!
|
||||
boss.aldric = Sir Aldric Neoblomný
|
||||
boss.seraphine = Dáma Seraphine z Úsvitu
|
||||
boss.halvard = Brat Halvard Zbožný
|
||||
boss.rothgar = Kapitán Rothgar Železný Bok
|
||||
msg.boss_comes = Vlnu vedie šampión rádu: {0}!
|
||||
msg.boss_slain = {0} padol! Korisť: {1} zlata a plány veže runovej vyhne.
|
||||
msg.wave = Vlna {0}: bránou sa valia hrdinovia ({1})!
|
||||
msg.gate_boss = Brána sa rúca! Objavuje sa strážca brány s obrancami ({0})!
|
||||
msg.gate_defenders = Brána povoláva obrancov ({0})!
|
||||
|
||||
@@ -53,6 +53,12 @@ msg.creature_arrived = Кроз портал је стигло створење:
|
||||
msg.payday_partial = Дан исплате! Плаћено створења: {0} ({1} злата), {2} нису добила ништа и бесна су!
|
||||
msg.payday = Дан исплате! Створења ({0}) примила су {1} злата.
|
||||
msg.wave_boss = Талас {0}: Паладин светлости води хероје ({1}) у твоје царство!
|
||||
boss.aldric = Сер Алдрик Непоколебљиви
|
||||
boss.seraphine = Дама Серафина од Зоре
|
||||
boss.halvard = Брат Халвард Побожни
|
||||
boss.rothgar = Капетан Ротгар Гвоздени Бок
|
||||
msg.boss_comes = Првак реда предводи талас: {0}!
|
||||
msg.boss_slain = {0} је пао! Плен: {1} злата и нацрти куле рунске ковачнице.
|
||||
msg.wave = Талас {0}: хероји ({1}) пробијају капију!
|
||||
msg.gate_boss = Капија се руши! Појављује се Чувар капије са браниоцима ({0})!
|
||||
msg.gate_defenders = Капија призива браниоце: {0}!
|
||||
|
||||
@@ -53,6 +53,12 @@ msg.creature_arrived = En {0} kom genom portalen.
|
||||
msg.payday_partial = Lönedag! {0} varelser fick betalt ({1} guld), {2} fick ingenting och är arga!
|
||||
msg.payday = Lönedag! {0} varelser fick {1} guld.
|
||||
msg.wave_boss = Våg {0}: en Ljusets paladin leder {1} hjältar in i ditt rike!
|
||||
boss.aldric = Sir Aldric den Obeveklige
|
||||
boss.seraphine = Dam Seraphine av Gryningen
|
||||
boss.halvard = Broder Halvard den Fromme
|
||||
boss.rothgar = Kapten Rothgar Järnflank
|
||||
msg.boss_comes = En av ordens kämpar leder vågen: {0}!
|
||||
msg.boss_slain = {0} har fallit! Byte: {1} guld och ritningarna till ett runsmedjetorn.
|
||||
msg.wave = Våg {0}: {1} hjältar bryter igenom porten!
|
||||
msg.gate_boss = Porten vacklar! Portväktaren dyker upp med {0} försvarare!
|
||||
msg.gate_defenders = Porten kallar på {0} försvarare!
|
||||
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
// Bosses: every fifth wave is led by one of the Order's champions - a paladin with a name, more
|
||||
// than twice the health, an ability of his own and loot for whoever brings him down (gold and a
|
||||
// free rune forge tower). His health bar stands at the top of the screen while he lives.
|
||||
|
||||
use crate::game::*;
|
||||
use crate::particles::*;
|
||||
|
||||
// the champions (Ent::boss = index + 1): ability cooldowns in seconds
|
||||
pub const BOSSES: [(&str, f32); 4] = [("aldric", 12.0), ("seraphine", 10.0), ("halvard", 18.0), ("rothgar", 9.0)];
|
||||
pub const BOSS_HP: f32 = 2.5; // health factor
|
||||
pub const BOSS_GOLD: f32 = 600.0;
|
||||
|
||||
pub fn boss_name(b: u8) -> String {
|
||||
format!("@boss.{}", BOSSES[(b.max(1) as usize - 1) % BOSSES.len()].0)
|
||||
}
|
||||
|
||||
impl Game {
|
||||
// the unit at index j leads the wave as champion number `b` (1..=4)
|
||||
pub(crate) fn make_boss(&mut self, j: usize, b: u8) {
|
||||
let e = &mut self.ents[j];
|
||||
e.boss = b;
|
||||
e.max_hp *= BOSS_HP;
|
||||
e.hp = e.max_hp;
|
||||
e.ab_cd = 4.0;
|
||||
let name = boss_name(b);
|
||||
self.msg("msg.boss_comes", vec![name]);
|
||||
}
|
||||
|
||||
// the champion's ability, used by itself whenever it is ready
|
||||
pub(crate) fn boss_ability(&mut self, e: &mut Ent, dt: f32) {
|
||||
e.ab_cd -= dt;
|
||||
if e.ab_cd > 0.0 || e.captive != 0 {
|
||||
return;
|
||||
}
|
||||
let (bx, by) = (e.x, e.y);
|
||||
let idx_b = (e.boss.max(1) as usize - 1) % BOSSES.len();
|
||||
let foe = |o: &Ent| o.alive && !o.held && !o.hero && o.captive == 0 && !o.chained;
|
||||
let near = |o: &Ent, r: f32| (o.x - bx).powi(2) + (o.y - by).powi(2) < r * r;
|
||||
let used = match idx_b {
|
||||
// Sir Aldric: shield wall - heroes around are healed and shielded
|
||||
0 => {
|
||||
for o in self.ents.iter_mut().filter(|o| o.alive && o.hero && (o.x - bx).powi(2) + (o.y - by).powi(2) < 16.0) {
|
||||
o.hp = (o.hp + 60.0).min(o.max_hp);
|
||||
o.shield = o.shield.max(6.0);
|
||||
}
|
||||
self.part(RING, (bx, by, 0.1), (0.0, 0.0, 0.0), 0.7, abgr(255, 230, 140), 4.0);
|
||||
true
|
||||
}
|
||||
// Dame Seraphine: radiant burst - the dungeon's units around are burnt by light
|
||||
1 => {
|
||||
let hit: Vec<usize> = (0..self.ents.len()).filter(|&k| foe(&self.ents[k]) && near(&self.ents[k], 3.0)).collect();
|
||||
if hit.is_empty() {
|
||||
false
|
||||
} else {
|
||||
for k in hit {
|
||||
self.damage_unit(k, 45.0);
|
||||
}
|
||||
self.part(FLASH, (bx, by, 0.5), (0.0, 0.0, 0.0), 0.5, abgr(255, 250, 200), 3.0);
|
||||
true
|
||||
}
|
||||
}
|
||||
// Brother Halvard: call to arms - two knights join him
|
||||
2 => {
|
||||
let level = e.level;
|
||||
for k in 0..2 {
|
||||
let a = k as f32 * 3.1;
|
||||
let id = self.spawn(EK::Knight, true, bx + a.cos(), by + a.sin(), level.max(2) - 1);
|
||||
if let Some(o) = self.ents.iter_mut().find(|o| o.id == id) {
|
||||
o.target = e.target;
|
||||
}
|
||||
}
|
||||
self.fx(4, bx, by, 0.0, 0.0, 0.8, 0xffffe0a0);
|
||||
true
|
||||
}
|
||||
// Captain Rothgar: charge - he rushes at an enemy, hits hard and stuns
|
||||
_ => {
|
||||
let target = (0..self.ents.len()).filter(|&k| foe(&self.ents[k]) && near(&self.ents[k], 6.0)).min_by(|&a, &b| {
|
||||
let da = (self.ents[a].x - bx).powi(2) + (self.ents[a].y - by).powi(2);
|
||||
let db = (self.ents[b].x - bx).powi(2) + (self.ents[b].y - by).powi(2);
|
||||
da.partial_cmp(&db).unwrap_or(std::cmp::Ordering::Equal)
|
||||
});
|
||||
match target {
|
||||
Some(k) => {
|
||||
let (tx, ty) = (self.ents[k].x, self.ents[k].y);
|
||||
let d = ((tx - bx).powi(2) + (ty - by).powi(2)).sqrt().max(0.01);
|
||||
if self.map.walk((tx - (tx - bx) / d * 0.8) as i32, (ty - (ty - by) / d * 0.8) as i32) {
|
||||
e.x = tx - (tx - bx) / d * 0.8;
|
||||
e.y = ty - (ty - by) / d * 0.8;
|
||||
e.path.clear();
|
||||
}
|
||||
self.ents[k].stun = self.ents[k].stun.max(1.5);
|
||||
self.damage_unit(k, 50.0);
|
||||
for _ in 0..10 {
|
||||
let v = (self.vrng.f() * 2.0 - 1.0, self.vrng.f() * 2.0 - 1.0, 0.5);
|
||||
self.parts.push(Part { kind: DEBRIS, x: bx, y: by, h: 0.1, vx: v.0, vy: v.1, vh: v.2, t: 0.0, max: 0.8, col: abgr(150, 130, 110), size: 0.05 });
|
||||
}
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
};
|
||||
e.ab_cd = if used { BOSSES[idx_b].1 } else { 1.0 };
|
||||
}
|
||||
|
||||
// a champion fell (or was captured): his loot
|
||||
pub(crate) fn boss_loot(&mut self, j: usize) {
|
||||
let b = self.ents[j].boss;
|
||||
if b == 0 {
|
||||
return;
|
||||
}
|
||||
self.ents[j].boss = 0;
|
||||
let got = self.add_gold(BOSS_GOLD);
|
||||
self.rune_free += 1;
|
||||
let (x, y) = (self.ents[j].x, self.ents[j].y);
|
||||
self.fx(7, x, y, 0.0, 0.0, 1.2, 0xff40e0ff);
|
||||
self.sfx_ui(Sfx::Victory);
|
||||
self.msg("msg.boss_slain", vec![boss_name(b), (got as i32).to_string()]);
|
||||
}
|
||||
|
||||
// the living champion with the most health (for the bar at the top)
|
||||
pub fn boss_alive(&self) -> Option<&Ent> {
|
||||
self.ents.iter().filter(|e| e.alive && e.boss > 0 && e.captive == 0).max_by(|a, b| a.hp.partial_cmp(&b.hp).unwrap_or(std::cmp::Ordering::Equal))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn every_fifth_wave_brings_a_champion_with_loot() {
|
||||
let mut g = Game::new(8, 80, 64);
|
||||
g.wave = 4; // the next wave is the fifth
|
||||
let before = g.ents.len();
|
||||
g.spawn_wave();
|
||||
let boss = g.ents[before..].iter().position(|e| e.boss > 0).map(|k| k + before).expect("a champion");
|
||||
assert!(g.ents[boss].max_hp > st(g.ents[boss].kind).hp * 2.0);
|
||||
assert!(g.boss_alive().is_some());
|
||||
let (gold, runes) = (g.gold, g.rune_free);
|
||||
g.boss_loot(boss);
|
||||
assert!(g.gold > gold && g.rune_free == runes + 1);
|
||||
assert!(g.boss_alive().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn champions_use_their_abilities() {
|
||||
for b in 1..=4u8 {
|
||||
let mut g = Game::new(8, 80, 64);
|
||||
let (cx, cy) = g.map.core;
|
||||
let (x, y) = (cx as f32 + 1.5, cy as f32 + 4.5);
|
||||
let id = g.spawn(EK::Paladin, true, x, y, 5);
|
||||
let j = g.ents.iter().position(|e| e.id == id).unwrap();
|
||||
g.make_boss(j, b);
|
||||
// an ogre of the dungeon close by
|
||||
g.spawn(EK::Ogre, false, x + 1.5, y, 3);
|
||||
let n0 = g.ents.len();
|
||||
let mut e = g.ents[j].clone();
|
||||
e.ab_cd = 0.0;
|
||||
e.hp = e.max_hp * 0.5;
|
||||
g.boss_ability(&mut e, 0.1);
|
||||
assert!(e.ab_cd > 1.5, "champion {} used his ability", b);
|
||||
if b == 3 {
|
||||
assert_eq!(g.ents.len(), n0 + 2, "two knights joined");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -296,6 +296,8 @@ pub struct Ent {
|
||||
pub target: Option<u8>, // attackers: side whose core (or gate) they march on
|
||||
#[serde(default)]
|
||||
pub chained: bool, // a lone creature chained in a sealed cave: joins when the cave is claimed
|
||||
#[serde(default)]
|
||||
pub boss: u8, // a champion of the Order leading a wave (see bosses.rs), 0: none
|
||||
#[serde(skip, default = "zero_f32")]
|
||||
pub disp_x: f32, // smoothed screen position (not part of the saved or synced world state)
|
||||
#[serde(skip, default = "zero_f32")]
|
||||
@@ -366,6 +368,7 @@ impl Ent {
|
||||
side: 0,
|
||||
target: None,
|
||||
chained: false,
|
||||
boss: 0,
|
||||
disp_x: 0.0,
|
||||
disp_y: 0.0,
|
||||
}
|
||||
@@ -2152,6 +2155,12 @@ impl Game {
|
||||
self.last_wave_value = Self::squad_value(&list);
|
||||
let before = self.ents.len();
|
||||
self.spawn_squad(&list, false);
|
||||
// the paladin of every fifth wave is one of the Order's champions
|
||||
if boss.is_some() {
|
||||
if let Some(j) = (before..self.ents.len()).find(|&j| self.ents[j].kind == Paladin) {
|
||||
self.make_boss(j, 1 + ((w / 5 - 1) % 4) as u8);
|
||||
}
|
||||
}
|
||||
if goal != self.me_side {
|
||||
for e in self.ents[before..].iter_mut() {
|
||||
e.target = Some(goal);
|
||||
@@ -2731,6 +2740,7 @@ impl Game {
|
||||
}
|
||||
|
||||
pub(crate) fn kill(&mut self, j: usize) {
|
||||
self.boss_loot(j);
|
||||
let e = &self.ents[j];
|
||||
if e.hero && e.captive == 0 && self.prison_space() > 0 {
|
||||
// knocked out instead of killed: imps carry the hero to the torture chamber
|
||||
@@ -4450,6 +4460,9 @@ impl Game {
|
||||
// ---------------------------------------------------------------- heroes
|
||||
|
||||
fn hero_ai(&mut self, e: &mut Ent, dt: f32) {
|
||||
if e.boss > 0 {
|
||||
self.boss_ability(e, dt);
|
||||
}
|
||||
if e.kind == EK::Fairy {
|
||||
// fairy dust: the heroes around are healed a little all the time
|
||||
for o in self.ents.iter_mut() {
|
||||
|
||||
@@ -30,6 +30,7 @@ mod save;
|
||||
#[cfg(test)]
|
||||
mod scenes;
|
||||
mod blocks;
|
||||
mod bosses;
|
||||
mod bridges;
|
||||
mod mscript;
|
||||
mod settings;
|
||||
|
||||
+1
-1
@@ -377,7 +377,7 @@ impl Game {
|
||||
true
|
||||
}
|
||||
|
||||
fn damage_unit(&mut self, j: usize, dmg: f32) {
|
||||
pub(crate) fn damage_unit(&mut self, j: usize, dmg: f32) {
|
||||
let o = &mut self.ents[j];
|
||||
o.hp -= dmg;
|
||||
o.flash = 0.15;
|
||||
|
||||
@@ -719,6 +719,18 @@ impl Ui {
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------- a champion of the Order on the field: his name and health under the top bar
|
||||
if let Some(b) = g.boss_alive() {
|
||||
let name = crate::i18n::tr(crate::bosses::boss_name(b.boss).trim_start_matches('@'));
|
||||
let bw = (name.chars().count() as i32 + 26).min(cols - 4);
|
||||
let bx = ((cols - bw) / 2) as f32 * CW();
|
||||
let by = self.hud_h;
|
||||
gfx.window(bx, by, bw, 3, S(), false, RED, BG);
|
||||
gfx.text(&name, bx + CW() * 2.0, by + CH(), S(), GOLD);
|
||||
let bar_cols = (bw - name.chars().count() as i32 - 6).max(6);
|
||||
ascii_bar(gfx, bx + CW() * (name.chars().count() as f32 + 4.0), by + CH(), bar_cols as usize, b.hp / b.max_hp, RED, S());
|
||||
}
|
||||
|
||||
// ---------------- toolbar: buttons of 6 x 3 characters, icons and labels on the grid
|
||||
let tb_rows = 5;
|
||||
let tb_y = sh - tb_rows as f32 * CH();
|
||||
|
||||
Reference in new issue
Block a user