From ac22351cdf9b8e6e4308270e95199005fa6e4f67 Mon Sep 17 00:00:00 2001 From: Richard Zink Date: Fri, 6 Nov 2026 10:06:51 +0100 Subject: [PATCH] Monster eye marks the camera on the minimap; middle double click resets the view angle; creatures by beds up to 100 Co-Authored-By: Claude Opus 5.5 --- lang/cs.lang | 2 ++ lang/da.lang | 2 ++ lang/de.lang | 2 ++ lang/el.lang | 2 ++ lang/en.lang | 2 ++ lang/es.lang | 2 ++ lang/fi.lang | 2 ++ lang/hr.lang | 2 ++ lang/hu.lang | 2 ++ lang/it.lang | 2 ++ lang/nl.lang | 2 ++ lang/no.lang | 2 ++ lang/pt.lang | 2 ++ lang/ro.lang | 2 ++ lang/ru.lang | 2 ++ lang/sk.lang | 2 ++ lang/sr.lang | 2 ++ lang/sv.lang | 2 ++ src/game.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++++++- src/main.rs | 13 ++++++++++++- src/render3d.rs | 11 ++++++++++- src/ui.rs | 40 +++++++++++++++++++++++++++++++++++-- 22 files changed, 147 insertions(+), 5 deletions(-) diff --git a/lang/cs.lang b/lang/cs.lang index 087f57a..2e761c3 100644 --- a/lang/cs.lang +++ b/lang/cs.lang @@ -81,6 +81,7 @@ msg.no_mana_cost = Nedostatek many (potřeba {0}). hint.portal_no_lair = Portál je otevřený, ale bez doupěte žádní tvorové nepřijdou. hint.no_farm = Tvorové chtějí jíst: postav houbovou zahradu. hint.lair_full = Všechna lůžka v doupěti jsou obsazená. Zvětši doupě. +hint.creature_max = Tvá kobka má 100 tvorů - portálem už další nepřijdou. hint.gate_attack = Tví tvorové útočí na bránu hrdinů! hint.treasury_full = Tvé pokladnice jsou plné! Postav další políčka pokladnice. hint.flag_unreachable = Tví tvorové se k útočné vlajce nedostanou. @@ -154,6 +155,7 @@ help.k_right = Pravé kliknutí Položit jednotku (zajatce i do mučírny) help.k_slap = Shift+Levé Ruka: pohlavek vlastním, pěst hrdinům na tvém území help.k_pan = Pravé tažení Posun mapy (také WASD/šipky, okraj obrazovky) help.k_rot = Prostřední tah. Otáčení a naklánění kamery (také Q/E, R/F) +help.k_reset = Prostřední 2x klik Obnovit úhel a otočení (místo zůstane) help.k_zoom = Kolečko myši Zoom help.k_tools = 1-9,0,X,V,K,J,B,C,T,U,Y,O Volba nástroje help.k_misc = P / Mezerník Pauza M Zvuk zap./vyp. +/- Hlasitost diff --git a/lang/da.lang b/lang/da.lang index 6295cf9..f558e05 100644 --- a/lang/da.lang +++ b/lang/da.lang @@ -81,6 +81,7 @@ msg.no_mana_cost = Ikke nok mana ({0} kræves). hint.portal_no_lair = Portalen er åben, men uden et hi kommer der ingen væsner. hint.no_farm = Væsner vil have mad: byg en svampehave. hint.lair_full = Alle senge i hiet er optaget. Gør dit hi større. +hint.creature_max = Dit fangehul huser 100 væsner - der kommer ikke flere gennem portalen. hint.gate_attack = Dine væsner angriber helteporten! hint.treasury_full = Dine skatkamre er fulde! Byg flere skatkammerfelter. hint.flag_unreachable = Dine væsner kan ikke nå angrebsflaget. @@ -154,6 +155,7 @@ help.k_right = Højreklik Sæt en enhed ned (fanger: også i torturkammere help.k_slap = Shift+Venstre Hånd: bagkast til egne enheder, slå helte på din jord help.k_pan = Højre træk Flyt kortet (også WASD/pile, skærmkant) help.k_rot = Midter træk Drej og vip kameraet (også Q/E, R/F) +help.k_reset = Midter 2x klik Nulstil vinkel og drejning (stedet bliver) help.k_zoom = Musehjul Zoom help.k_tools = 1-9,0,X,V,K,J,B,C,T,U,Y,O Vælg værktøj help.k_misc = P / Mellemrum Pause M Lyd til/fra +/- Lydstyrke diff --git a/lang/de.lang b/lang/de.lang index 5c0073c..d31d42e 100644 --- a/lang/de.lang +++ b/lang/de.lang @@ -80,6 +80,7 @@ msg.no_mana_cost = Nicht genug Mana ({0} benötigt). hint.portal_no_lair = Das Portal ist offen, aber ohne Quartier kommen keine Kreaturen. hint.no_farm = Kreaturen wollen essen: Baue einen Pilzgarten. hint.lair_full = Alle Quartierplätze sind belegt. Vergrößere dein Quartier. +hint.creature_max = Dein Kerker beherbergt 100 Kreaturen - mehr kommen nicht durch das Portal. hint.gate_attack = Deine Kreaturen greifen das Heldentor an! hint.treasury_full = Deine Schatzkammern sind voll! Baue mehr Schatzkammer-Felder. hint.flag_unreachable = Die Angriffsflagge ist für deine Kreaturen nicht erreichbar. @@ -153,6 +154,7 @@ help.k_right = Rechtsklick Einheit absetzen (Gefangene auch in den Kerker) help.k_slap = Shift+Links Hand: Rückhand für eigene, Faust für Helden auf eigenem Gebiet help.k_pan = Rechts ziehen Karte verschieben (auch WASD/Pfeile, Bildrand) help.k_rot = Mitte ziehen Kamera drehen und neigen (auch Q/E, R/F) +help.k_reset = Mitte 2x klicken Blickwinkel und Drehung zurücksetzen (Ort bleibt) help.k_zoom = Mausrad Zoomen help.k_tools = 1-9,0,X,V,K,J,B,C,T,U,Y,O Werkzeug help.k_misc = P / Leertaste Pause M Ton an/aus +/- Lautstärke diff --git a/lang/el.lang b/lang/el.lang index c683c42..bb38080 100644 --- a/lang/el.lang +++ b/lang/el.lang @@ -81,6 +81,7 @@ msg.no_mana_cost = Δεν φτάνει το μάνα (χρειάζονται {0} hint.portal_no_lair = Η πύλη μετάβασης είναι ανοιχτή, αλλά χωρίς φωλιά δεν θα έρθει κανένα πλάσμα. hint.no_farm = Τα πλάσματα θέλουν να φάνε: χτίσε μανιταρόκηπο. hint.lair_full = Όλα τα κρεβάτια στη φωλιά είναι πιασμένα. Μεγάλωσε τη φωλιά σου. +hint.creature_max = Το μπουντρούμι σου έχει 100 πλάσματα - δεν έρχονται άλλα από την πύλη. hint.gate_attack = Τα πλάσματά σου επιτίθενται στην Πύλη Ηρώων! hint.treasury_full = Τα θησαυροφυλάκιά σου γέμισαν! Χτίσε περισσότερα πλακίδια θησαυροφυλακίου. hint.flag_unreachable = Τα πλάσματά σου δεν μπορούν να φτάσουν τη σημαία επίθεσης. @@ -154,6 +155,7 @@ help.k_right = Δεξί κλικ Άφησε μονάδα (αιχμαλώτ help.k_slap = Shift+Αριστερό Χέρι: χαστούκι στις δικές σου μονάδες, γροθιά σε ήρωες στο έδαφός σου help.k_pan = Δεξί σύρσιμο Μετακίνηση χάρτη (και WASD/βέλη, άκρη οθόνης) help.k_rot = Μεσαίο σύρσιμο Περιστροφή και κλίση κάμερας (και Q/E, R/F) +help.k_reset = Μεσαίο 2x κλικ Επαναφορά γωνίας και περιστροφής help.k_zoom = Ροδέλα Ζουμ help.k_tools = 1-9,0,X,V,K,J,B,C,T,U,Y,O Επιλογή εργαλείου help.k_misc = P / Space Παύση M Ήχος ναι/όχι +/- Ένταση diff --git a/lang/en.lang b/lang/en.lang index 333f90a..d2895e0 100644 --- a/lang/en.lang +++ b/lang/en.lang @@ -81,6 +81,7 @@ msg.no_mana_cost = Not enough mana ({0} needed). hint.portal_no_lair = The portal is open, but without a lair no creatures will come. hint.no_farm = Creatures want to eat: build a mushroom garden. hint.lair_full = All beds in the lair are taken. Enlarge your lair. +hint.creature_max = Your dungeon holds 100 creatures - no more come through the portal. hint.gate_attack = Your creatures are attacking the Hero Gate! hint.treasury_full = Your treasuries are full! Build more treasury tiles. hint.flag_unreachable = Your creatures cannot reach the attack flag. @@ -154,6 +155,7 @@ help.k_right = Right click Drop a unit (prisoners: also into the torture cha help.k_slap = Shift+Left Hand: backhand own units, punch heroes on your ground help.k_pan = Right drag Move the map (also WASD/arrows, screen edge) help.k_rot = Middle drag Rotate and tilt the camera (also Q/E, R/F) +help.k_reset = Middle 2x click Reset angle and turn (the place stays) help.k_zoom = Mouse wheel Zoom help.k_tools = 1-9,0,X,V,K,J,B,C,T,U,Y,O Select tool help.k_misc = P / Space Pause M Sound on/off +/- Volume diff --git a/lang/es.lang b/lang/es.lang index 486256b..6ab1da5 100644 --- a/lang/es.lang +++ b/lang/es.lang @@ -81,6 +81,7 @@ msg.no_mana_cost = No hay maná suficiente (se necesitan {0}). hint.portal_no_lair = El portal está abierto, pero sin guarida no vendrá ninguna criatura. hint.no_farm = Las criaturas quieren comer: construye un huerto de setas. hint.lair_full = Todas las camas de la guarida están ocupadas. Amplía tu guarida. +hint.creature_max = Tu mazmorra alberga 100 criaturas: no vendrán más por el portal. hint.gate_attack = ¡Tus criaturas atacan la Puerta de los Héroes! hint.treasury_full = ¡Tus tesorerías están llenas! Construye más casillas de tesorería. hint.flag_unreachable = Tus criaturas no pueden llegar a la bandera de ataque. @@ -154,6 +155,7 @@ help.k_right = Clic derecho Soltar unidad (prisioneros: también en la cámar help.k_slap = Mayús+Izq. Mano: abofetear unidades propias, golpear héroes en tu suelo help.k_pan = Arrastrar dcho. Mover el mapa (también WASD/flechas, borde de pantalla) help.k_rot = Arrastrar medio Rotar e inclinar la cámara (también Q/E, R/F) +help.k_reset = Medio 2x clic Restablecer ángulo y giro (el lugar se queda) help.k_zoom = Rueda del ratón Zoom help.k_tools = 1-9,0,X,V,K,J,B,C,T,U,Y,O Elegir herramienta help.k_misc = P / Espacio Pausa M Sonido sí/no +/- Volumen diff --git a/lang/fi.lang b/lang/fi.lang index 15dad56..5dc9356 100644 --- a/lang/fi.lang +++ b/lang/fi.lang @@ -81,6 +81,7 @@ msg.no_mana_cost = Mana ei riitä (tarvitaan {0}). hint.portal_no_lair = Portaali on auki, mutta ilman pesää yksikään olento ei tule. hint.no_farm = Olennot haluavat syödä: rakenna sienitarha. hint.lair_full = Pesän kaikki vuoteet ovat varattuja. Laajenna pesää. +hint.creature_max = Luolastossasi asuu 100 olentoa - portaalista ei tule enempää. hint.gate_attack = Olentosi hyökkäävät sankariporttia vastaan! hint.treasury_full = Aarreaittasi ovat täynnä! Rakenna lisää aarreaittaruutuja. hint.flag_unreachable = Olentosi eivät pääse hyökkäyslipun luo. @@ -154,6 +155,7 @@ help.k_right = Oikea klikkaus Pudota yksikkö (vangit: myös kidutuskammioon) help.k_slap = Shift+Vasen Käsi: läimäytä omia, mukiloi sankareita omalla maalla help.k_pan = Oikea veto Siirrä karttaa (myös WASD/nuolet, ruudun reuna) help.k_rot = Keskiveto Kierrä ja kallista kameraa (myös Q/E, R/F) +help.k_reset = Keski 2x klikkaus Palauta kulma ja kierto (paikka säilyy) help.k_zoom = Hiiren rulla Zoomaa help.k_tools = 1-9,0,X,V,K,J,B,C,T,U,Y,O Valitse työkalu help.k_misc = P / Välilyönti Tauko M Ääni päälle/pois +/- Voimakkuus diff --git a/lang/hr.lang b/lang/hr.lang index f093f31..fe4c6f6 100644 --- a/lang/hr.lang +++ b/lang/hr.lang @@ -81,6 +81,7 @@ msg.no_mana_cost = Nema dovoljno mane (potrebno {0}). hint.portal_no_lair = Portal je otvoren, ali bez brloga nijedno stvorenje neće doći. hint.no_farm = Stvorenja žele jesti: izgradi vrt gljiva. hint.lair_full = Svi kreveti u brlogu su zauzeti. Proširi brlog. +hint.creature_max = Tvoja tamnica ima 100 stvorenja - kroz portal ih više ne dolazi. hint.gate_attack = Tvoja stvorenja napadaju Vrata junaka! hint.treasury_full = Riznice su pune! Izgradi još polja riznice. hint.flag_unreachable = Tvoja stvorenja ne mogu doći do zastave napada. @@ -154,6 +155,7 @@ help.k_right = Desni klik Spusti jedinicu (zarobljenike i u mučionicu) help.k_slap = Shift+lijevi Ruka: pljusni svoje jedinice, udari junake na svom tlu help.k_pan = Desno povlačenje Pomiči kartu (i WASD/strelice, rub zaslona) help.k_rot = Srednje povlačenje Okreći i naginji kameru (i Q/E, R/F) +help.k_reset = Srednji 2x klik Vrati kut i okret (mjesto ostaje) help.k_zoom = Kotačić miša Zumiranje help.k_tools = 1-9,0,X,V,K,J,B,C,T,U,Y,O Odabir alata help.k_misc = P / Razmak Stanka M Zvuk uklj./isklj. +/- Glasnoća diff --git a/lang/hu.lang b/lang/hu.lang index d6fc524..b48d255 100644 --- a/lang/hu.lang +++ b/lang/hu.lang @@ -81,6 +81,7 @@ msg.no_mana_cost = Nincs elég mana ({0} kell). hint.portal_no_lair = A portál nyitva van, de odú nélkül egy lény sem jön. hint.no_farm = A lények enni akarnak: építs gombakertet. hint.lair_full = Az odúban minden ágy foglalt. Bővítsd az odút. +hint.creature_max = A kazamatádban 100 lény él - több nem jön a portálon át. hint.gate_attack = A lényeid megtámadták a Hőskaput! hint.treasury_full = A kincstáraid tele vannak! Építs további kincstármezőket. hint.flag_unreachable = A lényeid nem érik el a támadási zászlót. @@ -154,6 +155,7 @@ help.k_right = Jobb klikk Egység lerakása (foglyok: a kínzókamrába is) help.k_slap = Shift+Bal Kéz: saját egységek felpofozása, hősök ütése a saját földeden help.k_pan = Jobb húzás Térkép mozgatása (WASD/nyilak, képernyőszél is) help.k_rot = Középső húzás Kamera forgatása és döntése (Q/E, R/F is) +help.k_reset = Középső 2x katt. Szög és forgatás alaphelyzetbe (a hely marad) help.k_zoom = Egérgörgő Nagyítás help.k_tools = 1-9,0,X,V,K,J,B,C,T,U,Y,O Eszköz kiválasztása help.k_misc = P / Szóköz Szünet M Hang be/ki +/- Hangerő diff --git a/lang/it.lang b/lang/it.lang index 739a5f7..8c8fd55 100644 --- a/lang/it.lang +++ b/lang/it.lang @@ -81,6 +81,7 @@ msg.no_mana_cost = Mana insufficiente (servono {0}). hint.portal_no_lair = Il portale è aperto, ma senza una tana non verrà nessuna creatura. hint.no_farm = Le creature vogliono mangiare: costruisci una fungaia. hint.lair_full = Tutti i letti della tana sono occupati. Ingrandisci la tana. +hint.creature_max = Il tuo dungeon ospita 100 creature: dal portale non ne arrivano altre. hint.gate_attack = Le tue creature attaccano la Porta degli Eroi! hint.treasury_full = Le tesorerie sono piene! Costruisci altre caselle di tesoreria. hint.flag_unreachable = Le tue creature non riescono a raggiungere la bandiera d'attacco. @@ -154,6 +155,7 @@ help.k_right = Clic destro Posa un'unità (prigionieri: anche nella camera d help.k_slap = Shift+Sinistro Mano: schiaffo alle tue unità, pugno agli eroi sul tuo suolo help.k_pan = Destro+trascina Sposta la mappa (anche WASD/frecce, bordo schermo) help.k_rot = Centro+trascina Ruota e inclina la camera (anche Q/E, R/F) +help.k_reset = Centro 2x clic Ripristina angolo e rotazione (il posto resta) help.k_zoom = Rotellina Zoom help.k_tools = 1-9,0,X,V,K,J,B,C,T,U,Y,O Scegli strumento help.k_misc = P / Spazio Pausa M Audio sì/no +/- Volume diff --git a/lang/nl.lang b/lang/nl.lang index 1b5d7a8..c9dc250 100644 --- a/lang/nl.lang +++ b/lang/nl.lang @@ -81,6 +81,7 @@ msg.no_mana_cost = Niet genoeg mana ({0} nodig). hint.portal_no_lair = Het portaal staat open, maar zonder hol komen er geen wezens. hint.no_farm = Wezens willen eten: bouw een paddenstoeltuin. hint.lair_full = Alle bedden in het hol zijn bezet. Vergroot je hol. +hint.creature_max = Je kerker huisvest 100 wezens - er komen er geen meer door het portaal. hint.gate_attack = Je wezens vallen de Heldenpoort aan! hint.treasury_full = Je schatkamers zijn vol! Bouw meer schatkamervakken. hint.flag_unreachable = Je wezens kunnen de aanvalsvlag niet bereiken. @@ -154,6 +155,7 @@ help.k_right = Rechtsklik Unit neerzetten (gevangenen: ook in de martelkame help.k_slap = Shift+Links Hand: eigen units een mep geven, helden op je grond slaan help.k_pan = Rechts slepen Kaart verschuiven (ook WASD/pijltjes, schermrand) help.k_rot = Midden slepen Camera draaien en kantelen (ook Q/E, R/F) +help.k_reset = Midden 2x klik Hoek en draaiing terugzetten (plek blijft) help.k_zoom = Muiswiel Zoomen help.k_tools = 1-9,0,X,V,K,J,B,C,T,U,Y,O Gereedschap kiezen help.k_misc = P / Spatie Pauze M Geluid aan/uit +/- Volume diff --git a/lang/no.lang b/lang/no.lang index 492b8a5..166df56 100644 --- a/lang/no.lang +++ b/lang/no.lang @@ -81,6 +81,7 @@ msg.no_mana_cost = Ikke nok mana ({0} kreves). hint.portal_no_lair = Portalen er åpen, men uten et hi kommer det ingen skapninger. hint.no_farm = Skapninger vil ha mat: bygg en soppehage. hint.lair_full = Alle sengene i hiet er opptatt. Gjør hiet større. +hint.creature_max = Fangehullet ditt huser 100 vesener - det kommer ikke flere gjennom portalen. hint.gate_attack = Skapningene dine angriper helteporten! hint.treasury_full = Skattkamrene dine er fulle! Bygg flere skattkammerruter. hint.flag_unreachable = Skapningene dine kan ikke nå angrepsflagget. @@ -154,6 +155,7 @@ help.k_right = Høyreklikk Sett ned en enhet (fanger: også i torturkammeret help.k_slap = Shift+Venstre Hånd: baksveiv egne enheter, slå helter på din grunn help.k_pan = Høyre dra Flytt kartet (også WASD/piler, skjermkant) help.k_rot = Midtre dra Drei og vipp kameraet (også Q/E, R/F) +help.k_reset = Midtre 2x klikk Tilbakestill vinkel og dreiing (stedet blir) help.k_zoom = Musehjul Zoom help.k_tools = 1-9,0,X,V,K,J,B,C,T,U,Y,O Velg verktøy help.k_misc = P / Mellomrom Pause M Lyd på/av +/- Volum diff --git a/lang/pt.lang b/lang/pt.lang index 61cec49..b0ccd75 100644 --- a/lang/pt.lang +++ b/lang/pt.lang @@ -81,6 +81,7 @@ msg.no_mana_cost = Mana insuficiente ({0} necessária). hint.portal_no_lair = O portal está aberto, mas sem covil não vem nenhuma criatura. hint.no_farm = As criaturas querem comer: constrói uma horta de cogumelos. hint.lair_full = Todas as camas do covil estão ocupadas. Aumenta o covil. +hint.creature_max = A tua masmorra abriga 100 criaturas - não vêm mais pelo portal. hint.gate_attack = As tuas criaturas estão a atacar o Portão dos Heróis! hint.treasury_full = As tuas tesourarias estão cheias! Constrói mais casas de tesouraria. hint.flag_unreachable = As tuas criaturas não conseguem chegar à bandeira de ataque. @@ -154,6 +155,7 @@ help.k_right = Clique dir. Largar unidade (prisioneiros: também na câmara help.k_slap = Shift+Esq. Mão: esbofetear as tuas unidades, socar heróis no teu chão help.k_pan = Arrastar dir. Mover o mapa (também WASD/setas, borda do ecrã) help.k_rot = Arrastar meio Rodar e inclinar a câmara (também Q/E, R/F) +help.k_reset = Meio 2x clique Repor ângulo e rotação (o local mantém-se) help.k_zoom = Roda do rato Zoom help.k_tools = 1-9,0,X,V,K,J,B,C,T,U,Y,O Escolher ferramenta help.k_misc = P / Espaço Pausa M Som lig./desl. +/- Volume diff --git a/lang/ro.lang b/lang/ro.lang index a14d010..d08ec08 100644 --- a/lang/ro.lang +++ b/lang/ro.lang @@ -81,6 +81,7 @@ msg.no_mana_cost = Nu ai destulă mana (necesar {0}). hint.portal_no_lair = Portalul e deschis, dar fără bârlog nu vine nicio creatură. hint.no_farm = Creaturile vor să mănânce: construiește o grădină de ciuperci. hint.lair_full = Toate paturile din bârlog sunt ocupate. Mărește-ți bârlogul. +hint.creature_max = Temnița ta adăpostește 100 de creaturi - nu mai vin altele prin portal. hint.gate_attack = Creaturile tale atacă Poarta Eroilor! hint.treasury_full = Vistieriile tale sunt pline! Construiește mai multe dale de vistierie. hint.flag_unreachable = Creaturile tale nu pot ajunge la steagul de atac. @@ -154,6 +155,7 @@ help.k_right = Clic dreapta Lasă jos o unitate (prizonieri: și în camera d help.k_slap = Shift+Stânga Mână: palmă unităților tale, pumn eroilor de pe terenul tău help.k_pan = Dreapta+trage Mută harta (și WASD/săgeți, marginea ecranului) help.k_rot = Mijloc+trage Rotește și înclină camera (și Q/E, R/F) +help.k_reset = Mijloc 2x clic Resetează unghiul și rotația (locul rămâne) help.k_zoom = Rotița mouse Zoom help.k_tools = 1-9,0,X,V,K,J,B,C,T,U,Y,O Alege unealta help.k_misc = P / Spațiu Pauză M Sunet pornit/oprit +/- Volum diff --git a/lang/ru.lang b/lang/ru.lang index bf5b950..53ff6ab 100644 --- a/lang/ru.lang +++ b/lang/ru.lang @@ -81,6 +81,7 @@ msg.no_mana_cost = Не хватает маны (нужно {0}). hint.portal_no_lair = Портал открыт, но без логова существа не придут. hint.no_farm = Существа хотят есть: построй грибной сад. hint.lair_full = Все места в логове заняты. Расширь логово. +hint.creature_max = В твоём подземелье 100 существ - больше через портал не придёт. hint.gate_attack = Твои существа атакуют Врата героев! hint.treasury_full = Сокровищницы полны! Построй больше клеток сокровищницы. hint.flag_unreachable = Существа не могут добраться до флага атаки. @@ -154,6 +155,7 @@ help.k_right = Правый клик Опустить существо (пл help.k_slap = Shift+Левый Рука: шлепок своим, удар героям на своей земле help.k_pan = Тянуть правой Двигать карту (также WASD/стрелки, край экрана) help.k_rot = Тянуть средней Вращать и наклонять камеру (также Q/E, R/F) +help.k_reset = Средняя 2x щелчок Сбросить угол и поворот (место остаётся) help.k_zoom = Колесо мыши Масштаб help.k_tools = 1-9,0,X,V,K,J,B,C,T,U,Y,O Выбор инструмента help.k_misc = P / Пробел Пауза M Звук вкл/выкл +/- Громкость diff --git a/lang/sk.lang b/lang/sk.lang index a1150b5..ab81596 100644 --- a/lang/sk.lang +++ b/lang/sk.lang @@ -81,6 +81,7 @@ msg.no_mana_cost = Nedostatok many (treba {0}). hint.portal_no_lair = Portál je otvorený, ale bez brlohu žiadne tvory neprídu. hint.no_farm = Tvory chcú jesť: postav hubovú záhradu. hint.lair_full = Všetky lôžka v brlohu sú obsadené. Zväčši brloh. +hint.creature_max = Tvoja kobka má 100 tvorov - cez portál už ďalšie neprídu. hint.gate_attack = Tvoje tvory útočia na bránu hrdinov! hint.treasury_full = Tvoje pokladnice sú plné! Postav ďalšie políčka pokladnice. hint.flag_unreachable = Tvoje tvory sa k útočnej vlajke nedostanú. @@ -154,6 +155,7 @@ help.k_right = Pravé kliknutie Položiť jednotku (zajatcov aj do mučiarne) help.k_slap = Shift+Ľavé Ruka: zaucho vlastným, päsť hrdinom na tvojom území help.k_pan = Pravé ťahanie Posun mapy (aj WASD/šípky, okraj obrazovky) help.k_rot = Stredné ťahanie Otáčanie a nakláňanie kamery (aj Q/E, R/F) +help.k_reset = Stredné 2x klik Obnoviť uhol a otočenie (miesto zostane) help.k_zoom = Koliesko myši Zoom help.k_tools = 1-9,0,X,V,K,J,B,C,T,U,Y,O Voľba nástroja help.k_misc = P / Medzerník Pauza M Zvuk zap./vyp. +/- Hlasitosť diff --git a/lang/sr.lang b/lang/sr.lang index f506a76..93a9eeb 100644 --- a/lang/sr.lang +++ b/lang/sr.lang @@ -81,6 +81,7 @@ msg.no_mana_cost = Нема довољно мане (потребно {0}). hint.portal_no_lair = Портал је отворен, али без брлога ниједно створење неће доћи. hint.no_farm = Створења желе да једу: изгради врт печурака. hint.lair_full = Сви кревети у брлогу су заузети. Прошири брлог. +hint.creature_max = Твоја тамница има 100 створења - кроз портал их више не долази. hint.gate_attack = Твоја створења нападају Капију хероја! hint.treasury_full = Ризнице су пуне! Изгради још поља ризнице. hint.flag_unreachable = Твоја створења не могу да стигну до заставе напада. @@ -154,6 +155,7 @@ help.k_right = Десни клик Спусти јединицу (заро help.k_slap = Shift+леви Рука: ошамари своје јединице, удари хероје на свом тлу help.k_pan = Десно превлачење Помера мапу (и WASD/стрелице, ивица екрана) help.k_rot = Средње превлачење Окреће и нагиње камеру (и Q/E, R/F) +help.k_reset = Средњи 2x клик Врати угао и окрет (место остаје) help.k_zoom = Точкић миша Зумирање help.k_tools = 1-9,0,X,V,K,J,B,C,T,U,Y,O Избор алатке help.k_misc = P / Размак Пауза M Звук ук./иск. +/- Јачина diff --git a/lang/sv.lang b/lang/sv.lang index 98dd8d4..7901b20 100644 --- a/lang/sv.lang +++ b/lang/sv.lang @@ -81,6 +81,7 @@ msg.no_mana_cost = Inte tillräckligt med mana ({0} krävs). hint.portal_no_lair = Portalen är öppen, men utan näste kommer inga varelser. hint.no_farm = Varelserna vill äta: bygg en svampträdgård. hint.lair_full = Alla sängar i nästet är upptagna. Gör nästet större. +hint.creature_max = Din fängelsehåla rymmer 100 varelser - inga fler kommer genom portalen. hint.gate_attack = Dina varelser anfaller Hjälteporten! hint.treasury_full = Dina skattkammare är fulla! Bygg fler skattkammarrutor. hint.flag_unreachable = Dina varelser kan inte nå anfallsflaggan. @@ -154,6 +155,7 @@ help.k_right = Högerklick Släpp en enhet (fångar: även i tortyrkammaren help.k_slap = Shift+Vänster Hand: örfila egna enheter, slå hjältar på din mark help.k_pan = Högerdrag Flytta kartan (även WASD/pilar, skärmkanten) help.k_rot = Mittendrag Rotera och luta kameran (även Q/E, R/F) +help.k_reset = Mitten 2x klick Återställ vinkel och vridning (platsen kvar) help.k_zoom = Mushjul Zooma help.k_tools = 1-9,0,X,V,K,J,B,C,T,U,Y,O Välj verktyg help.k_misc = P / Mellanslag Paus M Ljud på/av +/- Volym diff --git a/src/game.rs b/src/game.rs index 3fea8fa..5576d02 100644 --- a/src/game.rs +++ b/src/game.rs @@ -94,6 +94,7 @@ pub struct SfxEvent { pub pos: Option<(f32, f32)>, // world position (for distance-based volume), None = UI } pub const MANA_MAX: f32 = 400.0; +pub const MAX_CREATURES: usize = 100; // creatures of one master (the beds decide below that) pub const SPRING_MANA: f32 = 0.6; // mana per second of each claimed mana spring pub const SPRING_MAX: f32 = 150.0; // more mana maximum per claimed spring pub const CARRY_MAX: i32 = 300; @@ -1925,7 +1926,14 @@ impl Game { pub fn free_lair_aerie(&self) -> (usize, usize) { let flyers = self.ents.iter().filter(|e| e.alive && e.creature() && flies(e.kind)).count(); let walkers = self.creature_count() - flyers; - (self.counts[1].min(30).saturating_sub(walkers), self.counts[7].min(20).saturating_sub(flyers)) + // a bed per lair tile (aerie: per aerie tile), never more than MAX_CREATURES in all + let room = MAX_CREATURES.saturating_sub(walkers + flyers); + (self.counts[1].saturating_sub(walkers).min(room), self.counts[7].saturating_sub(flyers).min(room)) + } + + // how many creatures this master can house: his beds, at most MAX_CREATURES + pub fn creature_cap(&self) -> usize { + (self.counts[1] + self.counts[7]).min(MAX_CREATURES) } pub fn lair_factor(&self) -> f32 { @@ -1955,6 +1963,10 @@ impl Game { self.hint(1, "hint.no_farm"); return; } + if self.creature_count() >= MAX_CREATURES { + self.hint(35, "hint.creature_max"); + return; + } let (free_lair, free_aerie) = self.free_lair_aerie(); if free_lair == 0 && free_aerie == 0 { self.hint(2, "hint.lair_full"); @@ -6861,6 +6873,44 @@ mod tests { assert!(g.ents.iter().filter(|e| e.kind == EK::Chainbreaker).count() <= 1); } + #[test] + fn the_beds_decide_how_many_creatures_come_but_never_more_than_100() { + let mut g = Game::new(9, 96, 96); + let (cx, cy) = g.map.core; + // a lair of 40 beds: room for 40 + let mut n = 0; + for y in cy + 4..cy + 20 { + for x in cx - 6..cx + 8 { + if n < 40 && inb(x, y) { + let t = &mut g.map.t[idx(x, y)]; + t.kind = Kind::Lair; + t.owner = Owner::Player; + n += 1; + } + } + } + g.recount(); + assert_eq!(g.creature_cap(), 40); + assert_eq!(g.free_lair_aerie().0, 40, "more than the old 30"); + // a huge lair: the cap is 100 + for y in cy + 4..cy + 20 { + for x in cx - 10..cx + 12 { + if inb(x, y) && g.map.t[idx(x, y)].kind != Kind::Core { + let t = &mut g.map.t[idx(x, y)]; + t.kind = Kind::Lair; + t.owner = Owner::Player; + } + } + } + g.recount(); + assert!(g.counts[1] > 100); + assert_eq!(g.creature_cap(), MAX_CREATURES); + for k in 0..100 { + g.spawn(EK::Kobold, false, cx as f32 + 0.5 + (k % 10) as f32, cy as f32 + 5.5 + (k / 10) as f32, 1); + } + assert_eq!(g.free_lair_aerie(), (0, 0), "no room for a 101st"); + } + #[test] fn creatures_never_make_their_bed_in_an_allys_lair() { let mut g = Game::new(11, 96, 128); diff --git a/src/main.rs b/src/main.rs index 8e82730..f3ae377 100644 --- a/src/main.rs +++ b/src/main.rs @@ -96,6 +96,7 @@ struct Input { rlast: (f32, f32), rdrag: bool, mlast: Option<(f32, f32)>, // middle button drag + mclick: f64, // time of the last middle click (a double click resets the view) minimap_drag: bool, // touch tlast: Option, // last position of a one-finger pan (device pixels) @@ -902,7 +903,7 @@ async fn main() { let mut app = App { game, cam, settings, seed, status: None, recorded: false, client: MatchClient::new(), ws_id: 0, match_mode: false, coop: false, coop_editor: false, coop_run: None, offline: false, tutorial: false, fps: 0.0, renderer: platform::renderer(), frame_ms: 0.0, frame_hist: [0.0; FRAME_HIST], frame_hist_pos: 0, custom_campaign: None, custom_progress: None, custom_mission_index: None, custom_next_index: None, editor: None, editor_testing: false, editor_test_only: false, editor_public_pending: false, editor_loading: None, pending_briefing: None }; menu.progress = platform::storage_get(PROGRESS_KEY).and_then(|s| serde_json::from_str(&s).ok()).unwrap_or_default(); apply_game_settings(&mut app.game, &app.settings); - let mut inp = Input { ldown: None, rdown: None, rlast: (0.0, 0.0), rdrag: false, mlast: None, minimap_drag: false, tlast: None, touch_world: false, inspect: None }; + let mut inp = Input { ldown: None, rdown: None, rlast: (0.0, 0.0), rdrag: false, mlast: None, mclick: -1.0, minimap_drag: false, tlast: None, touch_world: false, inspect: None }; let mut touch = TouchInput::new(); let mut auto_touch = platform::coarse_pointer(); let mut menu_swipe: Option<(f32, f32)> = None; // a swipe over a menu: last finger y, unused distance @@ -1329,6 +1330,16 @@ async fn main() { if is_key_down(key(Action::TiltDown)) { cam.pitch -= rot * 0.6; } + // a double click with the middle button: the standard angle and turn (same place) + if is_mouse_button_pressed(MouseButton::Middle) && !touch_mode { + let now = get_time(); + if now - inp.mclick < 0.35 { + cam.reset_view(); + inp.mclick = -1.0; + } else { + inp.mclick = now; + } + } if is_mouse_button_down(MouseButton::Middle) && !touch_mode { if let Some((lx, ly)) = inp.mlast { let inv = if keys.invert_mouse { -1.0 } else { 1.0 }; diff --git a/src/render3d.rs b/src/render3d.rs index aeef481..19751ea 100644 --- a/src/render3d.rs +++ b/src/render3d.rs @@ -34,6 +34,9 @@ pub struct Cam { pub render_init: bool, } +pub const DEFAULT_YAW: f32 = 0.785; +pub const DEFAULT_PITCH: f32 = 0.6155; + fn zero_f32() -> f32 { 0.0 } @@ -44,7 +47,13 @@ fn cam_uninit() -> bool { impl Cam { pub fn new(tx: f32, tz: f32) -> Cam { - Cam { tx, tz, yaw: 0.785, pitch: 0.6155, zoom: 18.0, rx: tx, rz: tz, render_init: true } + Cam { tx, tz, yaw: DEFAULT_YAW, pitch: DEFAULT_PITCH, zoom: 18.0, rx: tx, rz: tz, render_init: true } + } + + // the standard view angle and turn; the position and zoom stay + pub fn reset_view(&mut self) { + self.yaw = DEFAULT_YAW; + self.pitch = DEFAULT_PITCH; } pub fn snap(&mut self) { diff --git a/src/ui.rs b/src/ui.rs index 54d1f34..e92fdd1 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -741,7 +741,7 @@ impl Ui { Gap, } let txt = |s: String, c: Color| Part::T(s, c); - let cap = g.counts[1].min(30); + let cap = g.creature_cap(); let wave_col = if g.wave_timer < 30.0 { RED } else { TXT }; let vol = if settings.muted { tr("hud.off") } else { format!("{}%", (settings.volume * 100.0).round() as i32) }; let mut gold_seg = vec![txt(tr("hud.gold"), GOLD), Part::Gap, txt(format!("{}/{}", g.gold as i32, g.gold_cap() as i32), TXT)]; @@ -1026,6 +1026,42 @@ impl Ui { draw_line(mrx + a.x * ms, mry + a.y * ms, mrx + b.x * ms, mry + b.y * ms, px, WHITE); } } + // the camera: a monster's eye on the viewer's side of the footprint, looking in + { + let near = (corners[2] + corners[3]) * 0.5; + let look = vec2(-cam.yaw.sin(), -cam.yaw.cos()); // from the eye towards the target (map units) + let r = (4.0 * px).max(ms * 2.5); + let (ex, ey) = (mrx + near.x * ms - look.x * r * 1.6, mry + near.y * ms - look.y * r * 1.6); + let (ex, ey) = (ex.clamp(mrx + r, mrx + map_w - r), ey.clamp(mry + r, mry + map_h - r)); + let side = vec2(-look.y, look.x); + // the lids: an almond across the view direction + let lid = |t: f32, w: f32| vec2(ex, ey) + side * (t * r * 1.25) + look * w; + let n = 8; + let mut upper = Vec::new(); + let mut lower = Vec::new(); + for k in 0..=n { + let t = k as f32 / n as f32 * 2.0 - 1.0; + let h = (1.0 - t * t).max(0.0).sqrt() * r * 0.75; + upper.push(lid(t, h)); + lower.push(lid(t, -h)); + } + let c = vec2(ex, ey); + let sclera = Color::new(0.95, 0.85, 0.35, 1.0); + for k in 0..n { + draw_triangle(c, upper[k], upper[k + 1], sclera); + draw_triangle(c, lower[k], lower[k + 1], sclera); + } + // the iris looks towards the target, with a slit pupil across it + let iris = c + look * (r * 0.2); + draw_circle(iris.x, iris.y, r * 0.55, Color::new(0.85, 0.3, 0.08, 1.0)); + let a = iris + side * (r * 0.45); + let b = iris - side * (r * 0.45); + draw_line(a.x, a.y, b.x, b.y, (r * 0.22).max(px), Color::new(0.05, 0.0, 0.02, 1.0)); + for k in 0..n { + draw_line(upper[k].x, upper[k].y, upper[k + 1].x, upper[k + 1].y, px.max(1.0), Color::new(0.2, 0.05, 0.08, 1.0)); + draw_line(lower[k].x, lower[k].y, lower[k + 1].x, lower[k + 1].y, px.max(1.0), Color::new(0.2, 0.05, 0.08, 1.0)); + } + } // ---------------- mission goals (campaign) if let Some(m) = &g.mission { @@ -1327,7 +1363,7 @@ impl Ui { let controls: &[&str] = if touch_ui() { &["help.t_tap", "help.t_drag", "help.t_two", "help.t_long", "help.t_double", "help.t_tools"] } else { - &["help.k_left", "help.k_right", "help.k_slap", "help.k_pan", "help.k_rot", "help.k_zoom", "help.k_tools", "help.k_misc", "help.k_misc2"] + &["help.k_left", "help.k_right", "help.k_slap", "help.k_pan", "help.k_rot", "help.k_reset", "help.k_zoom", "help.k_tools", "help.k_misc", "help.k_misc2"] }; let mut keys: Vec<(&str, Color)> = vec![("help.goal", GOLD), ("", TXT)]; keys.extend(controls.iter().map(|k| (*k, TXT)));