From eb219f6b013bbf39b764e01dbf8d24941fdc7cf9 Mon Sep 17 00:00:00 2001 From: Richard Zink Date: Fri, 6 Nov 2026 13:29:44 +0100 Subject: [PATCH] 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 --- docs/MISSION_SCRIPTING.md | 6 ++++-- lang/cs.lang | 6 ++++++ lang/da.lang | 6 ++++++ lang/de.lang | 6 ++++++ lang/el.lang | 6 ++++++ lang/en.lang | 6 ++++++ lang/es.lang | 6 ++++++ lang/fi.lang | 6 ++++++ lang/hr.lang | 6 ++++++ lang/hu.lang | 6 ++++++ lang/it.lang | 6 ++++++ lang/nl.lang | 6 ++++++ lang/no.lang | 6 ++++++ lang/pt.lang | 6 ++++++ lang/ro.lang | 6 ++++++ lang/ru.lang | 6 ++++++ lang/sk.lang | 6 ++++++ lang/sr.lang | 6 ++++++ lang/sv.lang | 6 ++++++ src/blocks.rs | 31 +++++++++++++++++++++++----- src/editor/blocks_ui.rs | 22 +++++++++++++++++++- src/editor/coop_campaign.rs | 34 +++++++++++++++++++++++++++++++ src/mscript.rs | 40 +++++++++++++++++++++++++++++++++++++ 23 files changed, 233 insertions(+), 8 deletions(-) diff --git a/docs/MISSION_SCRIPTING.md b/docs/MISSION_SCRIPTING.md index 1b541df..5abb582 100644 --- a/docs/MISSION_SCRIPTING.md +++ b/docs/MISSION_SCRIPTING.md @@ -58,10 +58,12 @@ creatures and heroes. | Units | Spawn | count, kind, level, side, where (the core, the trigger unit, a zone), optional name | | | Hero wave | count (sent at once) | | | Remove | side, zone (removes those units) | -| World | Change ground | zone → floor, earth, rock, water, lava, gold (the core, portals, towers and the gate stay) | +| World | Change ground | zone → floor, earth, rock, water, lava, gold, mushroom grove (the core, portals, towers and the gate stay) | | | Reveal | zone (lifts the fog of war) | | | Show | zone (moves the camera there) | | | Gold + / Mana + | amount (negative takes) | +| | Weather above ground | fair, rain, fog or storm, for seconds (0: until a block changes it); it fades in softly. Only maps with land above ground have weather | +| | Talent experience + | amount (experience for the player's master talents) | | Logic | If / else | condition; blocks inside | | | Repeat | times (0–100); blocks inside | | | Repeat until | condition, checked **before** each run (already true: the inside never runs); blocks inside | @@ -80,7 +82,7 @@ Every number field holds a **value**; the switch in front of it changes the valu side/kind), *Count* in a zone, *Random* (whole number between a and b, deterministic), *Calculation* (`+ - * /`, division by 0 gives 0), - conditions (for *If*): *Comparison* (`< <= = != >= >`), *and*, *or*, *not*, *Yes/no*, - *Trigger unit is a* (kind). + *Trigger unit is a* (kind), *Weather above ground is* (fair, rain, fog, storm). Variables are numbers the mission remembers (saved with the game); a variable is known once some script of the mission sets it. diff --git a/lang/cs.lang b/lang/cs.lang index 3cad155..3f5ead4 100644 --- a/lang/cs.lang +++ b/lang/cs.lang @@ -1376,6 +1376,8 @@ blk.reveal = Odhalit blk.camera = Ukázat blk.gold = Zlato + blk.mana = Mana + +blk.weather = Počasí na povrchu +blk.talentxp = Zkušenosti talentů + blk.if = Když blk.repeat = Opakovat blk.trigger = Přepnout spouštěč @@ -1395,6 +1397,8 @@ blk.help.reveal = Odhalí mlhu války nad zónou. blk.help.camera = Přesune kameru na zónu. blk.help.gold = Dá (nebo vezme) zlato. blk.help.mana = Dá (nebo vezme) manu. +blk.help.weather = Nastaví počasí na povrchu (jasno, déšť, mlha nebo bouře) na tolik sekund; 0 ho ponechá, dokud ho jiný blok nezmění. +blk.help.talentxp = Dá hráči zkušenosti pro pánovy talenty. blk.help.if = Spustí vnitřní bloky, jen když platí podmínka, jinak ty pod "jinak". blk.help.repeat = Spustí vnitřní bloky několikrát. blk.help.trigger = Zapne spouštěč (může se spustit znovu) nebo ho vypne. @@ -1417,6 +1421,7 @@ blk.v.or = nebo blk.v.not = ne blk.v.bool = Ano/ne blk.v.eventkind = Spouštěcí jednotka je +blk.v.weatheris = Počasí na povrchu je blk.w_at = na blk.w_by = o blk.w_in = v @@ -1465,6 +1470,7 @@ blk.until = Opakovat dokud blk.dountil = Opakovat, pak ověřit: dokud blk.wait = Čekat blk.w_seconds = sekund +blk.w_for = na blk.help.until = Spouští vnitřní bloky znovu a znovu, dokud neplatí podmínka - ověřuje se před každým během, takže pokud už platí, vnitřek se nespustí vůbec. blk.help.dountil = Spustí vnitřní bloky, pak ověří podmínku a opakuje, dokud neplatí - vnitřek proběhne vždy aspoň jednou. blk.help.wait = Pozastaví tento skript na několik sekund, pak pokračuje dalším blokem (i uvnitř smyček). diff --git a/lang/da.lang b/lang/da.lang index 771790b..9fe671f 100644 --- a/lang/da.lang +++ b/lang/da.lang @@ -1375,6 +1375,8 @@ blk.reveal = Afslør blk.camera = Vis blk.gold = Guld + blk.mana = Mana + +blk.weather = Vejret over jorden +blk.talentxp = Talenterfaring + blk.if = Hvis blk.repeat = Gentag blk.trigger = Skift udløser @@ -1394,6 +1396,8 @@ blk.help.reveal = Løfter krigens tåge over en zone. blk.help.camera = Flytter kameraet til en zone. blk.help.gold = Giver (eller tager) guld. blk.help.mana = Giver (eller tager) mana. +blk.help.weather = Sætter vejret over jorden (klart, regn, tåge eller storm) i så mange sekunder; 0 beholder det, til en anden blok ændrer det. +blk.help.talentxp = Giver spilleren erfaring til mestertalenterne. blk.help.if = Kører blokkene indeni kun hvis betingelsen gælder, ellers dem under "ellers". blk.help.repeat = Kører blokkene indeni flere gange. blk.help.trigger = Slår en udløser til (den kan udløses igen) eller fra. @@ -1416,6 +1420,7 @@ blk.v.or = eller blk.v.not = ikke blk.v.bool = Ja/nej blk.v.eventkind = Udløserenhed er en +blk.v.weatheris = Vejret over jorden er blk.w_at = ved blk.w_by = med blk.w_in = i @@ -1464,6 +1469,7 @@ blk.until = Gentag indtil blk.dountil = Gentag, tjek så: indtil blk.wait = Vent blk.w_seconds = sekunder +blk.w_for = i blk.help.until = Kører blokkene indeni igen og igen, indtil betingelsen gælder - tjekkes før hver kørsel, så hvis den allerede gælder, kører indholdet slet ikke. blk.help.dountil = Kører blokkene indeni, tjekker så betingelsen og gentager, indtil den gælder - indholdet kører altid mindst én gang. blk.help.wait = Sætter dette script på pause i nogle sekunder, derefter fortsætter det med næste blok (også inde i løkker). diff --git a/lang/de.lang b/lang/de.lang index 426acc3..47454ba 100644 --- a/lang/de.lang +++ b/lang/de.lang @@ -1375,6 +1375,8 @@ blk.reveal = Aufdecken blk.camera = Zeigen blk.gold = Gold + blk.mana = Mana + +blk.weather = Wetter über der Erde +blk.talentxp = Talent-Erfahrung + blk.if = Wenn blk.repeat = Wiederhole blk.trigger = Trigger schalten @@ -1394,6 +1396,8 @@ blk.help.reveal = Hebt den Nebel über einer Zone. blk.help.camera = Bewegt die Kamera zu einer Zone. blk.help.gold = Gibt (oder nimmt) Gold. blk.help.mana = Gibt (oder nimmt) Mana. +blk.help.weather = Setzt das Wetter über der Erde (heiter, Regen, Nebel oder Sturm) für so viele Sekunden; 0 hält es, bis ein anderer Block es ändert. +blk.help.talentxp = Gibt dem Spieler Erfahrung für die Meister-Talente. blk.help.if = Führt die Blöcke darin nur aus, wenn die Bedingung gilt, sonst die unter "sonst". blk.help.repeat = Führt die Blöcke darin mehrmals aus. blk.help.trigger = Schaltet einen Trigger ein (er darf erneut auslösen) oder aus. @@ -1416,6 +1420,7 @@ blk.v.or = oder blk.v.not = nicht blk.v.bool = Ja/Nein blk.v.eventkind = Auslöser ist ein +blk.v.weatheris = Wetter über der Erde ist blk.w_at = bei blk.w_by = um blk.w_in = in @@ -1464,6 +1469,7 @@ blk.until = Wiederhole bis blk.dountil = Wiederhole, prüfe danach: bis blk.wait = Warte blk.w_seconds = Sekunden +blk.w_for = für blk.help.until = Führt die Blöcke darin immer wieder aus, bis die Bedingung gilt - geprüft vor jedem Durchlauf; gilt sie schon, läuft der Inhalt gar nicht. blk.help.dountil = Führt die Blöcke darin aus, prüft dann die Bedingung und wiederholt, bis sie gilt - der Inhalt läuft mindestens einmal. blk.help.wait = Hält dieses Skript einige Sekunden an, danach geht es mit dem nächsten Block weiter (auch in Schleifen). diff --git a/lang/el.lang b/lang/el.lang index 37f3b95..3ba9d2d 100644 --- a/lang/el.lang +++ b/lang/el.lang @@ -1376,6 +1376,8 @@ blk.reveal = Αποκάλυψη blk.camera = Δείξε blk.gold = Χρυσός + blk.mana = Μάνα + +blk.weather = Καιρός στην επιφάνεια +blk.talentxp = Εμπειρία ταλέντων + blk.if = Αν blk.repeat = Επανάληψη blk.trigger = Διακόπτης εναύσματος @@ -1395,6 +1397,8 @@ blk.help.reveal = Σηκώνει την ομίχλη του πολέμου πά blk.help.camera = Μετακινεί την κάμερα σε μια ζώνη. blk.help.gold = Δίνει (ή παίρνει) χρυσό. blk.help.mana = Δίνει (ή παίρνει) μάνα. +blk.help.weather = Ορίζει τον καιρό στην επιφάνεια (αίθριο, βροχή, ομίχλη ή καταιγίδα) για τόσα δευτερόλεπτα· το 0 τον κρατά μέχρι να τον αλλάξει άλλο μπλοκ. +blk.help.talentxp = Δίνει στον παίκτη εμπειρία για τα ταλέντα του άρχοντα. blk.help.if = Εκτελεί τα μπλοκ μέσα μόνο αν ισχύει η συνθήκη, αλλιώς αυτά κάτω από το "αλλιώς". blk.help.repeat = Εκτελεί τα μπλοκ μέσα πολλές φορές. blk.help.trigger = Ενεργοποιεί ένα έναυσμα (μπορεί να ξαναπυροδοτηθεί) ή το απενεργοποιεί. @@ -1417,6 +1421,7 @@ blk.v.or = ή blk.v.not = όχι blk.v.bool = Ναι/όχι blk.v.eventkind = Μονάδα εναύσματος είναι +blk.v.weatheris = Ο καιρός στην επιφάνεια είναι blk.w_at = σε blk.w_by = κατά blk.w_in = σε @@ -1465,6 +1470,7 @@ blk.until = Επανάληψη ώσπου blk.dountil = Επανάληψη, μετά έλεγχος: ώσπου blk.wait = Αναμονή blk.w_seconds = δευτερόλεπτα +blk.w_for = για blk.help.until = Εκτελεί τα μπλοκ μέσα ξανά και ξανά ώσπου να ισχύσει η συνθήκη - ελέγχεται πριν από κάθε εκτέλεση, οπότε αν ισχύει ήδη, το εσωτερικό δεν εκτελείται καθόλου. blk.help.dountil = Εκτελεί τα μπλοκ μέσα, μετά ελέγχει τη συνθήκη και επαναλαμβάνει ώσπου να ισχύσει - το εσωτερικό εκτελείται πάντα τουλάχιστον μία φορά. blk.help.wait = Σταματά αυτό το σενάριο για μερικά δευτερόλεπτα, και μετά συνεχίζει με το επόμενο μπλοκ (και μέσα σε βρόχους). diff --git a/lang/en.lang b/lang/en.lang index 1b372b6..26bc718 100644 --- a/lang/en.lang +++ b/lang/en.lang @@ -1376,6 +1376,8 @@ blk.reveal = Reveal blk.camera = Show blk.gold = Gold + blk.mana = Mana + +blk.weather = Weather above ground +blk.talentxp = Talent experience + blk.if = If blk.repeat = Repeat blk.trigger = Switch trigger @@ -1395,6 +1397,8 @@ blk.help.reveal = Lifts the fog of war over a zone. blk.help.camera = Moves the camera to a zone. blk.help.gold = Gives (or takes) gold. blk.help.mana = Gives (or takes) mana. +blk.help.weather = Sets the weather above ground (fair, rain, fog or storm) for so many seconds; 0 keeps it until another block changes it. +blk.help.talentxp = Gives the player experience for the master talents. blk.help.if = Runs the blocks inside only if the condition holds, otherwise the ones under "else". blk.help.repeat = Runs the blocks inside several times. blk.help.trigger = Switches a trigger on (it may fire again) or off. @@ -1417,6 +1421,7 @@ blk.v.or = or blk.v.not = not blk.v.bool = Yes/no blk.v.eventkind = Trigger unit is a +blk.v.weatheris = Weather above ground is blk.w_at = at blk.w_by = by blk.w_in = in @@ -1465,6 +1470,7 @@ blk.until = Repeat until blk.dountil = Repeat, then check: until blk.wait = Wait blk.w_seconds = seconds +blk.w_for = for blk.help.until = Runs the blocks inside again and again until the condition holds - checked before each run, so if it already holds the inside does not run at all. blk.help.dountil = Runs the blocks inside, then checks the condition and repeats until it holds - the inside always runs at least once. blk.help.wait = Pauses this script for some seconds, then it goes on with the next block (also inside loops). diff --git a/lang/es.lang b/lang/es.lang index 7a7b638..e82a791 100644 --- a/lang/es.lang +++ b/lang/es.lang @@ -1368,6 +1368,8 @@ blk.reveal = Revelar blk.camera = Mostrar blk.gold = Oro + blk.mana = Maná + +blk.weather = Clima en la superficie +blk.talentxp = Experiencia de talentos + blk.if = Si blk.repeat = Repetir blk.trigger = Conmutar disparador @@ -1387,6 +1389,8 @@ blk.help.reveal = Levanta la niebla de guerra sobre una zona. blk.help.camera = Mueve la cámara a una zona. blk.help.gold = Da (o quita) oro. blk.help.mana = Da (o quita) maná. +blk.help.weather = Fija el clima en la superficie (despejado, lluvia, niebla o tormenta) durante tantos segundos; 0 lo mantiene hasta que otro bloque lo cambie. +blk.help.talentxp = Da al jugador experiencia para los talentos del maestro. blk.help.if = Ejecuta los bloques de dentro solo si se cumple la condición; si no, los de «si no». blk.help.repeat = Ejecuta varias veces los bloques de dentro. blk.help.trigger = Activa un disparador (puede volver a saltar) o lo desactiva. @@ -1409,6 +1413,7 @@ blk.v.or = o blk.v.not = no blk.v.bool = Sí/no blk.v.eventkind = El causante es un +blk.v.weatheris = El clima en la superficie es blk.w_at = en blk.w_by = en blk.w_in = en @@ -1465,6 +1470,7 @@ blk.until = Repetir hasta blk.dountil = Repetir y luego: hasta blk.wait = Esperar blk.w_seconds = segundos +blk.w_for = durante blk.help.until = Ejecuta los bloques de dentro una y otra vez hasta que se cumpla la condición; se comprueba antes de cada vuelta, así que si ya se cumple no se ejecuta nada. blk.help.dountil = Ejecuta los bloques de dentro, luego comprueba la condición y repite hasta que se cumpla; el contenido se ejecuta al menos una vez. blk.help.wait = Detiene este script unos segundos y luego sigue con el siguiente bloque (también dentro de bucles). diff --git a/lang/fi.lang b/lang/fi.lang index f52b9f5..d4e8785 100644 --- a/lang/fi.lang +++ b/lang/fi.lang @@ -1376,6 +1376,8 @@ blk.reveal = Paljasta blk.camera = Näytä blk.gold = Kulta + blk.mana = Mana + +blk.weather = Sää maan päällä +blk.talentxp = Kykykokemus + blk.if = Jos blk.repeat = Toista blk.trigger = Vaihda laukaisin @@ -1395,6 +1397,8 @@ blk.help.reveal = Poistaa sodan sumun alueen yltä. blk.help.camera = Siirtää kameran alueelle. blk.help.gold = Antaa (tai ottaa) kultaa. blk.help.mana = Antaa (tai ottaa) manaa. +blk.help.weather = Asettaa sään maan päällä (selkeää, sade, sumu tai myrsky) niin moneksi sekunniksi; 0 pitää sen, kunnes toinen palikka muuttaa sitä. +blk.help.talentxp = Antaa pelaajalle kokemusta mestarin kykyihin. blk.help.if = Suorittaa sisällä olevat lohkot vain, jos ehto pätee, muuten "muuten"-kohdan lohkot. blk.help.repeat = Suorittaa sisällä olevat lohkot useita kertoja. blk.help.trigger = Kytkee laukaisimen päälle (se voi laueta uudelleen) tai pois. @@ -1417,6 +1421,7 @@ blk.v.or = tai blk.v.not = ei blk.v.bool = Kyllä/ei blk.v.eventkind = Laukaisija on laji +blk.v.weatheris = Sää maan päällä on blk.w_at = paikka blk.w_by = määrä blk.w_in = alue @@ -1465,6 +1470,7 @@ blk.until = Toista kunnes blk.dountil = Toista, sitten tarkista: kunnes blk.wait = Odota blk.w_seconds = sekuntia +blk.w_for = kesto blk.help.until = Suorittaa sisällä olevia lohkoja yhä uudelleen, kunnes ehto pätee - tarkistetaan ennen jokaista kierrosta, joten jos ehto jo pätee, sisältöä ei suoriteta lainkaan. blk.help.dountil = Suorittaa sisällä olevat lohkot, tarkistaa sitten ehdon ja toistaa, kunnes se pätee - sisältö suoritetaan aina vähintään kerran. blk.help.wait = Pysäyttää tämän skriptin muutamaksi sekunniksi, sitten se jatkaa seuraavasta lohkosta (myös silmukoiden sisällä). diff --git a/lang/hr.lang b/lang/hr.lang index 23f998d..6e51cdd 100644 --- a/lang/hr.lang +++ b/lang/hr.lang @@ -1376,6 +1376,8 @@ blk.reveal = Otkrij blk.camera = Pokaži blk.gold = Zlato + blk.mana = Mana + +blk.weather = Vrijeme na površini +blk.talentxp = Iskustvo talenata + blk.if = Ako blk.repeat = Ponovi blk.trigger = Prebaci okidač @@ -1395,6 +1397,8 @@ blk.help.reveal = Podiže maglu rata nad zonom. blk.help.camera = Pomiče kameru na zonu. blk.help.gold = Daje (ili oduzima) zlato. blk.help.mana = Daje (ili oduzima) manu. +blk.help.weather = Postavlja vrijeme na površini (vedro, kiša, magla ili oluja) na toliko sekundi; 0 ga zadržava dok ga drugi blok ne promijeni. +blk.help.talentxp = Daje igraču iskustvo za gospodareve talente. blk.help.if = Pokreće unutarnje blokove samo ako uvjet vrijedi, inače one pod "inače". blk.help.repeat = Pokreće unutarnje blokove nekoliko puta. blk.help.trigger = Uključuje okidač (može se ponovo aktivirati) ili ga isključuje. @@ -1417,6 +1421,7 @@ blk.v.or = ili blk.v.not = ne blk.v.bool = Da/ne blk.v.eventkind = Jedinica okidača je +blk.v.weatheris = Vrijeme na površini je blk.w_at = na blk.w_by = za blk.w_in = u @@ -1465,6 +1470,7 @@ blk.until = Ponavljaj dok blk.dountil = Ponovi, zatim provjeri: dok blk.wait = Čekaj blk.w_seconds = sekundi +blk.w_for = na blk.help.until = Pokreće unutarnje blokove iznova i iznova dok uvjet ne vrijedi - provjerava se prije svakog prolaza, pa ako već vrijedi, unutrašnjost se uopće ne pokreće. blk.help.dountil = Pokreće unutarnje blokove, zatim provjerava uvjet i ponavlja dok ne vrijedi - unutrašnjost se uvijek pokrene barem jednom. blk.help.wait = Pauzira ovu skriptu nekoliko sekundi, a zatim nastavlja sljedećim blokom (i unutar petlji). diff --git a/lang/hu.lang b/lang/hu.lang index 2679006..d582873 100644 --- a/lang/hu.lang +++ b/lang/hu.lang @@ -1376,6 +1376,8 @@ blk.reveal = Feltárás blk.camera = Mutat blk.gold = Arany + blk.mana = Mana + +blk.weather = Időjárás a felszínen +blk.talentxp = Tehetség-tapasztalat + blk.if = Ha blk.repeat = Ismétlés blk.trigger = Indító be/ki @@ -1395,6 +1397,8 @@ blk.help.reveal = Eloszlatja a háború ködét egy zóna fölött. blk.help.camera = A kamerát egy zónához mozgatja. blk.help.gold = Aranyat ad (vagy vesz el). blk.help.mana = Manát ad (vagy vesz el). +blk.help.weather = Beállítja az időjárást a felszínen (derült, eső, köd vagy vihar) ennyi másodpercre; 0 esetén megmarad, amíg egy másik blokk meg nem változtatja. +blk.help.talentxp = Tapasztalatot ad a játékosnak a mesteri tehetségekhez. blk.help.if = A benne lévő blokkokat csak akkor futtatja, ha a feltétel teljesül, különben a "különben" alattiakat. blk.help.repeat = A benne lévő blokkokat többször lefuttatja. blk.help.trigger = Egy indítót bekapcsol (újra elsülhet) vagy kikapcsol. @@ -1417,6 +1421,7 @@ blk.v.or = vagy blk.v.not = nem blk.v.bool = Igen/nem blk.v.eventkind = Indító egység fajtája +blk.v.weatheris = Az időjárás a felszínen blk.w_at = itt: blk.w_by = ennyivel: blk.w_in = itt: @@ -1465,6 +1470,7 @@ blk.until = Ismételd, amíg blk.dountil = Ismételd, majd ellenőrizd: amíg blk.wait = Várj blk.w_seconds = másodperc +blk.w_for = időtartam: blk.help.until = A benne lévő blokkokat újra meg újra lefuttatja, amíg a feltétel nem teljesül - minden futás előtt ellenőrzi, így ha már teljesül, a belseje egyszer sem fut le. blk.help.dountil = Lefuttatja a benne lévő blokkokat, majd ellenőrzi a feltételt, és addig ismétel, amíg nem teljesül - a belseje legalább egyszer mindig lefut. blk.help.wait = Néhány másodpercre szünetelteti ezt a szkriptet, aztán a következő blokkal folytatja (ciklusokon belül is). diff --git a/lang/it.lang b/lang/it.lang index 0b490ad..eadc573 100644 --- a/lang/it.lang +++ b/lang/it.lang @@ -1368,6 +1368,8 @@ blk.reveal = Rivela blk.camera = Mostra blk.gold = Oro + blk.mana = Mana + +blk.weather = Meteo in superficie +blk.talentxp = Esperienza talenti + blk.if = Se blk.repeat = Ripeti blk.trigger = Commuta trigger @@ -1387,6 +1389,8 @@ blk.help.reveal = Solleva la nebbia di guerra su una zona. blk.help.camera = Sposta la telecamera su una zona. blk.help.gold = Dà (o toglie) oro. blk.help.mana = Dà (o toglie) mana. +blk.help.weather = Imposta il meteo in superficie (sereno, pioggia, nebbia o tempesta) per tanti secondi; 0 lo mantiene finché un altro blocco non lo cambia. +blk.help.talentxp = Dà al giocatore esperienza per i talenti del maestro. blk.help.if = Esegue i blocchi interni solo se la condizione è vera, altrimenti quelli sotto "altrimenti". blk.help.repeat = Esegue più volte i blocchi interni. blk.help.trigger = Attiva un trigger (può scattare di nuovo) o lo disattiva. @@ -1409,6 +1413,7 @@ blk.v.or = o blk.v.not = non blk.v.bool = Sì/no blk.v.eventkind = L'unità innesco è +blk.v.weatheris = Il meteo in superficie è blk.w_at = presso blk.w_by = di blk.w_in = in @@ -1465,6 +1470,7 @@ blk.until = Ripeti finché blk.dountil = Ripeti, poi controlla: finché blk.wait = Attendi blk.w_seconds = secondi +blk.w_for = per blk.help.until = Esegue i blocchi interni più volte finché la condizione è vera; viene controllata prima di ogni giro, quindi se è già vera il contenuto non viene eseguito. blk.help.dountil = Esegue i blocchi interni, poi controlla la condizione e ripete finché è vera; il contenuto viene eseguito almeno una volta. blk.help.wait = Mette in pausa questo script per alcuni secondi, poi prosegue con il blocco successivo (anche nei cicli). diff --git a/lang/nl.lang b/lang/nl.lang index 6b79a8e..710f917 100644 --- a/lang/nl.lang +++ b/lang/nl.lang @@ -1376,6 +1376,8 @@ blk.reveal = Onthullen blk.camera = Tonen blk.gold = Goud + blk.mana = Mana + +blk.weather = Weer bovengronds +blk.talentxp = Talentervaring + blk.if = Als blk.repeat = Herhaal blk.trigger = Trigger schakelen @@ -1395,6 +1397,8 @@ blk.help.reveal = Heft de oorlogsmist boven een zone op. blk.help.camera = Verplaatst de camera naar een zone. blk.help.gold = Geeft (of neemt) goud. blk.help.mana = Geeft (of neemt) mana. +blk.help.weather = Zet het weer bovengronds (helder, regen, mist of storm) voor zoveel seconden; 0 houdt het tot een ander blok het verandert. +blk.help.talentxp = Geeft de speler ervaring voor de meestertalenten. blk.help.if = Voert de blokken erin alleen uit als de voorwaarde klopt, anders die onder "anders". blk.help.repeat = Voert de blokken erin meerdere keren uit. blk.help.trigger = Zet een trigger aan (hij mag weer afgaan) of uit. @@ -1417,6 +1421,7 @@ blk.v.or = of blk.v.not = niet blk.v.bool = Ja/nee blk.v.eventkind = Triggerunit is een +blk.v.weatheris = Weer bovengronds is blk.w_at = op blk.w_by = met blk.w_in = in @@ -1465,6 +1470,7 @@ blk.until = Herhaal tot blk.dountil = Herhaal, dan controleer: tot blk.wait = Wacht blk.w_seconds = seconden +blk.w_for = voor blk.help.until = Voert de blokken erin steeds opnieuw uit tot de voorwaarde klopt - gecontroleerd voor elke ronde, dus als ze al klopt, wordt de inhoud helemaal niet uitgevoerd. blk.help.dountil = Voert de blokken erin uit, controleert dan de voorwaarde en herhaalt tot ze klopt - de inhoud wordt altijd minstens een keer uitgevoerd. blk.help.wait = Pauzeert dit script een aantal seconden en gaat dan verder met het volgende blok (ook binnen lussen). diff --git a/lang/no.lang b/lang/no.lang index 2e890fd..ac3ced2 100644 --- a/lang/no.lang +++ b/lang/no.lang @@ -1375,6 +1375,8 @@ blk.reveal = Avslør blk.camera = Vis blk.gold = Gull + blk.mana = Mana + +blk.weather = Været over jorden +blk.talentxp = Talenterfaring + blk.if = Hvis blk.repeat = Gjenta blk.trigger = Bytt utløser @@ -1394,6 +1396,8 @@ blk.help.reveal = Løfter krigens tåke over en sone. blk.help.camera = Flytter kameraet til en sone. blk.help.gold = Gir (eller tar) gull. blk.help.mana = Gir (eller tar) mana. +blk.help.weather = Setter været over jorden (klart, regn, tåke eller storm) i så mange sekunder; 0 beholder det til en annen blokk endrer det. +blk.help.talentxp = Gir spilleren erfaring til mestertalentene. blk.help.if = Kjører blokkene inni bare hvis betingelsen gjelder, ellers de under "ellers". blk.help.repeat = Kjører blokkene inni flere ganger. blk.help.trigger = Slår en utløser på (den kan utløses igjen) eller av. @@ -1416,6 +1420,7 @@ blk.v.or = eller blk.v.not = ikke blk.v.bool = Ja/nei blk.v.eventkind = Utløserenhet er en +blk.v.weatheris = Været over jorden er blk.w_at = ved blk.w_by = med blk.w_in = i @@ -1464,6 +1469,7 @@ blk.until = Gjenta til blk.dountil = Gjenta, sjekk så: til blk.wait = Vent blk.w_seconds = sekunder +blk.w_for = i blk.help.until = Kjører blokkene inni igjen og igjen til betingelsen gjelder - sjekkes før hver kjøring, så hvis den allerede gjelder, kjører innholdet ikke i det hele tatt. blk.help.dountil = Kjører blokkene inni, sjekker så betingelsen og gjentar til den gjelder - innholdet kjører alltid minst én gang. blk.help.wait = Setter dette skriptet på pause i noen sekunder, så fortsetter det med neste blokk (også inni løkker). diff --git a/lang/pt.lang b/lang/pt.lang index efe6b95..e3c4658 100644 --- a/lang/pt.lang +++ b/lang/pt.lang @@ -1376,6 +1376,8 @@ blk.reveal = Revelar blk.camera = Mostrar blk.gold = Ouro + blk.mana = Mana + +blk.weather = Tempo na superfície +blk.talentxp = Experiência de talentos + blk.if = Se blk.repeat = Repetir blk.trigger = Ligar gatilho @@ -1395,6 +1397,8 @@ blk.help.reveal = Levanta o nevoeiro de guerra sobre uma zona. blk.help.camera = Move a câmara para uma zona. blk.help.gold = Dá (ou tira) ouro. blk.help.mana = Dá (ou tira) mana. +blk.help.weather = Define o tempo na superfície (limpo, chuva, nevoeiro ou temporal) durante tantos segundos; 0 mantém-no até outro bloco o mudar. +blk.help.talentxp = Dá ao jogador experiência para os talentos do mestre. blk.help.if = Executa os blocos de dentro só se a condição se verificar; caso contrário, os de "senão". blk.help.repeat = Executa os blocos de dentro várias vezes. blk.help.trigger = Liga um gatilho (pode disparar de novo) ou desliga-o. @@ -1417,6 +1421,7 @@ blk.v.or = ou blk.v.not = não blk.v.bool = Sim/não blk.v.eventkind = Unidade do gatilho é +blk.v.weatheris = Tempo na superfície é blk.w_at = em blk.w_by = por blk.w_in = em @@ -1465,6 +1470,7 @@ blk.until = Repetir até blk.dountil = Repetir, depois verificar: até blk.wait = Esperar blk.w_seconds = segundos +blk.w_for = durante blk.help.until = Executa os blocos de dentro uma e outra vez até a condição se verificar - verificada antes de cada execução, por isso, se já se verificar, o interior nem chega a correr. blk.help.dountil = Executa os blocos de dentro, depois verifica a condição e repete até ela se verificar - o interior corre sempre pelo menos uma vez. blk.help.wait = Pausa este script durante alguns segundos e depois continua com o bloco seguinte (também dentro de ciclos). diff --git a/lang/ro.lang b/lang/ro.lang index 2ab9793..bed5b1c 100644 --- a/lang/ro.lang +++ b/lang/ro.lang @@ -1376,6 +1376,8 @@ blk.reveal = Dezvăluie blk.camera = Arată blk.gold = Aur + blk.mana = Mana + +blk.weather = Vremea la suprafață +blk.talentxp = Experiență pentru talente + blk.if = Dacă blk.repeat = Repetă blk.trigger = Comută declanșator @@ -1395,6 +1397,8 @@ blk.help.reveal = Ridică ceața războiului de pe o zonă. blk.help.camera = Mută camera la o zonă. blk.help.gold = Dă (sau ia) aur. blk.help.mana = Dă (sau ia) mana. +blk.help.weather = Setează vremea la suprafață (senin, ploaie, ceață sau furtună) pentru atâtea secunde; 0 o păstrează până când alt bloc o schimbă. +blk.help.talentxp = Dă jucătorului experiență pentru talentele stăpânului. blk.help.if = Rulează blocurile dinăuntru doar dacă condiția e adevărată, altfel pe cele de sub "altfel". blk.help.repeat = Rulează blocurile dinăuntru de mai multe ori. blk.help.trigger = Pornește un declanșator (poate acționa din nou) sau îl oprește. @@ -1417,6 +1421,7 @@ blk.v.or = sau blk.v.not = nu blk.v.bool = Da/nu blk.v.eventkind = Unitatea declanșatoare e un +blk.v.weatheris = Vremea la suprafață e blk.w_at = la blk.w_by = cu blk.w_in = în @@ -1465,6 +1470,7 @@ blk.until = Repetă până când blk.dountil = Repetă, apoi verifică: până când blk.wait = Așteaptă blk.w_seconds = secunde +blk.w_for = pentru blk.help.until = Rulează blocurile dinăuntru iar și iar până când condiția e adevărată - verificată înaintea fiecărei rulări, deci dacă e deja adevărată, interiorul nu rulează deloc. blk.help.dountil = Rulează blocurile dinăuntru, apoi verifică condiția și repetă până e adevărată - interiorul rulează mereu cel puțin o dată. blk.help.wait = Oprește acest script câteva secunde, apoi continuă cu blocul următor (și în bucle). diff --git a/lang/ru.lang b/lang/ru.lang index f9776d1..4f0e0f0 100644 --- a/lang/ru.lang +++ b/lang/ru.lang @@ -1368,6 +1368,8 @@ blk.reveal = Открыть blk.camera = Показать blk.gold = Золото + blk.mana = Мана + +blk.weather = Погода на поверхности +blk.talentxp = Опыт талантов + blk.if = Если blk.repeat = Повторить blk.trigger = Переключить триггер @@ -1387,6 +1389,8 @@ blk.help.reveal = Снимает туман войны с зоны. blk.help.camera = Переносит камеру к зоне. blk.help.gold = Даёт (или забирает) золото. blk.help.mana = Даёт (или забирает) ману. +blk.help.weather = Задаёт погоду на поверхности (ясно, дождь, туман или гроза) на столько секунд; 0 оставляет её, пока другой блок её не изменит. +blk.help.talentxp = Даёт игроку опыт для талантов мастера. blk.help.if = Выполняет вложенные блоки, только если условие верно, иначе - блоки под «иначе». blk.help.repeat = Выполняет вложенные блоки несколько раз. blk.help.trigger = Включает триггер (он может сработать снова) или выключает его. @@ -1409,6 +1413,7 @@ blk.v.or = или blk.v.not = не blk.v.bool = Да/нет blk.v.eventkind = Боец триггера: +blk.v.weatheris = Погода на поверхности: blk.w_at = где: blk.w_by = на blk.w_in = в @@ -1465,6 +1470,7 @@ blk.until = Повторять, пока не blk.dountil = Повторять, затем проверить: пока не blk.wait = Ждать blk.w_seconds = сек. +blk.w_for = на blk.help.until = Снова и снова выполняет блоки внутри, пока условие не станет верным; проверка перед каждым проходом, поэтому если оно уже верно, блоки не выполняются. blk.help.dountil = Выполняет блоки внутри, затем проверяет условие и повторяет, пока оно не станет верным; блоки выполняются хотя бы один раз. blk.help.wait = Приостанавливает этот скрипт на несколько секунд, затем выполняется следующий блок (и внутри циклов). diff --git a/lang/sk.lang b/lang/sk.lang index 182a279..394c7bc 100644 --- a/lang/sk.lang +++ b/lang/sk.lang @@ -1376,6 +1376,8 @@ blk.reveal = Odhaliť blk.camera = Ukázať blk.gold = Zlato + blk.mana = Mana + +blk.weather = Počasie na povrchu +blk.talentxp = Skúsenosti talentov + blk.if = Ak blk.repeat = Opakovať blk.trigger = Prepnúť spúšťač @@ -1395,6 +1397,8 @@ blk.help.reveal = Odhalí hmlu vojny nad zónou. blk.help.camera = Presunie kameru na zónu. blk.help.gold = Dá (alebo vezme) zlato. blk.help.mana = Dá (alebo vezme) manu. +blk.help.weather = Nastaví počasie na povrchu (jasno, dážď, hmla alebo búrka) na toľko sekúnd; 0 ho ponechá, kým ho iný blok nezmení. +blk.help.talentxp = Dá hráčovi skúsenosti pre pánove talenty. blk.help.if = Spustí vnútorné bloky, len ak platí podmienka, inak tie pod "inak". blk.help.repeat = Spustí vnútorné bloky niekoľkokrát. blk.help.trigger = Zapne spúšťač (môže sa spustiť znova) alebo ho vypne. @@ -1417,6 +1421,7 @@ blk.v.or = alebo blk.v.not = nie blk.v.bool = Áno/nie blk.v.eventkind = Spúšťacia jednotka je +blk.v.weatheris = Počasie na povrchu je blk.w_at = na blk.w_by = o blk.w_in = v @@ -1465,6 +1470,7 @@ blk.until = Opakovať, kým blk.dountil = Opakovať, potom overiť: kým blk.wait = Čakať blk.w_seconds = sekúnd +blk.w_for = na blk.help.until = Spúšťa vnútorné bloky znova a znova, kým neplatí podmienka - overuje sa pred každým behom, takže ak už platí, vnútro sa nespustí vôbec. blk.help.dountil = Spustí vnútorné bloky, potom overí podmienku a opakuje, kým neplatí - vnútro prebehne vždy aspoň raz. blk.help.wait = Pozastaví tento skript na niekoľko sekúnd, potom pokračuje ďalším blokom (aj vnútri slučiek). diff --git a/lang/sr.lang b/lang/sr.lang index 7ecab77..6730897 100644 --- a/lang/sr.lang +++ b/lang/sr.lang @@ -1376,6 +1376,8 @@ blk.reveal = Откриј blk.camera = Покажи blk.gold = Злато + blk.mana = Мана + +blk.weather = Време на површини +blk.talentxp = Искуство талената + blk.if = Ако blk.repeat = Понови blk.trigger = Пребаци окидач @@ -1395,6 +1397,8 @@ blk.help.reveal = Подиже маглу рата над зоном. blk.help.camera = Помера камеру на зону. blk.help.gold = Даје (или одузима) злато. blk.help.mana = Даје (или одузима) ману. +blk.help.weather = Поставља време на површини (ведро, киша, магла или олуја) на толико секунди; 0 га задржава док га други блок не промени. +blk.help.talentxp = Даје играчу искуство за господареве таленте. blk.help.if = Покреће унутрашње блокове само ако услов важи, иначе оне под «иначе». blk.help.repeat = Покреће унутрашње блокове неколико пута. blk.help.trigger = Укључује окидач (може поново да се активира) или га искључује. @@ -1417,6 +1421,7 @@ blk.v.or = или blk.v.not = не blk.v.bool = Да/не blk.v.eventkind = Јединица окидача је +blk.v.weatheris = Време на површини је blk.w_at = на blk.w_by = за blk.w_in = у @@ -1465,6 +1470,7 @@ blk.until = Понављај док blk.dountil = Понови, затим провери: док blk.wait = Чекај blk.w_seconds = секунди +blk.w_for = на blk.help.until = Покреће унутрашње блокове изнова и изнова док услов не почне да важи - проверава се пре сваког пролаза, па ако већ важи, унутрашњост се уопште не покреће. blk.help.dountil = Покреће унутрашње блокове, затим проверава услов и понавља док не почне да важи - унутрашњост се увек покрене бар једном. blk.help.wait = Паузира ову скрипту неколико секунди, а затим наставља следећим блоком (и унутар петљи). diff --git a/lang/sv.lang b/lang/sv.lang index cce7558..1e3ce96 100644 --- a/lang/sv.lang +++ b/lang/sv.lang @@ -1376,6 +1376,8 @@ blk.reveal = Avslöja blk.camera = Visa blk.gold = Guld + blk.mana = Mana + +blk.weather = Vädret ovan jord +blk.talentxp = Talangerfarenhet + blk.if = Om blk.repeat = Upprepa blk.trigger = Växla trigger @@ -1395,6 +1397,8 @@ blk.help.reveal = Lyfter krigsdimman över en zon. blk.help.camera = Flyttar kameran till en zon. blk.help.gold = Ger (eller tar) guld. blk.help.mana = Ger (eller tar) mana. +blk.help.weather = Sätter vädret ovan jord (klart, regn, dimma eller storm) i så många sekunder; 0 behåller det tills ett annat block ändrar det. +blk.help.talentxp = Ger spelaren erfarenhet till mästartalangerna. blk.help.if = Kör blocken inuti bara om villkoret gäller, annars de under "annars". blk.help.repeat = Kör blocken inuti flera gånger. blk.help.trigger = Slår på en trigger (den får utlösas igen) eller av. @@ -1417,6 +1421,7 @@ blk.v.or = eller blk.v.not = inte blk.v.bool = Ja/nej blk.v.eventkind = Triggerenheten är en +blk.v.weatheris = Vädret ovan jord är blk.w_at = vid blk.w_by = med blk.w_in = i @@ -1465,6 +1470,7 @@ blk.until = Upprepa tills blk.dountil = Upprepa, kolla sedan: tills blk.wait = Vänta blk.w_seconds = sekunder +blk.w_for = i blk.help.until = Kör blocken inuti om och om igen tills villkoret gäller - kontrolleras före varje varv, så om det redan gäller körs insidan inte alls. blk.help.dountil = Kör blocken inuti, kontrollerar sedan villkoret och upprepar tills det gäller - insidan körs alltid minst en gång. blk.help.wait = Pausar det här skriptet några sekunder, sedan fortsätter det med nästa block (även inuti loopar). diff --git a/src/blocks.rs b/src/blocks.rs index f0e1a75..84372aa 100644 --- a/src/blocks.rs +++ b/src/blocks.rs @@ -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, b: Box }, Not { a: Box }, 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 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, out: &mut Vec 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)); diff --git a/src/editor/blocks_ui.rs b/src/editor/blocks_ui.rs index ce630c1..b60b236 100644 --- a/src/editor/blocks_ui.rs +++ b/src/editor/blocks_ui.rs @@ -543,7 +543,13 @@ impl BlockEdit { let r = lay.take(CW() * 10.0); im.text_field(gfx, fid(path, 6), r, name, 16); } - Block::Wave { count } | Block::Gold { amount: count } | Block::Mana { amount: count } => self.value(im, gfx, count, Ty::Num, path, 1, lay, ctx), + Block::Wave { count } | Block::Gold { amount: count } | Block::Mana { amount: count } | Block::TalentXp { amount: count } => self.value(im, gfx, count, Ty::Num, path, 1, lay, ctx), + Block::Weather { kind, secs } => { + weather_dd(im, gfx, kind, fid(path, 2), lay); + lay.word(gfx, &tr("blk.w_for")); + self.value(im, gfx, secs, Ty::Num, path, 1, lay, ctx); + lay.word(gfx, &tr("blk.w_seconds")); + } Block::SetVar { name, value } | Block::AddVar { name, value } => { let r = lay.take(CW() * 12.0); im.text_field(gfx, fid(path, 0), r, name, 24); @@ -713,10 +719,24 @@ impl BlockEdit { lay.word(gfx, &tr("blk.v.eventkind")); self.kind_dd(im, gfx, kind, false, path, sub(0), lay); } + Val::WeatherIs { kind } => { + lay.word(gfx, &tr("blk.v.weatheris")); + weather_dd(im, gfx, kind, fid(path, sub(0)), lay); + } } } } +// a dropdown with the kinds of weather +fn weather_dd(im: &mut Im, gfx: &Gfx, kind: &mut String, id: u64, lay: &mut Lay) { + let opts: Vec = WEATHER.iter().map(|w| tr(&format!("weather.{}", w))).collect(); + let cur = tr(&format!("weather.{}", kind)); + let r = lay.take(CW() * 12.0); + if let Some(c) = im.dropdown(gfx, id, r, &cur, &opts) { + *kind = WEATHER[c].to_string(); + } +} + // where the next field of a block goes: left to right, into a new row at the block's edge struct Lay { x: f32, diff --git a/src/editor/coop_campaign.rs b/src/editor/coop_campaign.rs index ac1c6f7..12428f9 100644 --- a/src/editor/coop_campaign.rs +++ b/src/editor/coop_campaign.rs @@ -143,6 +143,40 @@ pub fn coop_campaign() -> CampaignDoc { ], }); } + // the rogues of the Order in the later missions: thieves from mission 7, an inquisitor + // from mission 15; the last mission (above ground) brews a storm + let lv = n((1 + i / 3) as f64); + if i >= 6 { + sc.triggers.push(TriggerDoc { + name: "thieves".into(), + kind: TriggerKind::Timer { secs: 420.0, every: false }, + once: true, + enabled: true, + script: vec![Block::Message { text: tr("coop.raid") }, Block::Spawn { side: 1, kind: "Thief".into(), count: n(2.0), level: lv.clone(), place: Place::Zone(ZONES[i % 3].0.into()), name: String::new() }], + }); + } + if i >= 14 { + sc.triggers.push(TriggerDoc { + name: "inquisitor".into(), + kind: TriggerKind::Timer { secs: 600.0, every: false }, + once: true, + enabled: true, + script: vec![ + Block::Message { text: tr("coop.raid") }, + Block::Spawn { side: 1, kind: "Inquisitor".into(), count: n(1.0), level: lv.clone(), place: Place::Zone(ZONES[(i + 1) % 3].0.into()), name: String::new() }, + Block::Spawn { side: 1, kind: "Monk".into(), count: n(2.0), level: lv.clone(), place: Place::Zone(ZONES[(i + 1) % 3].0.into()), name: String::new() }, + ], + }); + } + if i + 1 == specs.len() { + sc.triggers.push(TriggerDoc { + name: "storm".into(), + kind: TriggerKind::Timer { secs: 480.0, every: false }, + once: true, + enabled: true, + script: vec![Block::Weather { kind: "storm".into(), secs: n(120.0) }], + }); + } if let Some((kind, level, name, zone)) = sp.boss { sc.start.push(Block::Spawn { side: 1, kind: kind.into(), count: n(1.0), level: n(level as f64), place: Place::Zone(ZONES[zone].0.into()), name: name.into() }); // the boss falls: the mission is won once the goals (if any) are done too diff --git a/src/mscript.rs b/src/mscript.rs index a5e0d3b..a4e7818 100644 --- a/src/mscript.rs +++ b/src/mscript.rs @@ -109,6 +109,8 @@ enum Act { Terrain(String, String), Kill(String, i32), Trigger(String, bool), + Weather(u8, f64), + TalentXp(f64), } // the triggering unit (for "where the unit is" and "the unit is a ...") @@ -539,6 +541,12 @@ impl Game { Val::Or { a, b } => (self.cond(s, a, ev) || self.cond(s, b, ev)) as i32 as f64, Val::Not { a } => (!self.cond(s, a, ev)) as i32 as f64, Val::EventKind { kind } => (ev.kind.is_some() && ev.kind == kind_by_name(kind)) as i32 as f64, + Val::WeatherIs { kind } => { + // the weather felt now (a change counts once it has come in) + let w = &self.weather; + let now = if w.level > 0.5 { w.shown } else { crate::weather::FAIR }; + (crate::blocks::WEATHER.iter().position(|k| k == kind) == Some(now as usize)) as i32 as f64 + } }; if r.is_finite() { r @@ -568,6 +576,8 @@ impl Game { Block::Wave { count } => Act::Wave(self.eval(s, count, ev).round() as i64), Block::Gold { amount } => Act::Gold(self.eval(s, amount, ev)), Block::Mana { amount } => Act::Mana(self.eval(s, amount, ev)), + Block::Weather { kind, secs } => Act::Weather(crate::blocks::WEATHER.iter().position(|k| k == kind).unwrap_or(0) as u8, self.eval(s, secs, ev)), + Block::TalentXp { amount } => Act::TalentXp(self.eval(s, amount, ev)), Block::SetVar { name, value } => { let v = self.eval(s, value, ev); s.vars.insert(name.clone(), v); @@ -824,6 +834,13 @@ impl Game { } } Act::Mana(n) => self.mana = (self.mana + n as f32).clamp(0.0, self.mana_max()), + // the weather comes (softly) and stays the given seconds (0: until a block changes it) + Act::Weather(k, secs) => { + self.weather.kind = k; + self.weather.left = if secs > 0.0 { secs as f32 } else { 1.0e9 }; + self.weather.strike_t = self.weather.strike_t.min(5.0); + } + Act::TalentXp(n) => self.add_master_xp(n.max(0.0) as f32), Act::Win => { self.state = 1; self.script_msg("msg.mission_won", vec![]); @@ -854,6 +871,7 @@ impl Game { "water" => Kind::Water, "lava" => Kind::Lava, "gold" => Kind::Gold, + "grove" => Kind::Grove, _ => Kind::Floor, }; for i in zone_tiles(&z) { @@ -960,6 +978,28 @@ mod tests { assert!(g.script.as_ref().unwrap().error.is_none(), "{:?}", g.script.as_ref().unwrap().error); } + #[test] + fn weather_and_talent_blocks_work() { + let mut g = Game::new(3, 64, 64); + g.add_surface(3, 0.5, 2); + let scripts = MissionScripts { + start: vec![ + Block::Weather { kind: "storm".into(), secs: Val::num(0.0) }, + Block::TalentXp { amount: Val::num(400.0) }, + Block::Wait { secs: Val::num(25.0) }, + Block::If { cond: Val::WeatherIs { kind: "storm".into() }, then: vec![Block::SetVar { name: "storm".into(), value: Val::num(1.0) }], els: vec![] }, + ], + ..Default::default() + }; + g.script = Some(ScriptState::new(scripts, vec![], 7)); + run(&mut g, 30.0); + assert_eq!(g.weather.kind, crate::weather::STORM); + assert!(g.weather.left > 1.0e8, "it stays"); + assert!(g.talents.xp >= 400.0 && g.talents.free() >= 1); + assert_eq!(g.script.as_ref().unwrap().vars.get("storm"), Some(&1.0), "the condition sees the storm"); + assert!(crate::blocks::check(&g.script.as_ref().unwrap().scripts.start, &crate::blocks::Names { zones: &[], triggers: &[], vars: &[] }).iter().all(|p| p.key != "blk.err_weather")); + } + #[test] fn a_zone_trigger_spawns_and_the_victory_script_wins() { let mut g = Game::new(3, 64, 64);