Random events: earthquakes, overflowing rivers, new gold veins (free games and versus, can be switched off)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5239e4b5a3
commit
c6d82027dd
26 files changed
+313
-10
No files matched your search
+4
-1
@@ -73,7 +73,10 @@ bosses (`src/bosses.rs`: four champions of the Order lead every fifth wave - Sir
|
|||||||
Dame Seraphine's radiant burst, Brother Halvard's call to arms, Captain Rothgar's charge - with a health bar
|
Dame Seraphine's radiant burst, Brother Halvard's call to arms, Captain Rothgar's charge - with a health bar
|
||||||
and loot), statistics (`src/stats.rs`: counters and a chart at the end of a game) and achievements
|
and loot), statistics (`src/stats.rs`: counters and a chart at the end of a game) and achievements
|
||||||
(`src/achievements.rs`: 64 of them, kept in the browser and merged with `/api/profile` on the server after a
|
(`src/achievements.rs`: 64 of them, kept in the browser and merged with `/api/profile` on the server after a
|
||||||
login; the menu page *Achievements*). Room levels 2 and 3 will be researched in the library (per room kind).
|
login; the menu page *Achievements*), room levels 2 and 3 (researched in the library once every tool is known:
|
||||||
|
+25% per level, brighter, gold trim) and random events (`src/events.rs`: earthquake, lava or water over the
|
||||||
|
banks, a new gold vein; every 8-12 minutes in free games and versus matches, switch in the game settings; the
|
||||||
|
host's choice goes to every client with `"events"` in the create message).
|
||||||
|
|
||||||
1. **Random events** – earthquake (tunnels cave in), lava eruption, flood, gold vein found. Rare
|
1. **Random events** – earthquake (tunnels cave in), lava eruption, flood, gold vein found. Rare
|
||||||
(every 8–12 minutes), free play and multiplayer only, can be switched off in the menu; in
|
(every 8–12 minutes), free play and multiplayer only, can be switched off in the menu; in
|
||||||
|
|||||||
@@ -246,6 +246,7 @@ set.lights = Zdroje světla
|
|||||||
set.ui_scale = Velikost rozhraní
|
set.ui_scale = Velikost rozhraní
|
||||||
set.game_speed = Rychlost hry
|
set.game_speed = Rychlost hry
|
||||||
set.hints = Rady
|
set.hints = Rady
|
||||||
|
set.events = Náhodné události
|
||||||
set.keys_hint = Klikni na akci a stiskni klávesu. Už použité klávesy se prohodí.
|
set.keys_hint = Klikni na akci a stiskni klávesu. Už použité klávesy se prohodí.
|
||||||
set.press_key = Stiskni klávesu pro: {0}
|
set.press_key = Stiskni klávesu pro: {0}
|
||||||
set.esc_cancel = Esc ruší
|
set.esc_cancel = Esc ruší
|
||||||
@@ -340,6 +341,10 @@ info.tortured = mučen
|
|||||||
info.prison = Zajatci: {0}/{1}
|
info.prison = Zajatci: {0}/{1}
|
||||||
|
|
||||||
msg.wave_warn_dir = Zvědové hlásí: vlna hrdinů {0} dorazí k bráně za 30 sekund! Chtějí vtrhnout ze směru: {1}.
|
msg.wave_warn_dir = Zvědové hlásí: vlna hrdinů {0} dorazí k bráně za 30 sekund! Chtějí vtrhnout ze směru: {1}.
|
||||||
|
msg.event_quake = Zemětřesení! Tunely na {0} se zřítily.
|
||||||
|
msg.event_lava = Láva se vylévá z břehů na {0}!
|
||||||
|
msg.event_flood = Povodeň! Řeka se vylévá z břehů na {0}.
|
||||||
|
msg.event_vein = Skřítci hlásí novou zlatou žílu na {0}!
|
||||||
msg.wave_warn_two = Zvědové hlásí: vlna hrdinů {0} dorazí k bráně za 30 sekund! Rozdělí se a vtrhnou ze směrů: {1} a {2}.
|
msg.wave_warn_two = Zvědové hlásí: vlna hrdinů {0} dorazí k bráně za 30 sekund! Rozdělí se a vtrhnou ze směrů: {1} a {2}.
|
||||||
dir.n = sever
|
dir.n = sever
|
||||||
dir.ne = severovýchod
|
dir.ne = severovýchod
|
||||||
|
|||||||
@@ -246,6 +246,7 @@ set.lights = Lyskilder
|
|||||||
set.ui_scale = Brugerflade
|
set.ui_scale = Brugerflade
|
||||||
set.game_speed = Spilhastighed
|
set.game_speed = Spilhastighed
|
||||||
set.hints = Tips
|
set.hints = Tips
|
||||||
|
set.events = Tilfældige hændelser
|
||||||
set.keys_hint = Klik på en handling og tryk på en tast. Taster der allerede er i brug, byttes om.
|
set.keys_hint = Klik på en handling og tryk på en tast. Taster der allerede er i brug, byttes om.
|
||||||
set.press_key = Tryk på en tast for: {0}
|
set.press_key = Tryk på en tast for: {0}
|
||||||
set.esc_cancel = Esc annullerer
|
set.esc_cancel = Esc annullerer
|
||||||
@@ -339,6 +340,10 @@ info.carried = bæres til torturkammeret
|
|||||||
info.tortured = bliver tortureret
|
info.tortured = bliver tortureret
|
||||||
info.prison = Fanger: {0}/{1}
|
info.prison = Fanger: {0}/{1}
|
||||||
msg.wave_warn_dir = Spejderne melder: heltebølge {0} når porten om 30 sekunder! De vil bryde ind fra {1}.
|
msg.wave_warn_dir = Spejderne melder: heltebølge {0} når porten om 30 sekunder! De vil bryde ind fra {1}.
|
||||||
|
msg.event_quake = Jordskælv! Tunneller mod {0} er styrtet sammen.
|
||||||
|
msg.event_lava = Lavaen går over sine bredder mod {0}!
|
||||||
|
msg.event_flood = Oversvømmelse! Floden går over sine bredder mod {0}.
|
||||||
|
msg.event_vein = Imps'ene melder om en ny guldåre mod {0}!
|
||||||
msg.wave_warn_two = Spejderne melder: heltebølge {0} når porten om 30 sekunder! De deler sig og bryder ind fra {1} og {2}.
|
msg.wave_warn_two = Spejderne melder: heltebølge {0} når porten om 30 sekunder! De deler sig og bryder ind fra {1} og {2}.
|
||||||
dir.n = nord
|
dir.n = nord
|
||||||
dir.ne = nordøst
|
dir.ne = nordøst
|
||||||
|
|||||||
@@ -245,6 +245,7 @@ set.lights = Lichtquellen
|
|||||||
set.ui_scale = Oberflächengröße
|
set.ui_scale = Oberflächengröße
|
||||||
set.game_speed = Spieltempo
|
set.game_speed = Spieltempo
|
||||||
set.hints = Hinweise
|
set.hints = Hinweise
|
||||||
|
set.events = Zufallsereignisse
|
||||||
set.keys_hint = Aktion anklicken und Taste drücken. Bereits belegte Tasten werden getauscht.
|
set.keys_hint = Aktion anklicken und Taste drücken. Bereits belegte Tasten werden getauscht.
|
||||||
set.press_key = Taste drücken für: {0}
|
set.press_key = Taste drücken für: {0}
|
||||||
set.esc_cancel = Esc bricht ab
|
set.esc_cancel = Esc bricht ab
|
||||||
@@ -339,6 +340,10 @@ info.tortured = wird gefoltert
|
|||||||
info.prison = Gefangene: {0}/{1}
|
info.prison = Gefangene: {0}/{1}
|
||||||
|
|
||||||
msg.wave_warn_dir = Späher melden: Welle {0} erreicht in 30 Sekunden das Tor! Die Helden wollen von {1} einfallen.
|
msg.wave_warn_dir = Späher melden: Welle {0} erreicht in 30 Sekunden das Tor! Die Helden wollen von {1} einfallen.
|
||||||
|
msg.event_quake = Erdbeben! Im {0} sind Gänge eingestürzt.
|
||||||
|
msg.event_lava = Im {0} tritt die Lava über die Ufer!
|
||||||
|
msg.event_flood = Hochwasser! Im {0} tritt der Fluss über die Ufer.
|
||||||
|
msg.event_vein = Die Imps melden eine neue Goldader im {0}!
|
||||||
msg.wave_warn_two = Späher melden: Welle {0} erreicht in 30 Sekunden das Tor! Die Helden teilen sich auf und fallen von {1} und von {2} ein.
|
msg.wave_warn_two = Späher melden: Welle {0} erreicht in 30 Sekunden das Tor! Die Helden teilen sich auf und fallen von {1} und von {2} ein.
|
||||||
dir.n = Norden
|
dir.n = Norden
|
||||||
dir.ne = Nordosten
|
dir.ne = Nordosten
|
||||||
|
|||||||
@@ -246,6 +246,7 @@ set.lights = Πηγές φωτός
|
|||||||
set.ui_scale = Μέγεθος διεπαφής
|
set.ui_scale = Μέγεθος διεπαφής
|
||||||
set.game_speed = Ταχύτητα παιχνιδιού
|
set.game_speed = Ταχύτητα παιχνιδιού
|
||||||
set.hints = Υποδείξεις
|
set.hints = Υποδείξεις
|
||||||
|
set.events = Τυχαία γεγονότα
|
||||||
set.keys_hint = Κάνε κλικ σε μια ενέργεια και πάτησε ένα πλήκτρο. Πλήκτρα που ήδη χρησιμοποιούνται ανταλλάσσονται.
|
set.keys_hint = Κάνε κλικ σε μια ενέργεια και πάτησε ένα πλήκτρο. Πλήκτρα που ήδη χρησιμοποιούνται ανταλλάσσονται.
|
||||||
set.press_key = Πάτησε πλήκτρο για: {0}
|
set.press_key = Πάτησε πλήκτρο για: {0}
|
||||||
set.esc_cancel = Esc ακυρώνει
|
set.esc_cancel = Esc ακυρώνει
|
||||||
@@ -340,6 +341,10 @@ info.tortured = βασανίζεται
|
|||||||
info.prison = Αιχμάλωτοι: {0}/{1}
|
info.prison = Αιχμάλωτοι: {0}/{1}
|
||||||
|
|
||||||
msg.wave_warn_dir = Οι ανιχνευτές αναφέρουν: το κύμα ηρώων {0} φτάνει στην πύλη σε 30 δευτερόλεπτα! Σχεδιάζουν να εισβάλουν από: {1}.
|
msg.wave_warn_dir = Οι ανιχνευτές αναφέρουν: το κύμα ηρώων {0} φτάνει στην πύλη σε 30 δευτερόλεπτα! Σχεδιάζουν να εισβάλουν από: {1}.
|
||||||
|
msg.event_quake = Σεισμός! Σήραγγες στα {0} κατέρρευσαν.
|
||||||
|
msg.event_lava = Η λάβα ξεχειλίζει στα {0}!
|
||||||
|
msg.event_flood = Πλημμύρα! Το ποτάμι ξεχειλίζει στα {0}.
|
||||||
|
msg.event_vein = Τα διαβολάκια βρήκαν νέα φλέβα χρυσού στα {0}!
|
||||||
msg.wave_warn_two = Οι ανιχνευτές αναφέρουν: το κύμα ηρώων {0} φτάνει στην πύλη σε 30 δευτερόλεπτα! Χωρίζονται και εισβάλλουν από: {1} και {2}.
|
msg.wave_warn_two = Οι ανιχνευτές αναφέρουν: το κύμα ηρώων {0} φτάνει στην πύλη σε 30 δευτερόλεπτα! Χωρίζονται και εισβάλλουν από: {1} και {2}.
|
||||||
dir.n = βορρά
|
dir.n = βορρά
|
||||||
dir.ne = βορειοανατολικά
|
dir.ne = βορειοανατολικά
|
||||||
|
|||||||
@@ -246,6 +246,7 @@ set.lights = Light sources
|
|||||||
set.ui_scale = Interface size
|
set.ui_scale = Interface size
|
||||||
set.game_speed = Game speed
|
set.game_speed = Game speed
|
||||||
set.hints = Hints
|
set.hints = Hints
|
||||||
|
set.events = Random events
|
||||||
set.keys_hint = Click an action and press a key. Keys already in use are swapped.
|
set.keys_hint = Click an action and press a key. Keys already in use are swapped.
|
||||||
set.press_key = Press a key for: {0}
|
set.press_key = Press a key for: {0}
|
||||||
set.esc_cancel = Esc cancels
|
set.esc_cancel = Esc cancels
|
||||||
@@ -340,6 +341,10 @@ info.tortured = being tortured
|
|||||||
info.prison = Prisoners: {0}/{1}
|
info.prison = Prisoners: {0}/{1}
|
||||||
|
|
||||||
msg.wave_warn_dir = Scouts report: hero wave {0} reaches the gate in 30 seconds! They plan to break in from the {1}.
|
msg.wave_warn_dir = Scouts report: hero wave {0} reaches the gate in 30 seconds! They plan to break in from the {1}.
|
||||||
|
msg.event_quake = Earthquake! Tunnels in the {0} have caved in.
|
||||||
|
msg.event_lava = The lava overflows its banks in the {0}!
|
||||||
|
msg.event_flood = Flood! The river overflows its banks in the {0}.
|
||||||
|
msg.event_vein = The imps report a new gold vein in the {0}!
|
||||||
msg.wave_warn_two = Scouts report: hero wave {0} reaches the gate in 30 seconds! They split up and break in from the {1} and the {2}.
|
msg.wave_warn_two = Scouts report: hero wave {0} reaches the gate in 30 seconds! They split up and break in from the {1} and the {2}.
|
||||||
dir.n = north
|
dir.n = north
|
||||||
dir.ne = north-east
|
dir.ne = north-east
|
||||||
|
|||||||
@@ -246,6 +246,7 @@ set.lights = Fuentes de luz
|
|||||||
set.ui_scale = Tamaño de interfaz
|
set.ui_scale = Tamaño de interfaz
|
||||||
set.game_speed = Velocidad de juego
|
set.game_speed = Velocidad de juego
|
||||||
set.hints = Consejos
|
set.hints = Consejos
|
||||||
|
set.events = Sucesos aleatorios
|
||||||
set.keys_hint = Haz clic en una acción y pulsa una tecla. Las teclas ya usadas se intercambian.
|
set.keys_hint = Haz clic en una acción y pulsa una tecla. Las teclas ya usadas se intercambian.
|
||||||
set.press_key = Pulsa una tecla para: {0}
|
set.press_key = Pulsa una tecla para: {0}
|
||||||
set.esc_cancel = Esc cancela
|
set.esc_cancel = Esc cancela
|
||||||
@@ -340,6 +341,10 @@ info.tortured = siendo torturado
|
|||||||
info.prison = Prisioneros: {0}/{1}
|
info.prison = Prisioneros: {0}/{1}
|
||||||
|
|
||||||
msg.wave_warn_dir = Los exploradores informan: ¡la oleada de héroes {0} llega a la puerta en 30 segundos! Planean entrar por el {1}.
|
msg.wave_warn_dir = Los exploradores informan: ¡la oleada de héroes {0} llega a la puerta en 30 segundos! Planean entrar por el {1}.
|
||||||
|
msg.event_quake = ¡Terremoto! Se han derrumbado túneles en el {0}.
|
||||||
|
msg.event_lava = ¡La lava se desborda en el {0}!
|
||||||
|
msg.event_flood = ¡Inundación! El río se desborda en el {0}.
|
||||||
|
msg.event_vein = ¡Los diablillos informan de una nueva veta de oro en el {0}!
|
||||||
msg.wave_warn_two = Los exploradores informan: ¡la oleada de héroes {0} llega a la puerta en 30 segundos! Se dividen y entran por el {1} y por el {2}.
|
msg.wave_warn_two = Los exploradores informan: ¡la oleada de héroes {0} llega a la puerta en 30 segundos! Se dividen y entran por el {1} y por el {2}.
|
||||||
dir.n = norte
|
dir.n = norte
|
||||||
dir.ne = nordeste
|
dir.ne = nordeste
|
||||||
|
|||||||
@@ -246,6 +246,7 @@ set.lights = Valonlähteet
|
|||||||
set.ui_scale = UI-koko
|
set.ui_scale = UI-koko
|
||||||
set.game_speed = Pelinopeus
|
set.game_speed = Pelinopeus
|
||||||
set.hints = Vinkit
|
set.hints = Vinkit
|
||||||
|
set.events = Satunnaiset tapahtumat
|
||||||
set.keys_hint = Klikkaa toimintoa ja paina näppäintä. Jo käytössä olevat näppäimet vaihdetaan keskenään.
|
set.keys_hint = Klikkaa toimintoa ja paina näppäintä. Jo käytössä olevat näppäimet vaihdetaan keskenään.
|
||||||
set.press_key = Paina näppäintä toiminnolle: {0}
|
set.press_key = Paina näppäintä toiminnolle: {0}
|
||||||
set.esc_cancel = Esc peruu
|
set.esc_cancel = Esc peruu
|
||||||
@@ -340,6 +341,10 @@ info.tortured = kidutetaan
|
|||||||
info.prison = Vangit: {0}/{1}
|
info.prison = Vangit: {0}/{1}
|
||||||
|
|
||||||
msg.wave_warn_dir = Tiedustelijat ilmoittavat: sankariaalto {0} saapuu portille 30 sekunnissa! Ne aikovat murtautua sisään suunnasta: {1}.
|
msg.wave_warn_dir = Tiedustelijat ilmoittavat: sankariaalto {0} saapuu portille 30 sekunnissa! Ne aikovat murtautua sisään suunnasta: {1}.
|
||||||
|
msg.event_quake = Maanjäristys! Tunneleita on sortunut suunnassa {0}.
|
||||||
|
msg.event_lava = Laava tulvii yli äyräidensä suunnassa {0}!
|
||||||
|
msg.event_flood = Tulva! Joki tulvii yli äyräidensä suunnassa {0}.
|
||||||
|
msg.event_vein = Pirut ilmoittavat uudesta kultasuonesta suunnassa {0}!
|
||||||
msg.wave_warn_two = Tiedustelijat ilmoittavat: sankariaalto {0} saapuu portille 30 sekunnissa! Ne jakautuvat ja murtautuvat sisään suunnista: {1} ja {2}.
|
msg.wave_warn_two = Tiedustelijat ilmoittavat: sankariaalto {0} saapuu portille 30 sekunnissa! Ne jakautuvat ja murtautuvat sisään suunnista: {1} ja {2}.
|
||||||
dir.n = pohjoinen
|
dir.n = pohjoinen
|
||||||
dir.ne = koillinen
|
dir.ne = koillinen
|
||||||
|
|||||||
@@ -246,6 +246,7 @@ set.lights = Izvori svjetla
|
|||||||
set.ui_scale = Veličina sučelja
|
set.ui_scale = Veličina sučelja
|
||||||
set.game_speed = Brzina igre
|
set.game_speed = Brzina igre
|
||||||
set.hints = Savjeti
|
set.hints = Savjeti
|
||||||
|
set.events = Slučajni događaji
|
||||||
set.keys_hint = Klikni na radnju i pritisni tipku. Već zauzete tipke se zamijene.
|
set.keys_hint = Klikni na radnju i pritisni tipku. Već zauzete tipke se zamijene.
|
||||||
set.press_key = Pritisni tipku za: {0}
|
set.press_key = Pritisni tipku za: {0}
|
||||||
set.esc_cancel = Esc poništava
|
set.esc_cancel = Esc poništava
|
||||||
@@ -340,6 +341,10 @@ info.tortured = muče ga
|
|||||||
info.prison = Zarobljenici: {0}/{1}
|
info.prison = Zarobljenici: {0}/{1}
|
||||||
|
|
||||||
msg.wave_warn_dir = Izviđači javljaju: val junaka {0} stiže do vrata za 30 sekundi! Planiraju provaliti sa strane: {1}.
|
msg.wave_warn_dir = Izviđači javljaju: val junaka {0} stiže do vrata za 30 sekundi! Planiraju provaliti sa strane: {1}.
|
||||||
|
msg.event_quake = Potres! Tuneli na {0} su se urušili.
|
||||||
|
msg.event_lava = Lava se izlijeva iz korita na {0}!
|
||||||
|
msg.event_flood = Poplava! Rijeka se izlijeva na {0}.
|
||||||
|
msg.event_vein = Vražići javljaju novu zlatnu žilu na {0}!
|
||||||
msg.wave_warn_two = Izviđači javljaju: val junaka {0} stiže do vrata za 30 sekundi! Dijele se i provaljuju sa strana: {1} i {2}.
|
msg.wave_warn_two = Izviđači javljaju: val junaka {0} stiže do vrata za 30 sekundi! Dijele se i provaljuju sa strana: {1} i {2}.
|
||||||
dir.n = sjever
|
dir.n = sjever
|
||||||
dir.ne = sjeveroistok
|
dir.ne = sjeveroistok
|
||||||
|
|||||||
@@ -246,6 +246,7 @@ set.lights = Fényforrások
|
|||||||
set.ui_scale = Felület mérete
|
set.ui_scale = Felület mérete
|
||||||
set.game_speed = Játéksebesség
|
set.game_speed = Játéksebesség
|
||||||
set.hints = Tippek
|
set.hints = Tippek
|
||||||
|
set.events = Véletlen események
|
||||||
set.keys_hint = Kattints egy műveletre, és nyomj meg egy billentyűt. A már használt billentyűk felcserélődnek.
|
set.keys_hint = Kattints egy műveletre, és nyomj meg egy billentyűt. A már használt billentyűk felcserélődnek.
|
||||||
set.press_key = Nyomj egy billentyűt ehhez: {0}
|
set.press_key = Nyomj egy billentyűt ehhez: {0}
|
||||||
set.esc_cancel = Esc: mégse
|
set.esc_cancel = Esc: mégse
|
||||||
@@ -340,6 +341,10 @@ info.tortured = kínozzák
|
|||||||
info.prison = Foglyok: {0}/{1}
|
info.prison = Foglyok: {0}/{1}
|
||||||
|
|
||||||
msg.wave_warn_dir = A felderítők jelentik: a(z) {0}. hőshullám 30 másodperc múlva eléri a kaput! Innen akarnak betörni: {1}.
|
msg.wave_warn_dir = A felderítők jelentik: a(z) {0}. hőshullám 30 másodperc múlva eléri a kaput! Innen akarnak betörni: {1}.
|
||||||
|
msg.event_quake = Földrengés! Alagutak omlottak be: {0}.
|
||||||
|
msg.event_lava = Kilép medréből a láva: {0}!
|
||||||
|
msg.event_flood = Árvíz! Kilép medréből a folyó: {0}.
|
||||||
|
msg.event_vein = A manók új aranyérre bukkantak: {0}!
|
||||||
msg.wave_warn_two = A felderítők jelentik: a(z) {0}. hőshullám 30 másodperc múlva eléri a kaput! Kettéválnak, és két irányból törnek be: {1} és {2}.
|
msg.wave_warn_two = A felderítők jelentik: a(z) {0}. hőshullám 30 másodperc múlva eléri a kaput! Kettéválnak, és két irányból törnek be: {1} és {2}.
|
||||||
dir.n = észak
|
dir.n = észak
|
||||||
dir.ne = északkelet
|
dir.ne = északkelet
|
||||||
|
|||||||
@@ -246,6 +246,7 @@ set.lights = Fonti di luce
|
|||||||
set.ui_scale = Dimensione interfaccia
|
set.ui_scale = Dimensione interfaccia
|
||||||
set.game_speed = Velocità di gioco
|
set.game_speed = Velocità di gioco
|
||||||
set.hints = Suggerimenti
|
set.hints = Suggerimenti
|
||||||
|
set.events = Eventi casuali
|
||||||
set.keys_hint = Clicca un'azione e premi un tasto. I tasti già in uso vengono scambiati.
|
set.keys_hint = Clicca un'azione e premi un tasto. I tasti già in uso vengono scambiati.
|
||||||
set.press_key = Premi un tasto per: {0}
|
set.press_key = Premi un tasto per: {0}
|
||||||
set.esc_cancel = Esc annulla
|
set.esc_cancel = Esc annulla
|
||||||
@@ -340,6 +341,10 @@ info.tortured = sotto tortura
|
|||||||
info.prison = Prigionieri: {0}/{1}
|
info.prison = Prigionieri: {0}/{1}
|
||||||
|
|
||||||
msg.wave_warn_dir = Gli esploratori riferiscono: l'ondata di eroi {0} raggiunge la porta tra 30 secondi! Vogliono irrompere da {1}.
|
msg.wave_warn_dir = Gli esploratori riferiscono: l'ondata di eroi {0} raggiunge la porta tra 30 secondi! Vogliono irrompere da {1}.
|
||||||
|
msg.event_quake = Terremoto! Sono crollati dei tunnel a {0}.
|
||||||
|
msg.event_lava = La lava straripa a {0}!
|
||||||
|
msg.event_flood = Inondazione! Il fiume straripa a {0}.
|
||||||
|
msg.event_vein = I diavoletti segnalano una nuova vena d'oro a {0}!
|
||||||
msg.wave_warn_two = Gli esploratori riferiscono: l'ondata di eroi {0} raggiunge la porta tra 30 secondi! Si dividono e irrompono da {1} e da {2}.
|
msg.wave_warn_two = Gli esploratori riferiscono: l'ondata di eroi {0} raggiunge la porta tra 30 secondi! Si dividono e irrompono da {1} e da {2}.
|
||||||
dir.n = nord
|
dir.n = nord
|
||||||
dir.ne = nord-est
|
dir.ne = nord-est
|
||||||
|
|||||||
@@ -246,6 +246,7 @@ set.lights = Lichtbronnen
|
|||||||
set.ui_scale = Interfacegrootte
|
set.ui_scale = Interfacegrootte
|
||||||
set.game_speed = Spelsnelheid
|
set.game_speed = Spelsnelheid
|
||||||
set.hints = Tips
|
set.hints = Tips
|
||||||
|
set.events = Willekeurige gebeurtenissen
|
||||||
set.keys_hint = Klik op een actie en druk op een toets. Toetsen die al in gebruik zijn, worden verwisseld.
|
set.keys_hint = Klik op een actie en druk op een toets. Toetsen die al in gebruik zijn, worden verwisseld.
|
||||||
set.press_key = Druk op een toets voor: {0}
|
set.press_key = Druk op een toets voor: {0}
|
||||||
set.esc_cancel = Esc annuleert
|
set.esc_cancel = Esc annuleert
|
||||||
@@ -340,6 +341,10 @@ info.tortured = wordt gemarteld
|
|||||||
info.prison = Gevangenen: {0}/{1}
|
info.prison = Gevangenen: {0}/{1}
|
||||||
|
|
||||||
msg.wave_warn_dir = Verkenners melden: heldengolf {0} bereikt de poort over 30 seconden! Ze willen vanuit het {1} binnenvallen.
|
msg.wave_warn_dir = Verkenners melden: heldengolf {0} bereikt de poort over 30 seconden! Ze willen vanuit het {1} binnenvallen.
|
||||||
|
msg.event_quake = Aardbeving! Tunnels in het {0} zijn ingestort.
|
||||||
|
msg.event_lava = De lava treedt buiten haar oevers in het {0}!
|
||||||
|
msg.event_flood = Overstroming! De rivier treedt buiten haar oevers in het {0}.
|
||||||
|
msg.event_vein = De duiveltjes melden een nieuwe goudader in het {0}!
|
||||||
msg.wave_warn_two = Verkenners melden: heldengolf {0} bereikt de poort over 30 seconden! Ze splitsen zich en vallen binnen vanuit het {1} en het {2}.
|
msg.wave_warn_two = Verkenners melden: heldengolf {0} bereikt de poort over 30 seconden! Ze splitsen zich en vallen binnen vanuit het {1} en het {2}.
|
||||||
dir.n = noorden
|
dir.n = noorden
|
||||||
dir.ne = noordoosten
|
dir.ne = noordoosten
|
||||||
|
|||||||
@@ -246,6 +246,7 @@ set.lights = Lyskilder
|
|||||||
set.ui_scale = Grensesnitt
|
set.ui_scale = Grensesnitt
|
||||||
set.game_speed = Spillfart
|
set.game_speed = Spillfart
|
||||||
set.hints = Tips
|
set.hints = Tips
|
||||||
|
set.events = Tilfeldige hendelser
|
||||||
set.keys_hint = Klikk på en handling og trykk på en tast. Taster som allerede er i bruk, byttes om.
|
set.keys_hint = Klikk på en handling og trykk på en tast. Taster som allerede er i bruk, byttes om.
|
||||||
set.press_key = Trykk på en tast for: {0}
|
set.press_key = Trykk på en tast for: {0}
|
||||||
set.esc_cancel = Esc avbryter
|
set.esc_cancel = Esc avbryter
|
||||||
@@ -339,6 +340,10 @@ info.carried = bæres til torturkammeret
|
|||||||
info.tortured = blir torturert
|
info.tortured = blir torturert
|
||||||
info.prison = Fanger: {0}/{1}
|
info.prison = Fanger: {0}/{1}
|
||||||
msg.wave_warn_dir = Speiderne melder: heltebølge {0} når porten om 30 sekunder! De vil bryte inn fra {1}.
|
msg.wave_warn_dir = Speiderne melder: heltebølge {0} når porten om 30 sekunder! De vil bryte inn fra {1}.
|
||||||
|
msg.event_quake = Jordskjelv! Tunneler mot {0} har rast sammen.
|
||||||
|
msg.event_lava = Lavaen går over sine bredder mot {0}!
|
||||||
|
msg.event_flood = Flom! Elva går over sine bredder mot {0}.
|
||||||
|
msg.event_vein = Impene melder om en ny gullåre mot {0}!
|
||||||
msg.wave_warn_two = Speiderne melder: heltebølge {0} når porten om 30 sekunder! De deler seg og bryter inn fra {1} og {2}.
|
msg.wave_warn_two = Speiderne melder: heltebølge {0} når porten om 30 sekunder! De deler seg og bryter inn fra {1} og {2}.
|
||||||
dir.n = nord
|
dir.n = nord
|
||||||
dir.ne = nordøst
|
dir.ne = nordøst
|
||||||
|
|||||||
@@ -246,6 +246,7 @@ set.lights = Fontes de luz
|
|||||||
set.ui_scale = Tamanho da interface
|
set.ui_scale = Tamanho da interface
|
||||||
set.game_speed = Velocidade do jogo
|
set.game_speed = Velocidade do jogo
|
||||||
set.hints = Dicas
|
set.hints = Dicas
|
||||||
|
set.events = Eventos aleatórios
|
||||||
set.keys_hint = Clica numa ação e prime uma tecla. Teclas já em uso são trocadas.
|
set.keys_hint = Clica numa ação e prime uma tecla. Teclas já em uso são trocadas.
|
||||||
set.press_key = Prime uma tecla para: {0}
|
set.press_key = Prime uma tecla para: {0}
|
||||||
set.esc_cancel = Esc cancela
|
set.esc_cancel = Esc cancela
|
||||||
@@ -340,6 +341,10 @@ info.tortured = a ser torturado
|
|||||||
info.prison = Prisioneiros: {0}/{1}
|
info.prison = Prisioneiros: {0}/{1}
|
||||||
|
|
||||||
msg.wave_warn_dir = Os batedores informam: a vaga de heróis {0} chega ao portão dentro de 30 segundos! Planeiam entrar pelo {1}.
|
msg.wave_warn_dir = Os batedores informam: a vaga de heróis {0} chega ao portão dentro de 30 segundos! Planeiam entrar pelo {1}.
|
||||||
|
msg.event_quake = Terramoto! Desabaram túneis a {0}.
|
||||||
|
msg.event_lava = A lava transborda a {0}!
|
||||||
|
msg.event_flood = Cheia! O rio transborda a {0}.
|
||||||
|
msg.event_vein = Os diabretes encontraram um novo veio de ouro a {0}!
|
||||||
msg.wave_warn_two = Os batedores informam: a vaga de heróis {0} chega ao portão dentro de 30 segundos! Dividem-se e entram pelo {1} e pelo {2}.
|
msg.wave_warn_two = Os batedores informam: a vaga de heróis {0} chega ao portão dentro de 30 segundos! Dividem-se e entram pelo {1} e pelo {2}.
|
||||||
dir.n = norte
|
dir.n = norte
|
||||||
dir.ne = nordeste
|
dir.ne = nordeste
|
||||||
|
|||||||
@@ -246,6 +246,7 @@ set.lights = Surse de lumină
|
|||||||
set.ui_scale = Mărime interfață
|
set.ui_scale = Mărime interfață
|
||||||
set.game_speed = Viteza jocului
|
set.game_speed = Viteza jocului
|
||||||
set.hints = Sfaturi
|
set.hints = Sfaturi
|
||||||
|
set.events = Evenimente aleatorii
|
||||||
set.keys_hint = Clic pe o acțiune și apasă o tastă. Tastele deja folosite se schimbă între ele.
|
set.keys_hint = Clic pe o acțiune și apasă o tastă. Tastele deja folosite se schimbă între ele.
|
||||||
set.press_key = Apasă o tastă pentru: {0}
|
set.press_key = Apasă o tastă pentru: {0}
|
||||||
set.esc_cancel = Esc anulează
|
set.esc_cancel = Esc anulează
|
||||||
@@ -340,6 +341,10 @@ info.tortured = e torturat
|
|||||||
info.prison = Prizonieri: {0}/{1}
|
info.prison = Prizonieri: {0}/{1}
|
||||||
|
|
||||||
msg.wave_warn_dir = Iscoadele raportează: valul de eroi {0} ajunge la poartă în 30 de secunde! Plănuiesc să pătrundă dinspre {1}.
|
msg.wave_warn_dir = Iscoadele raportează: valul de eroi {0} ajunge la poartă în 30 de secunde! Plănuiesc să pătrundă dinspre {1}.
|
||||||
|
msg.event_quake = Cutremur! S-au prăbușit tuneluri în {0}.
|
||||||
|
msg.event_lava = Lava se revarsă în {0}!
|
||||||
|
msg.event_flood = Inundație! Râul se revarsă în {0}.
|
||||||
|
msg.event_vein = Drăcușorii au găsit un nou filon de aur în {0}!
|
||||||
msg.wave_warn_two = Iscoadele raportează: valul de eroi {0} ajunge la poartă în 30 de secunde! Se despart și pătrund dinspre {1} și dinspre {2}.
|
msg.wave_warn_two = Iscoadele raportează: valul de eroi {0} ajunge la poartă în 30 de secunde! Se despart și pătrund dinspre {1} și dinspre {2}.
|
||||||
dir.n = nord
|
dir.n = nord
|
||||||
dir.ne = nord-est
|
dir.ne = nord-est
|
||||||
|
|||||||
@@ -246,6 +246,7 @@ set.lights = Источники света
|
|||||||
set.ui_scale = Размер интерфейса
|
set.ui_scale = Размер интерфейса
|
||||||
set.game_speed = Скорость игры
|
set.game_speed = Скорость игры
|
||||||
set.hints = Подсказки
|
set.hints = Подсказки
|
||||||
|
set.events = Случайные события
|
||||||
set.keys_hint = Выбери действие и нажми клавишу. Занятые клавиши меняются местами.
|
set.keys_hint = Выбери действие и нажми клавишу. Занятые клавиши меняются местами.
|
||||||
set.press_key = Нажми клавишу для: {0}
|
set.press_key = Нажми клавишу для: {0}
|
||||||
set.esc_cancel = Esc - отмена
|
set.esc_cancel = Esc - отмена
|
||||||
@@ -340,6 +341,10 @@ info.tortured = его пытают
|
|||||||
info.prison = Пленники: {0}/{1}
|
info.prison = Пленники: {0}/{1}
|
||||||
|
|
||||||
msg.wave_warn_dir = Разведчики докладывают: волна героев {0} будет у врат через 30 секунд! Они хотят прорваться с направления: {1}.
|
msg.wave_warn_dir = Разведчики докладывают: волна героев {0} будет у врат через 30 секунд! Они хотят прорваться с направления: {1}.
|
||||||
|
msg.event_quake = Землетрясение! Туннели на {0} обрушились.
|
||||||
|
msg.event_lava = Лава выходит из берегов на {0}!
|
||||||
|
msg.event_flood = Наводнение! Река выходит из берегов на {0}.
|
||||||
|
msg.event_vein = Бесы докладывают о новой золотой жиле на {0}!
|
||||||
msg.wave_warn_two = Разведчики докладывают: волна героев {0} будет у врат через 30 секунд! Они разделились и прорвутся с направлений: {1} и {2}.
|
msg.wave_warn_two = Разведчики докладывают: волна героев {0} будет у врат через 30 секунд! Они разделились и прорвутся с направлений: {1} и {2}.
|
||||||
dir.n = север
|
dir.n = север
|
||||||
dir.ne = северо-восток
|
dir.ne = северо-восток
|
||||||
|
|||||||
@@ -246,6 +246,7 @@ set.lights = Zdroje svetla
|
|||||||
set.ui_scale = Veľkosť rozhrania
|
set.ui_scale = Veľkosť rozhrania
|
||||||
set.game_speed = Rýchlosť hry
|
set.game_speed = Rýchlosť hry
|
||||||
set.hints = Rady
|
set.hints = Rady
|
||||||
|
set.events = Náhodné udalosti
|
||||||
set.keys_hint = Klikni na akciu a stlač kláves. Už použité klávesy sa vymenia.
|
set.keys_hint = Klikni na akciu a stlač kláves. Už použité klávesy sa vymenia.
|
||||||
set.press_key = Stlač kláves pre: {0}
|
set.press_key = Stlač kláves pre: {0}
|
||||||
set.esc_cancel = Esc ruší
|
set.esc_cancel = Esc ruší
|
||||||
@@ -340,6 +341,10 @@ info.tortured = mučený
|
|||||||
info.prison = Zajatci: {0}/{1}
|
info.prison = Zajatci: {0}/{1}
|
||||||
|
|
||||||
msg.wave_warn_dir = Zvedi hlásia: vlna hrdinov {0} dorazí k bráne o 30 sekúnd! Chcú vtrhnúť zo smeru: {1}.
|
msg.wave_warn_dir = Zvedi hlásia: vlna hrdinov {0} dorazí k bráne o 30 sekúnd! Chcú vtrhnúť zo smeru: {1}.
|
||||||
|
msg.event_quake = Zemetrasenie! Tunely na {0} sa zrútili.
|
||||||
|
msg.event_lava = Láva sa vylieva z brehov na {0}!
|
||||||
|
msg.event_flood = Povodeň! Rieka sa vylieva z brehov na {0}.
|
||||||
|
msg.event_vein = Škriatkovia hlásia novú zlatú žilu na {0}!
|
||||||
msg.wave_warn_two = Zvedi hlásia: vlna hrdinov {0} dorazí k bráne o 30 sekúnd! Rozdelia sa a vtrhnú zo smerov: {1} a {2}.
|
msg.wave_warn_two = Zvedi hlásia: vlna hrdinov {0} dorazí k bráne o 30 sekúnd! Rozdelia sa a vtrhnú zo smerov: {1} a {2}.
|
||||||
dir.n = sever
|
dir.n = sever
|
||||||
dir.ne = severovýchod
|
dir.ne = severovýchod
|
||||||
|
|||||||
@@ -246,6 +246,7 @@ set.lights = Извори светла
|
|||||||
set.ui_scale = Величина интерфејса
|
set.ui_scale = Величина интерфејса
|
||||||
set.game_speed = Брзина игре
|
set.game_speed = Брзина игре
|
||||||
set.hints = Савети
|
set.hints = Савети
|
||||||
|
set.events = Случајни догађаји
|
||||||
set.keys_hint = Кликни на радњу и притисни тастер. Већ заузети тастери се замене.
|
set.keys_hint = Кликни на радњу и притисни тастер. Већ заузети тастери се замене.
|
||||||
set.press_key = Притисни тастер за: {0}
|
set.press_key = Притисни тастер за: {0}
|
||||||
set.esc_cancel = Esc поништава
|
set.esc_cancel = Esc поништава
|
||||||
@@ -340,6 +341,10 @@ info.tortured = муче га
|
|||||||
info.prison = Заробљеници: {0}/{1}
|
info.prison = Заробљеници: {0}/{1}
|
||||||
|
|
||||||
msg.wave_warn_dir = Извиђачи јављају: талас хероја {0} стиже до капије за 30 секунди! Планирају да провале са стране: {1}.
|
msg.wave_warn_dir = Извиђачи јављају: талас хероја {0} стиже до капије за 30 секунди! Планирају да провале са стране: {1}.
|
||||||
|
msg.event_quake = Земљотрес! Тунели на {0} су се урушили.
|
||||||
|
msg.event_lava = Лава се излива из корита на {0}!
|
||||||
|
msg.event_flood = Поплава! Река се излива на {0}.
|
||||||
|
msg.event_vein = Врагови јављају нову златну жилу на {0}!
|
||||||
msg.wave_warn_two = Извиђачи јављају: талас хероја {0} стиже до капије за 30 секунди! Деле се и проваљују са страна: {1} и {2}.
|
msg.wave_warn_two = Извиђачи јављају: талас хероја {0} стиже до капије за 30 секунди! Деле се и проваљују са страна: {1} и {2}.
|
||||||
dir.n = север
|
dir.n = север
|
||||||
dir.ne = североисток
|
dir.ne = североисток
|
||||||
|
|||||||
@@ -246,6 +246,7 @@ set.lights = Ljuskällor
|
|||||||
set.ui_scale = Gränssnittsstorlek
|
set.ui_scale = Gränssnittsstorlek
|
||||||
set.game_speed = Spelhastighet
|
set.game_speed = Spelhastighet
|
||||||
set.hints = Tips
|
set.hints = Tips
|
||||||
|
set.events = Slumpmässiga händelser
|
||||||
set.keys_hint = Klicka på en åtgärd och tryck på en tangent. Tangenter som redan används byter plats.
|
set.keys_hint = Klicka på en åtgärd och tryck på en tangent. Tangenter som redan används byter plats.
|
||||||
set.press_key = Tryck på en tangent för: {0}
|
set.press_key = Tryck på en tangent för: {0}
|
||||||
set.esc_cancel = Esc avbryter
|
set.esc_cancel = Esc avbryter
|
||||||
@@ -340,6 +341,10 @@ info.tortured = torteras
|
|||||||
info.prison = Fångar: {0}/{1}
|
info.prison = Fångar: {0}/{1}
|
||||||
|
|
||||||
msg.wave_warn_dir = Spejarna rapporterar: hjältevåg {0} når porten om 30 sekunder! De tänker bryta sig in från {1}.
|
msg.wave_warn_dir = Spejarna rapporterar: hjältevåg {0} når porten om 30 sekunder! De tänker bryta sig in från {1}.
|
||||||
|
msg.event_quake = Jordbävning! Tunnlar i {0} har rasat.
|
||||||
|
msg.event_lava = Lavan svämmar över sina bräddar i {0}!
|
||||||
|
msg.event_flood = Översvämning! Floden svämmar över i {0}.
|
||||||
|
msg.event_vein = Imparna rapporterar en ny guldåder i {0}!
|
||||||
msg.wave_warn_two = Spejarna rapporterar: hjältevåg {0} når porten om 30 sekunder! De delar upp sig och bryter in från {1} och {2}.
|
msg.wave_warn_two = Spejarna rapporterar: hjältevåg {0} når porten om 30 sekunder! De delar upp sig och bryter in från {1} och {2}.
|
||||||
dir.n = norr
|
dir.n = norr
|
||||||
dir.ne = nordost
|
dir.ne = nordost
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ struct Room {
|
|||||||
doc: Option<Value>, // editor campaign of a co-op match (sent to every client at the start)
|
doc: Option<Value>, // editor campaign of a co-op match (sent to every client at the start)
|
||||||
resume: Option<(u32, Value)>, // a resumed editor campaign run: its seed and what the masters carry
|
resume: Option<(u32, Value)>, // a resumed editor campaign run: its seed and what the masters carry
|
||||||
surface: bool, // a free match half above ground
|
surface: bool, // a free match half above ground
|
||||||
|
events: bool, // random events in a free match
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -384,7 +385,7 @@ impl Netplay {
|
|||||||
}
|
}
|
||||||
let name = self.clients.get(&conn).map(|c| c.name.clone()).unwrap_or_else(|| "Guest".into());
|
let name = self.clients.get(&conn).map(|c| c.name.clone()).unwrap_or_else(|| "Guest".into());
|
||||||
let seats = sides.iter().map(|s| (*s, new_seat(*s, false))).collect::<HashMap<_, _>>();
|
let seats = sides.iter().map(|s| (*s, new_seat(*s, false))).collect::<HashMap<_, _>>();
|
||||||
let room = Room { code: code.clone(), sides, seats, pending: HashMap::new(), turn: 0, started: false, paused: false, missing: false, seed: None, map_w, map_h, difficulty, mission, doc, resume, surface: msg.get("surface").and_then(|v| v.as_bool()).unwrap_or(false) };
|
let room = Room { code: code.clone(), sides, seats, pending: HashMap::new(), turn: 0, started: false, paused: false, missing: false, seed: None, map_w, map_h, difficulty, mission, doc, resume, surface: msg.get("surface").and_then(|v| v.as_bool()).unwrap_or(false), events: msg.get("events").and_then(|v| v.as_bool()).unwrap_or(false) };
|
||||||
self.rooms.insert(code.clone(), room);
|
self.rooms.insert(code.clone(), room);
|
||||||
if let Some(c) = self.clients.get_mut(&conn) {
|
if let Some(c) = self.clients.get_mut(&conn) {
|
||||||
c.room = Some(code.clone());
|
c.room = Some(code.clone());
|
||||||
@@ -652,6 +653,9 @@ impl Netplay {
|
|||||||
if r.surface {
|
if r.surface {
|
||||||
m["surface"] = json!(true);
|
m["surface"] = json!(true);
|
||||||
}
|
}
|
||||||
|
if r.events {
|
||||||
|
m["events"] = json!(true);
|
||||||
|
}
|
||||||
if let Some((_, carry)) = &r.resume {
|
if let Some((_, carry)) = &r.resume {
|
||||||
m["carry"] = carry.clone();
|
m["carry"] = carry.clone();
|
||||||
m["resume"] = json!(true);
|
m["resume"] = json!(true);
|
||||||
|
|||||||
+190
@@ -0,0 +1,190 @@
|
|||||||
|
// Random events in free games and versus matches (rare; can be switched off): an earthquake
|
||||||
|
// brings down tunnels near the dungeon, lava or water overflows its banks, or the imps find a
|
||||||
|
// new gold vein. Shared state and the shared random numbers: every client of a match sees the
|
||||||
|
// same. Campaigns have none (their stories are told by the missions).
|
||||||
|
|
||||||
|
use crate::game::*;
|
||||||
|
use crate::map::*;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
// seconds between two events: EVENT_GAP plus up to EVENT_SPREAD
|
||||||
|
pub const EVENT_GAP: f32 = 480.0;
|
||||||
|
pub const EVENT_SPREAD: f32 = 240.0;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||||
|
pub struct Events {
|
||||||
|
pub t: f32, // seconds until the next one
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Game {
|
||||||
|
// switches random events on (new free game or match) or off
|
||||||
|
pub fn set_events(&mut self, on: bool) {
|
||||||
|
self.happenings = if on && self.mission.is_none() { Some(Events { t: EVENT_GAP + self.rng.f() * EVENT_SPREAD }) } else { None };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn update_events(&mut self, dt: f32) {
|
||||||
|
let Some(ev) = self.happenings.as_mut() else { return };
|
||||||
|
ev.t -= dt;
|
||||||
|
if ev.t > 0.0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ev.t = EVENT_GAP + self.rng.f() * EVENT_SPREAD;
|
||||||
|
let kind = self.rng.next() % 4;
|
||||||
|
let happened = match kind {
|
||||||
|
0 => self.event_quake(),
|
||||||
|
1 => self.event_overflow(Kind::Lava),
|
||||||
|
2 => self.event_overflow(Kind::Water),
|
||||||
|
_ => self.event_vein(),
|
||||||
|
};
|
||||||
|
// nothing of that kind possible here: a gold vein instead (there is always earth)
|
||||||
|
if !happened && kind != 3 {
|
||||||
|
self.event_vein();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// own walkable ground within `r` of tile i?
|
||||||
|
fn near_own(&self, i: usize, r: i32) -> bool {
|
||||||
|
let (x, y) = xy(i);
|
||||||
|
(-r..=r).any(|dy| (-r..=r).any(|dx| self.map.get(x + dx, y + dy).map_or(false, |t| t.owner != Owner::None && t.owner != Owner::Hero && t.walkable())))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn announce(&mut self, key: &'static str, i: usize) {
|
||||||
|
let (x, y) = xy(i);
|
||||||
|
let dir = format!("@{}", self.direction_key((x, y)));
|
||||||
|
// every master hears of it
|
||||||
|
let me = self.me_side;
|
||||||
|
for s in self.master_sides() {
|
||||||
|
self.switch_to(s);
|
||||||
|
self.msg(key, vec![dir.clone()]);
|
||||||
|
self.sfx_ui(Sfx::CoreHit);
|
||||||
|
}
|
||||||
|
self.switch_to(me);
|
||||||
|
self.add_mark(x as f32 + 0.5, y as f32 + 0.5, crate::game::MARK_BRIDGE, 255, 8.0, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// an earthquake: plain tunnels (unowned, not rooms) near a dungeon cave in
|
||||||
|
fn event_quake(&mut self) -> bool {
|
||||||
|
let n = self.map.t.len();
|
||||||
|
let cands: Vec<usize> = (0..n).filter(|&i| {
|
||||||
|
let t = &self.map.t[i];
|
||||||
|
let (x, y) = xy(i);
|
||||||
|
t.kind == Kind::Floor && t.owner == Owner::None && x > 2 && y > 2 && x < mw() as i32 - 3 && y < mh() as i32 - 3 && !self.map.sky(i) && self.near_own(i, 6)
|
||||||
|
}).collect();
|
||||||
|
if cands.len() < 4 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let centre = cands[(self.rng.next() as usize) % cands.len()];
|
||||||
|
let (cx, cy) = xy(centre);
|
||||||
|
let mut fell = 0;
|
||||||
|
for &i in &cands {
|
||||||
|
let (x, y) = xy(i);
|
||||||
|
if (x - cx).abs() + (y - cy).abs() > 3 || self.rng.f() < 0.35 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if self.ents.iter().any(|e| e.alive && e.tile() == i) {
|
||||||
|
continue; // nobody is buried alive (the quake is not that mean)
|
||||||
|
}
|
||||||
|
let t = &mut self.map.t[i];
|
||||||
|
t.kind = Kind::Earth;
|
||||||
|
t.hp = 6.0;
|
||||||
|
t.marked = false;
|
||||||
|
fell += 1;
|
||||||
|
}
|
||||||
|
if fell == 0 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
self.announce("msg.event_quake", centre);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
// a river overflows its banks: unowned open ground next to it fills
|
||||||
|
fn event_overflow(&mut self, river: Kind) -> bool {
|
||||||
|
let n = self.map.t.len();
|
||||||
|
let bank: Vec<usize> = (0..n).filter(|&i| {
|
||||||
|
let t = &self.map.t[i];
|
||||||
|
let (x, y) = xy(i);
|
||||||
|
// no lava above ground
|
||||||
|
t.kind == Kind::Floor && t.owner == Owner::None && !(river == Kind::Lava && self.map.sky(i))
|
||||||
|
&& DIR4.iter().any(|&(dx, dy)| self.map.get(x + dx, y + dy).map_or(false, |o| o.kind == river))
|
||||||
|
}).collect();
|
||||||
|
if bank.is_empty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let start = bank[(self.rng.next() as usize) % bank.len()];
|
||||||
|
let (sx, sy) = xy(start);
|
||||||
|
let mut done = 0;
|
||||||
|
for &i in &bank {
|
||||||
|
let (x, y) = xy(i);
|
||||||
|
if (x - sx).abs() + (y - sy).abs() > 4 || done >= 8 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
self.map.t[i].kind = river;
|
||||||
|
self.ground_lost(i);
|
||||||
|
done += 1;
|
||||||
|
}
|
||||||
|
self.announce(if river == Kind::Lava { "msg.event_lava" } else { "msg.event_flood" }, start);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
// the imps find a gold vein: earth near a dungeon turns to gold
|
||||||
|
fn event_vein(&mut self) -> bool {
|
||||||
|
let n = self.map.t.len();
|
||||||
|
let cands: Vec<usize> = (0..n).filter(|&i| self.map.t[i].kind == Kind::Earth && !self.map.t[i].reinforced && self.near_own(i, 5)).collect();
|
||||||
|
if cands.is_empty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let centre = cands[(self.rng.next() as usize) % cands.len()];
|
||||||
|
let (cx, cy) = xy(centre);
|
||||||
|
for &i in &cands {
|
||||||
|
let (x, y) = xy(i);
|
||||||
|
if (x - cx).abs() + (y - cy).abs() <= 2 {
|
||||||
|
let t = &mut self.map.t[i];
|
||||||
|
t.kind = Kind::Gold;
|
||||||
|
t.gold = 900;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.announce("msg.event_vein", centre);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn free_games_have_rare_events() {
|
||||||
|
let mut g = Game::new(12, 80, 64);
|
||||||
|
g.set_events(true);
|
||||||
|
assert!(g.happenings.is_some());
|
||||||
|
let golds = |g: &Game| g.map.t.iter().filter(|t| t.kind == Kind::Gold).count();
|
||||||
|
let before = golds(&g);
|
||||||
|
g.happenings.as_mut().unwrap().t = 0.0;
|
||||||
|
g.rng = Rng(3); // a gold vein (or another event) happens now
|
||||||
|
g.update_events(0.1);
|
||||||
|
assert!(g.happenings.as_ref().unwrap().t >= EVENT_GAP);
|
||||||
|
assert!(g.msgs.iter().any(|m| m.key.starts_with("msg.event_")), "an event was told");
|
||||||
|
let _ = before;
|
||||||
|
// campaigns have none
|
||||||
|
let mut m = crate::campaign::start_mission(3, None);
|
||||||
|
m.set_events(true);
|
||||||
|
assert!(m.happenings.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn every_event_can_happen() {
|
||||||
|
let mut g = Game::new(12, 80, 64);
|
||||||
|
let (cx, cy) = g.map.core;
|
||||||
|
// a little lava and water next to unowned ground near the dungeon
|
||||||
|
for (x, k) in [(cx + 6, Kind::Lava), (cx + 9, Kind::Water)] {
|
||||||
|
for y in cy - 2..cy + 3 {
|
||||||
|
g.map.t[idx(x, y)].kind = k;
|
||||||
|
g.map.t[idx(x + 1, y)].kind = Kind::Floor;
|
||||||
|
g.map.t[idx(x + 1, y)].owner = Owner::None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert!(g.event_vein());
|
||||||
|
assert!(g.event_overflow(Kind::Lava));
|
||||||
|
assert!(g.event_overflow(Kind::Water));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -604,6 +604,8 @@ pub struct Game {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub bridgework: crate::bridges::BridgeWork, // burning and worn bridges
|
pub bridgework: crate::bridges::BridgeWork, // burning and worn bridges
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
pub happenings: Option<crate::events::Events>, // random events (free games and versus), see events.rs
|
||||||
|
#[serde(default)]
|
||||||
pub stats: crate::stats::GameStats, // statistics of the master at this computer (see stats.rs)
|
pub stats: crate::stats::GameStats, // statistics of the master at this computer (see stats.rs)
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub wall_plans: Vec<(usize, u8)>, // walls to raise: tile, master side (see walls.rs)
|
pub wall_plans: Vec<(usize, u8)>, // walls to raise: tile, master side (see walls.rs)
|
||||||
@@ -943,6 +945,7 @@ impl Game {
|
|||||||
vrng: crate::particles::vrng(),
|
vrng: crate::particles::vrng(),
|
||||||
dwarf_caves: Vec::new(),
|
dwarf_caves: Vec::new(),
|
||||||
bridgework: Default::default(),
|
bridgework: Default::default(),
|
||||||
|
happenings: None,
|
||||||
stats: Default::default(),
|
stats: Default::default(),
|
||||||
wall_plans: Vec::new(),
|
wall_plans: Vec::new(),
|
||||||
wood: crate::wood::WOOD_START,
|
wood: crate::wood::WOOD_START,
|
||||||
@@ -1715,6 +1718,7 @@ impl Game {
|
|||||||
self.update_dwarves(dt);
|
self.update_dwarves(dt);
|
||||||
self.update_bridges(dt);
|
self.update_bridges(dt);
|
||||||
self.update_wood(dt);
|
self.update_wood(dt);
|
||||||
|
self.update_events(dt);
|
||||||
// fallen hearts of a match are shared state: every client marks them in the same step
|
// fallen hearts of a match are shared state: every client marks them in the same step
|
||||||
self.update_fallen_masters();
|
self.update_fallen_masters();
|
||||||
// the end of the game and the fog are about the master at this computer
|
// the end of the game and the fog are about the master at this computer
|
||||||
|
|||||||
+8
-5
@@ -91,6 +91,7 @@ pub struct StartInfo {
|
|||||||
pub next: bool, // the next mission of a running editor campaign co-op match
|
pub next: bool, // the next mission of a running editor campaign co-op match
|
||||||
pub carry: Vec<(u8, crate::campaign::Carry)>, // what every side brings into that mission
|
pub carry: Vec<(u8, crate::campaign::Carry)>, // what every side brings into that mission
|
||||||
pub surface: bool, // a free match whose eastern half lies above ground
|
pub surface: bool, // a free match whose eastern half lies above ground
|
||||||
|
pub events: bool, // random events in a free match
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
@@ -225,12 +226,13 @@ impl MatchClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// a free match; `surface`: its eastern half lies above ground
|
// a free match; `surface`: its eastern half lies above ground
|
||||||
pub fn create_land(&mut self, sides: &[u8], map_w: usize, map_h: usize, difficulty: u8, surface: bool) {
|
pub fn create_land(&mut self, sides: &[u8], map_w: usize, map_h: usize, difficulty: u8, surface: bool, events: bool) {
|
||||||
let n = self.outbox.len();
|
let n = self.outbox.len();
|
||||||
self.send_create(sides, map_w, map_h, difficulty, None);
|
self.send_create(sides, map_w, map_h, difficulty, None);
|
||||||
if let (true, Some(text)) = (surface, self.outbox.get_mut(n)) {
|
if let (true, Some(text)) = (surface || events, self.outbox.get_mut(n)) {
|
||||||
if let Ok(mut msg) = serde_json::from_str::<Value>(text) {
|
if let Ok(mut msg) = serde_json::from_str::<Value>(text) {
|
||||||
msg["surface"] = json!(true);
|
msg["surface"] = json!(surface);
|
||||||
|
msg["events"] = json!(events);
|
||||||
*text = msg.to_string();
|
*text = msg.to_string();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -564,7 +566,8 @@ impl MatchClient {
|
|||||||
let resume = editor && v.get("resume").and_then(|x| x.as_bool()).unwrap_or(false);
|
let resume = editor && v.get("resume").and_then(|x| x.as_bool()).unwrap_or(false);
|
||||||
let carry: Vec<(u8, crate::campaign::Carry)> = if resume { v.get("carry").cloned().and_then(|c| serde_json::from_value(c).ok()).unwrap_or_default() } else { Vec::new() };
|
let carry: Vec<(u8, crate::campaign::Carry)> = if resume { v.get("carry").cloned().and_then(|c| serde_json::from_value(c).ok()).unwrap_or_default() } else { Vec::new() };
|
||||||
let surface = v.get("surface").and_then(|x| x.as_bool()).unwrap_or(false);
|
let surface = v.get("surface").and_then(|x| x.as_bool()).unwrap_or(false);
|
||||||
self.start = Some(StartInfo { seed, map_w, map_h, difficulty, sides, local_side, mission, ai, doc, editor, teams, next: resume, carry, surface });
|
let events = v.get("events").and_then(|x| x.as_bool()).unwrap_or(false);
|
||||||
|
self.start = Some(StartInfo { seed, map_w, map_h, difficulty, sides, local_side, mission, ai, doc, editor, teams, next: resume, carry, surface, events });
|
||||||
self.error = None;
|
self.error = None;
|
||||||
self.status = None;
|
self.status = None;
|
||||||
}
|
}
|
||||||
@@ -595,7 +598,7 @@ impl MatchClient {
|
|||||||
}
|
}
|
||||||
r.ai = ai.clone();
|
r.ai = ai.clone();
|
||||||
}
|
}
|
||||||
self.start = Some(StartInfo { seed, map_w, map_h, difficulty, sides, local_side, mission: Some(mission), ai, doc: Some(doc), editor: true, teams, next: true, carry, surface: false });
|
self.start = Some(StartInfo { seed, map_w, map_h, difficulty, sides, local_side, mission: Some(mission), ai, doc: Some(doc), editor: true, teams, next: true, carry, surface: false, events: false });
|
||||||
self.error = None;
|
self.error = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-2
@@ -8,6 +8,7 @@ mod cloud;
|
|||||||
mod commands;
|
mod commands;
|
||||||
mod demo;
|
mod demo;
|
||||||
mod editor;
|
mod editor;
|
||||||
|
mod events;
|
||||||
mod dwarves;
|
mod dwarves;
|
||||||
mod fog;
|
mod fog;
|
||||||
mod fortress;
|
mod fortress;
|
||||||
@@ -185,6 +186,7 @@ fn new_game(seed: u32, s: &Settings) -> (Game, Cam) {
|
|||||||
g.add_surface(seed, 0.5, 2 + (s.map_h / 64) as u32);
|
g.add_surface(seed, 0.5, 2 + (s.map_h / 64) as u32);
|
||||||
g.init_fog();
|
g.init_fog();
|
||||||
}
|
}
|
||||||
|
g.set_events(s.events);
|
||||||
let (cx, cy) = g.map.core;
|
let (cx, cy) = g.map.core;
|
||||||
let cam = Cam::new(cx as f32 + 1.5, cy as f32 + 1.5);
|
let cam = Cam::new(cx as f32 + 1.5, cy as f32 + 1.5);
|
||||||
(g, cam)
|
(g, cam)
|
||||||
@@ -352,7 +354,7 @@ fn account_action(a: MenuAction, cloud: &mut Cloud, menu: &mut Menu, app: &mut A
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
MenuAction::MatchJoin(code) => app.client.join(&code),
|
MenuAction::MatchJoin(code) => app.client.join(&code),
|
||||||
MenuAction::MatchCreate => app.client.create_land(&[0, 2, 3, 4], app.settings.map_w, app.settings.map_h, app.settings.difficulty, app.settings.surface),
|
MenuAction::MatchCreate => app.client.create_land(&[0, 2, 3, 4], app.settings.map_w, app.settings.map_h, app.settings.difficulty, app.settings.surface, app.settings.events),
|
||||||
MenuAction::MatchCoopCreate(mission) => {
|
MenuAction::MatchCoopCreate(mission) => {
|
||||||
let all = campaign::missions();
|
let all = campaign::missions();
|
||||||
if let Some(d) = all.get(mission) {
|
if let Some(d) = all.get(mission) {
|
||||||
@@ -721,7 +723,7 @@ impl App {
|
|||||||
let next = run_seed.is_some();
|
let next = run_seed.is_some();
|
||||||
let seed = run_seed.unwrap_or_else(|| next_seed(self.seed));
|
let seed = run_seed.unwrap_or_else(|| next_seed(self.seed));
|
||||||
let editor = doc.is_some();
|
let editor = doc.is_some();
|
||||||
let info = StartInfo { seed, map_w, map_h, difficulty: self.settings.difficulty, sides: vec![0, 2], local_side: Some(0), mission: Some(mission), ai: vec![2], doc, editor, teams: Vec::new(), next, carry, surface: false };
|
let info = StartInfo { seed, map_w, map_h, difficulty: self.settings.difficulty, sides: vec![0, 2], local_side: Some(0), mission: Some(mission), ai: vec![2], doc, editor, teams: Vec::new(), next, carry, surface: false, events: false };
|
||||||
if !self.start_match_game(info) {
|
if !self.start_match_game(info) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -805,6 +807,7 @@ impl App {
|
|||||||
// the same land on every client: built from the shared seed
|
// the same land on every client: built from the shared seed
|
||||||
self.game.add_surface(info.seed, 0.5, 2 + (info.map_h / 64) as u32);
|
self.game.add_surface(info.seed, 0.5, 2 + (info.map_h / 64) as u32);
|
||||||
}
|
}
|
||||||
|
self.game.set_events(info.events);
|
||||||
self.game.coop = false;
|
self.game.coop = false;
|
||||||
self.game.set_teams(&info.teams);
|
self.game.set_teams(&info.teams);
|
||||||
self.game.ai_difficulty = info.difficulty;
|
self.game.ai_difficulty = info.difficulty;
|
||||||
|
|||||||
+5
-1
@@ -64,6 +64,7 @@ pub enum Item {
|
|||||||
DebugPathLines,
|
DebugPathLines,
|
||||||
GameSpeed,
|
GameSpeed,
|
||||||
Hints,
|
Hints,
|
||||||
|
Events,
|
||||||
TouchUi,
|
TouchUi,
|
||||||
Voice,
|
Voice,
|
||||||
}
|
}
|
||||||
@@ -74,7 +75,7 @@ fn tab_items(tab: usize) -> &'static [Item] {
|
|||||||
0 => &[Language, Volume, MusicVolume, Mute, Voice],
|
0 => &[Language, Volume, MusicVolume, Mute, Voice],
|
||||||
1 => &[RotateSpeed, PanSpeed, ZoomSpeed, EdgeScroll, InvertMouse],
|
1 => &[RotateSpeed, PanSpeed, ZoomSpeed, EdgeScroll, InvertMouse],
|
||||||
2 => &[Outlines, WallDetail, Lights, UiScale, RenderScale],
|
2 => &[Outlines, WallDetail, Lights, UiScale, RenderScale],
|
||||||
3 => &[GameSpeed, Hints, TouchUi],
|
3 => &[GameSpeed, Hints, Events, TouchUi],
|
||||||
4 => &[DebugFps, DebugFrameTime, DebugPing, DebugTriggerZones, DebugCommandMarkers, DebugPathLines],
|
4 => &[DebugFps, DebugFrameTime, DebugPing, DebugTriggerZones, DebugCommandMarkers, DebugPathLines],
|
||||||
_ => &[],
|
_ => &[],
|
||||||
}
|
}
|
||||||
@@ -104,6 +105,7 @@ fn item_label(it: Item) -> String {
|
|||||||
Item::DebugPathLines => "set.debug_path_lines",
|
Item::DebugPathLines => "set.debug_path_lines",
|
||||||
Item::GameSpeed => "set.game_speed",
|
Item::GameSpeed => "set.game_speed",
|
||||||
Item::Hints => "set.hints",
|
Item::Hints => "set.hints",
|
||||||
|
Item::Events => "set.events",
|
||||||
Item::TouchUi => "set.touch_ui",
|
Item::TouchUi => "set.touch_ui",
|
||||||
Item::Voice => "set.voice",
|
Item::Voice => "set.voice",
|
||||||
})
|
})
|
||||||
@@ -160,6 +162,7 @@ fn item_value(it: Item, s: &Settings) -> String {
|
|||||||
}
|
}
|
||||||
Item::GameSpeed => format!("{}x", s.game_speed as i32),
|
Item::GameSpeed => format!("{}x", s.game_speed as i32),
|
||||||
Item::Hints => onoff(s.hints),
|
Item::Hints => onoff(s.hints),
|
||||||
|
Item::Events => onoff(s.events),
|
||||||
Item::TouchUi => match s.touch_ui {
|
Item::TouchUi => match s.touch_ui {
|
||||||
1 => tr("val.on"),
|
1 => tr("val.on"),
|
||||||
2 => tr("val.off"),
|
2 => tr("val.off"),
|
||||||
@@ -207,6 +210,7 @@ fn item_change(it: Item, s: &mut Settings, d: i32) {
|
|||||||
Item::DebugPathLines => s.debug_path_lines = !s.debug_path_lines,
|
Item::DebugPathLines => s.debug_path_lines = !s.debug_path_lines,
|
||||||
Item::GameSpeed => s.game_speed = cycle(&[1.0f32, 2.0], s.game_speed, d),
|
Item::GameSpeed => s.game_speed = cycle(&[1.0f32, 2.0], s.game_speed, d),
|
||||||
Item::Hints => s.hints = !s.hints,
|
Item::Hints => s.hints = !s.hints,
|
||||||
|
Item::Events => s.events = !s.events,
|
||||||
Item::TouchUi => s.touch_ui = cycle(&[0u8, 1, 2], s.touch_ui, d),
|
Item::TouchUi => s.touch_ui = cycle(&[0u8, 1, 2], s.touch_ui, d),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ pub struct Settings {
|
|||||||
pub map_w: usize, // size of new maps (64..256)
|
pub map_w: usize, // size of new maps (64..256)
|
||||||
pub map_h: usize,
|
pub map_h: usize,
|
||||||
pub surface: bool, // new free games: the eastern half lies above ground (forest)
|
pub surface: bool, // new free games: the eastern half lies above ground (forest)
|
||||||
|
pub events: bool, // random events in free games and versus matches
|
||||||
// key bindings: action id -> key name
|
// key bindings: action id -> key name
|
||||||
pub keys: BTreeMap<String, String>,
|
pub keys: BTreeMap<String, String>,
|
||||||
}
|
}
|
||||||
@@ -198,6 +199,7 @@ impl Default for Settings {
|
|||||||
map_w: 64,
|
map_w: 64,
|
||||||
map_h: 64,
|
map_h: 64,
|
||||||
surface: false,
|
surface: false,
|
||||||
|
events: true,
|
||||||
keys: BTreeMap::new(),
|
keys: BTreeMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user