diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 62ab14f..d040175 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -125,8 +125,10 @@ grid), guard and attack markers (shields and swords), savegames with the game st claim, mine and set torches; rooms by plan, traps, towers, research; the attack flag, shields and swords; strength by the difficulty. 2. **Mouse cursor** (done, v202611-00053) - clearer hands for the hand tool (open, holding, slap, punch). -3. **New heroes** - thief (steals gold, from wave 3), monk (immune to spells, 5), ranger (lays traps, 7), - inquisitor (converts the weakest creatures back, 9). +3. **New heroes** (done, v202611-00063, rogues.rs) - thief (sneaks to a treasury, steals up to 250 gold and runs + to the gate; slain, his loot is yours; from wave 3), monk (spells do not touch him, 5), ranger (shoots, lays + snares that hurt and stun a creature, 7), inquisitor (fragile, every 20 s turns a nearby kobold or spider to + the heroes, 9). In the campaign from missions 5, 9, 12 and 16 on. 4. **Master talents** - Builder, Warlord, Warlock, Merchant (5 levels each), a toolbar button; per game, carried over in the campaign. 5. **Weather above ground** - rain (puts out fire), fog (less sight), storms (lightning in trees and units). diff --git a/lang/cs.lang b/lang/cs.lang index 963f27b..a34d69d 100644 --- a/lang/cs.lang +++ b/lang/cs.lang @@ -64,6 +64,10 @@ msg.gate_boss = Brána se hroutí! Objevuje se strážce brány s obránci ({0}) msg.gate_defenders = Brána povolává obránce ({0})! msg.level_up = {0} dosahuje úrovně {1}. msg.hero_slain = Poražen: {0}! Kořist: {1} zlata. +msg.thief_in_treasury = V tvé pokladnici je zloděj! +msg.thief_escaped = Zloděj utekl s {0} zlata! +msg.snare_caught = Do pasti šlápl: {0}! +msg.converted = Inkvizitor obrátil jednoho z tvých tvorů: {0}! msg.creature_died = Padl tvůj tvor: {0}. msg.portal_claimed = Portál je tvůj! Přitahuje tvory. msg.flag_removed = Útočná vlajka odstraněna. Tví tvorové se vracejí. @@ -1090,12 +1094,20 @@ ability.drain.desc = léčí se o třetinu poškození, které způsobí. unit.giant = Obr unit.fairy = Vílí špeh unit.battlemage = Bitevní mág +unit.thief = Zloděj +unit.monk = Mnich +unit.ranger = Hraničář +unit.inquisitor = Inkvizitor unit.ram = Beranidlo unit.catapult = Katapult msg.trap_wrecked = Hrdinové zničili past: {0}. best.giant.text = Obr je to, co se stane, když rytíř tři sta let jí zeleninu. Pomalý, obrovský a dveře bere jako pouhý návrh. | Pasti ničí už tím, že stojí vedle nich. Odporné způsoby. Bij ho vším, co máš, nejlépe z dálky. best.fairy.text = Malý udavač Řádu: zářící komár s křídly, poslaný napřed, aby našel tvé pasti a všem to vykecal. Jakmile past uvidí, hrdinové ji rozbijí. | Navíc sype na hrdiny léčivý prášek. Plácni ji první. Dvakrát, pro jistotu. best.battlemage.text = Mág v rouchu Řádu, který považuje zdi za osobní urážku. Zpevněné zdi pod jeho ohnivými koulemi praskají a on o tom nepřestane mluvit. | Zblízka křehký. Nejvíc ho štvou ocelové zdi - dobře. +best.thief.text = Rychlé prsty, ještě rychlejší nohy. Nepřichází bojovat: vplíží se do tvé pokladnice, naplní si pytel a utíká zpátky k bráně. | Zabij ho dřív, než uteče, a zlato je zase tvoje - i s úroky. +best.monk.text = Roky půstu a modliteb ho učinily hluchým k tvé magii: blesk, mor i mráz z něj stékají jako déšť ze střechy. | Pěsti taky bolí. Přivítej ho ocelí, drápy a zuby. +best.ranger.text = Lesník Řádu, který střílí z dálky a nastražuje v tvých chodbách železné pasti. Tvor, který do jedné šlápne, je zraněn a chvíli uvízne. | Pasti zůstávají, dokud do nich někdo nešlápne. Raději kobold než tvůj zlobr. +best.inquisitor.text = Křehký, ale jeho kázání jsou nebezpečná: každých dvacet sekund přemluví jednoho z tvých nejslabších tvorů - kobolda nebo pavouka -, aby přešel k hrdinům. | Silní tvorové se mu jen vysmějí. Udeř první. best.ram.text = Kmen s železnou hlavicí a stříškou proti šípům. Tvé bytosti ho nezajímají – tvé dveře, zdi a věže ano. | Zastav ho před dveřmi, nebo si sežeň nové. best.catapult.text = Dřevěné rameno, vědro kamení a rytíř s příliš mnoha volnými chvílemi. Střílí dál než tvé věže a míří nejprve na ně. | Vrhni se na něj: zblízka neublíží ani mouše. diff --git a/lang/da.lang b/lang/da.lang index 3fe7169..1ea720f 100644 --- a/lang/da.lang +++ b/lang/da.lang @@ -64,6 +64,10 @@ msg.gate_boss = Porten smuldrer! Portvogteren dukker op med {0} forsvarere! msg.gate_defenders = Porten tilkalder {0} forsvarere! msg.level_up = {0} når niveau {1}. msg.hero_slain = {0} besejret! Bytte: {1} guld. +msg.thief_in_treasury = En tyv er i dit skatkammer! +msg.thief_escaped = En tyv slap væk med {0} guld! +msg.snare_caught = Trådt i en saks: {0}! +msg.converted = Inkvisitoren har omvendt et af dine væsner: {0}! msg.creature_died = Din {0} er faldet. msg.portal_claimed = Portalen er din! Den tiltrækker væsner. msg.flag_removed = Angrebsflaget er fjernet. Dine væsner vender tilbage. @@ -1089,12 +1093,20 @@ ability.drain.desc = heler sig selv med en tredjedel af den skade, den giver. unit.giant = Kæmpe unit.fairy = Feespion unit.battlemage = Kampmagiker +unit.thief = Tyv +unit.monk = Munk +unit.ranger = Jæger +unit.inquisitor = Inkvisitor unit.ram = Rambuk unit.catapult = Katapult msg.trap_wrecked = Heltene ødelagde en fælde: {0}. best.giant.text = En kæmpe er, hvad der sker, når en ridder spiser sine grøntsager i tre hundrede år. Langsom, enorm, og den betragter døre som et forslag. | Den ødelægger fælder bare ved at stå ved siden af dem. Væmmelige manerer. Ram den med alt, helst på afstand. best.fairy.text = Ordenens lille stikker: en glødende myg med vinger, sendt i forvejen for at finde dine fælder og fortælle alle om dem. Når den har set en fælde, smadrer heltene den. | Den drysser også helende støv på heltene. Smæk den først. To gange, for en sikkerheds skyld. best.battlemage.text = En magiker i Ordenens kåbe, der opfatter mure som en personlig fornærmelse. Forstærkede mure brister under hans ildkugler, og han holder aldrig op med at tale om det. | Skrøbelig på nært hold. Stålmure irriterer ham mest - godt. +best.thief.text = Hurtige fingre, endnu hurtigere fødder. Han kommer ikke for at kæmpe: han sniger sig ind i dit skatkammer, fylder sin sæk og løber tilbage til porten. | Dræb ham, før han slipper væk, og guldet er dit igen - med renter. +best.monk.text = Års faste og bøn har gjort ham døv for din magi: lyn, pest og frost preller af på ham som regn på et tag. | Knytnæver gør også ondt. Mød ham med stål, kløer og tænder. +best.ranger.text = En skovmand fra Ordenen, der skyder på afstand og lægger jernsakse ud i dine gange. Et væsen, der træder i en, bliver såret og sidder fast et stykke tid. | Saksene bliver liggende, til nogen træder i dem. Hellere en kobold end din trold. +best.inquisitor.text = Skrøbelig, men hans prædikener er farlige: hvert tyvende sekund taler han et af dine svageste væsner - en kobold eller en edderkop - over på heltenes side. | Stærke væsner griner bare af ham. Slå til først. best.ram.text = En træstamme med jernhætte og et tag mod pile. Dine væsner er ligegyldige for den – dine døre, mure og tårne ikke. | Stop den, før den når døren, eller skaf en ny dør. best.catapult.text = En træarm, en spand sten og en ridder med for meget fritid. Den rækker længere end dine tårne og sigter efter dem først. | Storm frem: på nært hold gør den ikke en flue fortræd. diff --git a/lang/de.lang b/lang/de.lang index 4d89ae7..123bf1f 100644 --- a/lang/de.lang +++ b/lang/de.lang @@ -63,6 +63,10 @@ msg.gate_boss = Das Tor wankt! Der Torwächter erscheint mit {0} Verteidigern! msg.gate_defenders = Das Tor ruft {0} Verteidiger herbei! msg.level_up = {0} erreicht Stufe {1}. msg.hero_slain = {0} besiegt! Beute: {1} Gold. +msg.thief_in_treasury = Ein Dieb ist in deiner Schatzkammer! +msg.thief_escaped = Ein Dieb ist mit {0} Gold entkommen! +msg.snare_caught = In eine Falle getreten: {0}! +msg.converted = Der Inquisitor hat eine deiner Kreaturen bekehrt: {0}! msg.creature_died = Dein {0} ist gefallen. msg.portal_claimed = Das Portal gehört nun dir! Kreaturen werden davon angelockt. msg.flag_removed = Angriffsflagge entfernt. Deine Kreaturen kehren zurück. @@ -1089,12 +1093,20 @@ ability.drain.desc = heilt sich um ein Drittel des Schadens, den er austeilt. unit.giant = Riese unit.fairy = Feenspion unit.battlemage = Kampfmagier +unit.thief = Dieb +unit.monk = Mönch +unit.ranger = Waldläufer +unit.inquisitor = Inquisitor unit.ram = Rammbock unit.catapult = Katapult msg.trap_wrecked = Die Helden haben eine Falle zerstört: {0}. best.giant.text = Ein Riese ist, was passiert, wenn ein Ritter dreihundert Jahre lang sein Gemüse isst. Langsam, gewaltig, und Türen hält er für einen Vorschlag. | Fallen zertrümmert er, indem er einfach danebensteht. Widerliche Manieren. Bearbeite ihn mit allem, am besten aus der Ferne. best.fairy.text = Der kleine Spitzel des Ordens: eine leuchtende Mücke mit Flügeln, vorausgeschickt, um deine Fallen zu finden und es allen zu erzählen. Hat sie eine Falle gesehen, schlagen die Helden sie kaputt. | Außerdem streut sie Heilstaub auf die Helden. Erschlag sie zuerst. Zweimal, sicherheitshalber. best.battlemage.text = Ein Magier in der Robe des Ordens, der Mauern als persönliche Beleidigung empfindet. Verstärkte Wände zerplatzen unter seinen Feuerbällen, und er hört nicht auf, davon zu reden. | Aus der Nähe zerbrechlich. Stahlwände ärgern ihn am meisten - gut so. +best.thief.text = Flinke Finger, noch flinkere Füße. Er kommt nicht zum Kämpfen: Er schleicht in deine Schatzkammer, füllt seinen Sack und rennt zurück zum Tor. | Erwisch ihn, bevor er entkommt, und das Gold gehört wieder dir - mit Zinsen. +best.monk.text = Jahre des Fastens und Betens haben ihn taub für deine Magie gemacht: Blitz, Seuche und Frost perlen an ihm ab wie Regen am Dach. | Fäuste tun auch weh. Begegne ihm mit Stahl, Klauen und Zähnen. +best.ranger.text = Ein Waldmann des Ordens, der aus der Ferne schießt und eiserne Fallen in deinen Gängen auslegt. Wer hineintritt, wird verletzt und steckt eine Weile fest. | Die Fallen bleiben, bis jemand hineintritt. Lieber ein Kobold als dein Oger. +best.inquisitor.text = Gebrechlich, aber seine Predigten sind gefährlich: Alle zwanzig Sekunden redet er eine deiner schwächsten Kreaturen - einen Kobold oder eine Spinne - auf die Seite der Helden. | Starke Kreaturen lachen ihn nur aus. Schlag zuerst zu. best.ram.text = Ein Baumstamm mit Eisenkappe und einem Dach gegen Pfeile. Deine Kreaturen sind ihm egal – nur deine Türen, Wände und Türme nicht. | Halte ihn auf, bevor er die Tür erreicht, oder besorg dir eine neue. best.catapult.text = Ein Holzarm, ein Eimer Steine und ein Ritter mit zu viel Zeit. Es schießt weiter als deine Türme und nimmt sie zuerst ins Visier. | Stürm drauf los: aus der Nähe tut es keiner Fliege etwas. diff --git a/lang/el.lang b/lang/el.lang index 53b7551..940631a 100644 --- a/lang/el.lang +++ b/lang/el.lang @@ -64,6 +64,10 @@ msg.gate_boss = Η πύλη καταρρέει! Ο Φύλακας της Πύλ msg.gate_defenders = Η πύλη καλεί {0} υπερασπιστές! msg.level_up = {0}: φτάνει στο επίπεδο {1}. msg.hero_slain = Νικήθηκε: {0}! Λάφυρα: {1} χρυσός. +msg.thief_in_treasury = Ένας κλέφτης είναι στο θησαυροφυλάκιό σου! +msg.thief_escaped = Ένας κλέφτης ξέφυγε με {0} χρυσό! +msg.snare_caught = Πάτησε σε παγίδα: {0}! +msg.converted = Ο ιεροεξεταστής προσηλύτισε ένα από τα πλάσματά σου: {0}! msg.creature_died = Έπεσε: {0}. msg.portal_claimed = Η πύλη μετάβασης είναι δική σου! Προσελκύει πλάσματα. msg.flag_removed = Η σημαία επίθεσης αφαιρέθηκε. Τα πλάσματά σου επιστρέφουν. @@ -1090,12 +1094,20 @@ ability.drain.desc = γιατρεύεται κατά το ένα τρίτο τη unit.giant = Γίγαντας unit.fairy = Νεράιδα Κατάσκοπος unit.battlemage = Μάγος Μάχης +unit.thief = Κλέφτης +unit.monk = Μοναχός +unit.ranger = Δασοφύλακας +unit.inquisitor = Ιεροεξεταστής unit.ram = Πολιορκητικός κριός unit.catapult = Καταπέλτης msg.trap_wrecked = Οι ήρωες κατέστρεψαν μια παγίδα: {0}. best.giant.text = Γίγαντας είναι ό,τι γίνεται όταν ένας ιππότης τρώει τα λαχανικά του για τριακόσια χρόνια. Αργός, τεράστιος, και θεωρεί τις πόρτες απλή πρόταση. | Καταστρέφει παγίδες απλώς στεκόμενος δίπλα τους. Αποκρουστικοί τρόποι. Χτύπα τον με ό,τι έχεις, κατά προτίμηση από μακριά. best.fairy.text = Ο μικρός καταδότης του Τάγματος: μια φωτεινή σκνίπα με φτερά, που στέλνεται μπροστά να βρει τις παγίδες σου και να τα πει σε όλους. Μόλις δει μια παγίδα, οι ήρωες τη σπάνε. | Ραντίζει επίσης τους ήρωες με θεραπευτική σκόνη. Λιώσ' την πρώτη. Δύο φορές, για σιγουριά. best.battlemage.text = Ένας μάγος με τον χιτώνα του Τάγματος που θεωρεί τους τοίχους προσωπική προσβολή. Οι ενισχυμένοι τοίχοι σκάνε κάτω από τις πύρινες σφαίρες του, και δεν σταματά ποτέ να το λέει. | Εύθραυστος από κοντά. Οι ατσάλινοι τοίχοι τον εκνευρίζουν περισσότερο - ωραία. +best.thief.text = Γρήγορα δάχτυλα, ακόμα πιο γρήγορα πόδια. Δεν έρχεται για να πολεμήσει: γλιστράει στο θησαυροφυλάκιό σου, γεμίζει το σακί του και τρέχει πίσω στην πύλη. | Σκότωσέ τον πριν ξεφύγει και ο χρυσός είναι ξανά δικός σου - με τόκο. +best.monk.text = Χρόνια νηστείας και προσευχής τον έκαναν κουφό στη μαγεία σου: ο κεραυνός, η πανούκλα και ο παγετός γλιστρούν πάνω του σαν βροχή σε στέγη. | Και οι γροθιές πονάνε. Υποδέξου τον με ατσάλι, νύχια και δόντια. +best.ranger.text = Ένας άνθρωπος του δάσους από το Τάγμα που ρίχνει από μακριά και αφήνει σιδερένιες παγίδες στους διαδρόμους σου. Όποιο πλάσμα πατήσει σε μία τραυματίζεται και κολλάει για λίγο. | Οι παγίδες μένουν ώσπου να πατήσει κάποιος μέσα. Καλύτερα ένας κόμπολντ παρά ο όγκρος σου. +best.inquisitor.text = Ασθενικός, αλλά τα κηρύγματά του είναι επικίνδυνα: κάθε είκοσι δευτερόλεπτα πείθει ένα από τα πιο αδύναμα πλάσματά σου - έναν κόμπολντ ή μια αράχνη - να περάσει στους ήρωες. | Τα δυνατά πλάσματα απλώς τον κοροϊδεύουν. Χτύπα πρώτος. best.ram.text = Ένας κορμός με σιδερένια κεφαλή και στέγη για τα βέλη. Τα πλάσματά σου δεν τον νοιάζουν – οι πόρτες, οι τοίχοι και οι πύργοι σου ναι. | Σταμάτα τον πριν φτάσει στην πόρτα, ή βρες καινούργια. best.catapult.text = Ένας ξύλινος βραχίονας, ένας κουβάς πέτρες και ένας ιππότης με πολύ ελεύθερο χρόνο. Βάλλει πιο μακριά από τους πύργους σου και τους σημαδεύει πρώτους. | Όρμα του: από κοντά δεν πειράζει ούτε μύγα. diff --git a/lang/en.lang b/lang/en.lang index 16ad566..31cce4b 100644 --- a/lang/en.lang +++ b/lang/en.lang @@ -64,6 +64,10 @@ msg.gate_boss = The gate is crumbling! The Gate Warden appears with {0} defender msg.gate_defenders = The gate summons {0} defenders! msg.level_up = {0} reaches level {1}. msg.hero_slain = {0} defeated! Loot: {1} gold. +msg.thief_in_treasury = A thief is in your treasury! +msg.thief_escaped = A thief escaped with {0} gold! +msg.snare_caught = Your {0} stepped into a snare! +msg.converted = The inquisitor turned your {0} against you! msg.creature_died = Your {0} has fallen. msg.portal_claimed = The portal is yours! It attracts creatures. msg.flag_removed = Attack flag removed. Your creatures return. @@ -1090,12 +1094,20 @@ ability.drain.desc = heals itself by a third of the damage it deals. unit.giant = Giant unit.fairy = Fairy Spy unit.battlemage = Battle Mage +unit.thief = Thief +unit.monk = Monk +unit.ranger = Ranger +unit.inquisitor = Inquisitor unit.ram = Battering ram unit.catapult = Catapult msg.trap_wrecked = The heroes wrecked a trap: {0}. best.giant.text = A giant is what happens when a knight eats his vegetables for three hundred years. Slow, enormous, and it treats doors as a suggestion. | It wrecks traps simply by standing next to them. Revolting manners. Hit it with everything, preferably from afar. best.fairy.text = The Order's little informer: a glowing gnat with wings, sent ahead to find your traps and tell everybody. Once it has seen a trap, the heroes smash it. | It also sprinkles healing dust on the heroes. Swat it first. Twice, to be sure. best.battlemage.text = A mage in the Order's robes who thinks walls are a personal insult. Reinforced walls burst under his fireballs, and he never stops talking about it. | Fragile up close. Steel walls annoy him most - good. +best.thief.text = Quick fingers, quicker feet. He does not come to fight: he sneaks into your treasury, fills his sack and runs back to the gate. | Kill him before he gets away and the gold is yours again - with interest. +best.monk.text = Years of fasting and praying have made him deaf to your magic: lightning, plague and frost slide off him like rain off a roof. | Fists hurt too. Meet him with steel, claws and teeth. +best.ranger.text = A woodsman of the Order who shoots from afar and leaves iron snares in your corridors. A creature that steps into one is hurt and stuck for a while. | Snares stay until something steps in. Better a kobold than your ogre. +best.inquisitor.text = Frail, but his sermons are dangerous: every twenty seconds he talks one of your weakest creatures - a kobold or a spider - into joining the heroes. | Strong creatures just laugh at him. Hit him first. best.ram.text = A tree trunk with an iron cap and a roof against arrows. It does not care for your creatures – only for your doors, walls and towers. | Stop it before it reaches the door, or get a new door. best.catapult.text = A wooden arm, a bucket of rocks and a knight with too much spare time. It outranges your towers and aims for them first. | Rush it: up close it cannot hurt a fly. diff --git a/lang/es.lang b/lang/es.lang index bc7f968..0d5cf8c 100644 --- a/lang/es.lang +++ b/lang/es.lang @@ -64,6 +64,10 @@ msg.gate_boss = ¡La puerta se desmorona! ¡El Guardián de la Puerta aparece co msg.gate_defenders = ¡La puerta invoca a {0} defensores! msg.level_up = {0} alcanza el nivel {1}. msg.hero_slain = ¡{0} derrotado! Botín: {1} de oro. +msg.thief_in_treasury = ¡Hay un ladrón en tu tesorería! +msg.thief_escaped = ¡Un ladrón ha escapado con {0} de oro! +msg.snare_caught = ¡Ha caído en un cepo: {0}! +msg.converted = ¡El inquisidor ha convertido a una de tus criaturas: {0}! msg.creature_died = Tu {0} ha caído. msg.portal_claimed = ¡El portal es tuyo! Atrae a las criaturas. msg.flag_removed = Bandera de ataque retirada. Tus criaturas regresan. @@ -1082,12 +1086,20 @@ ability.drain.desc = se cura un tercio del daño que inflige. unit.giant = Gigante unit.fairy = Hada espía unit.battlemage = Mago de batalla +unit.thief = Ladrón +unit.monk = Monje +unit.ranger = Explorador +unit.inquisitor = Inquisidor unit.ram = Ariete unit.catapult = Catapulta msg.trap_wrecked = Los héroes han destrozado una trampa: {0}. best.giant.text = Un gigante es lo que pasa cuando un caballero se come la verdura durante trescientos años. Lento, enorme, y trata las puertas como una sugerencia. | Destroza trampas con solo plantarse a su lado. Modales repugnantes. Golpéalo con todo, a ser posible desde lejos. best.fairy.text = La pequeña chivata de la Orden: un mosquito brillante con alas, enviado por delante para encontrar tus trampas y contárselo a todos. Cuando ha visto una trampa, los héroes la destrozan. | También rocía polvo curativo sobre los héroes. Aplástala primero. Dos veces, por si acaso. best.battlemage.text = Un mago con el hábito de la Orden que considera los muros un insulto personal. Los muros reforzados revientan bajo sus bolas de fuego, y nunca deja de hablar de ello. | Frágil de cerca. Lo que más le fastidia son los muros de acero. Bien. +best.thief.text = Dedos rápidos, pies aún más rápidos. No viene a luchar: se cuela en tu tesorería, llena su saco y corre de vuelta a la puerta. | Mátalo antes de que escape y el oro vuelve a ser tuyo. Con intereses. +best.monk.text = Años de ayuno y oración lo han vuelto sordo a tu magia: el rayo, la plaga y el frío le resbalan como la lluvia por un tejado. | Los puños también duelen. Recíbelo con acero, garras y dientes. +best.ranger.text = Un hombre de los bosques de la Orden que dispara desde lejos y deja cepos de hierro en tus pasillos. La criatura que pisa uno queda herida y atrapada un rato. | Los cepos siguen ahí hasta que alguien los pisa. Mejor un kóbold que tu ogro. +best.inquisitor.text = Frágil, pero sus sermones son peligrosos: cada veinte segundos convence a una de tus criaturas más débiles (un kóbold o una araña) de unirse a los héroes. | Las criaturas fuertes se ríen de él. Golpea tú primero. best.ram.text = Un tronco con punta de hierro y un tejado contra las flechas. Tus criaturas le dan igual; tus puertas, muros y torres no. | Detenlo antes de que llegue a la puerta, o búscate otra puerta. best.catapult.text = Un brazo de madera, un cubo de piedras y un caballero con demasiado tiempo libre. Alcanza más lejos que tus torres y apunta a ellas primero. | Lánzate sobre ella: de cerca no hace daño ni a una mosca. diff --git a/lang/fi.lang b/lang/fi.lang index 6be8229..1de78a6 100644 --- a/lang/fi.lang +++ b/lang/fi.lang @@ -64,6 +64,10 @@ msg.gate_boss = Portti horjuu! Portinvartija ilmestyy, mukanaan {0} puolustajaa! msg.gate_defenders = Portti kutsuu {0} puolustajaa! msg.level_up = {0} nousee tasolle {1}. msg.hero_slain = Kaatui: {0}! Saalis: {1} kultaa. +msg.thief_in_treasury = Varas on aarreaitassasi! +msg.thief_escaped = Varas pakeni {0} kullan kanssa! +msg.snare_caught = Astui ansaan: {0}! +msg.converted = Inkvisiittori käännytti yhden olennoistasi: {0}! msg.creature_died = Olentosi kaatui: {0}. msg.portal_claimed = Portaali on sinun! Se houkuttelee olentoja. msg.flag_removed = Hyökkäyslippu poistettu. Olentosi palaavat. @@ -1090,12 +1094,20 @@ ability.drain.desc = parantaa itseään kolmanneksella aiheuttamastaan vahingost unit.giant = Jättiläinen unit.fairy = Keijuvakooja unit.battlemage = Taistelumaagi +unit.thief = Varas +unit.monk = Munkki +unit.ranger = Samooja +unit.inquisitor = Inkvisiittori unit.ram = Muurinmurtaja unit.catapult = Katapultti msg.trap_wrecked = Sankarit romuttivat ansan: {0}. best.giant.text = Jättiläinen on se, mitä tapahtuu, kun ritari syö vihanneksensa kolmensadan vuoden ajan. Hidas, valtava, ja ovet ovat sille pelkkä ehdotus. | Se romuttaa ansat pelkästään seisomalla niiden vieressä. Kuvottavat tavat. Lyö sitä kaikella, mieluiten kaukaa. best.fairy.text = Ritarikunnan pieni ilmiantaja: hehkuva siivekäs mäkärä, joka lähetetään edeltä etsimään ansasi ja kertomaan kaikille. Kun se on nähnyt ansan, sankarit murskaavat sen. | Se myös sirottelee parantavaa pölyä sankarien päälle. Läimäise se ensin. Kahdesti, varmuuden vuoksi. best.battlemage.text = Maagi ritarikunnan kaavussa, joka pitää muureja henkilökohtaisena loukkauksena. Vahvistetut seinät halkeavat hänen tulipallojensa alla, eikä hän lakkaa puhumasta siitä. | Hauras lähietäisyydellä. Teräsmuurit ärsyttävät häntä eniten - hyvä. +best.thief.text = Nopeat sormet, vielä nopeammat jalat. Hän ei tule taistelemaan: hän hiipii aarreaittaasi, täyttää säkkinsä ja juoksee takaisin portille. | Tapa hänet ennen kuin hän pääsee karkuun, niin kulta on taas sinun - korkojen kera. +best.monk.text = Vuosien paasto ja rukous ovat tehneet hänestä kuuron taikuudellesi: salama, rutto ja halla valuvat hänestä kuin sade katolta. | Nyrkitkin sattuvat. Ota hänet vastaan teräksellä, kynsillä ja hampailla. +best.ranger.text = Ritarikunnan metsämies, joka ampuu kaukaa ja jättää rautaisia ansoja käytäviisi. Ansaan astuva olento haavoittuu ja jää hetkeksi jumiin. | Ansat pysyvät, kunnes joku astuu niihin. Mieluummin koboldi kuin hiisisi. +best.inquisitor.text = Hauras, mutta hänen saarnansa ovat vaarallisia: kahdenkymmenen sekunnin välein hän puhuu jonkin heikoimmista olennoistasi - koboldin tai hämähäkin - sankarien puolelle. | Vahvat olennot vain nauravat hänelle. Iske ensin. best.ram.text = Puunrunko rautakärjellä ja katto nuolia vastaan. Olentosi eivät sitä kiinnosta – ovesi, muurisi ja tornisi kyllä. | Pysäytä se ennen ovea tai hanki uusi ovi. best.catapult.text = Puinen varsi, ämpäri kiviä ja ritari, jolla on liikaa vapaa-aikaa. Se ampuu torneja kauempaa ja tähtää niihin ensin. | Ryntää sen kimppuun: läheltä se ei vahingoita kärpästäkään. diff --git a/lang/hr.lang b/lang/hr.lang index 7204422..cb42757 100644 --- a/lang/hr.lang +++ b/lang/hr.lang @@ -64,6 +64,10 @@ msg.gate_boss = Vrata se urušavaju! Pojavljuje se Čuvar vrata s braniteljima ( msg.gate_defenders = Vrata dozivaju branitelje: {0}! msg.level_up = {0} doseže razinu {1}. msg.hero_slain = Poražen: {0}! Plijen: {1} zlata. +msg.thief_in_treasury = Lopov je u tvojoj riznici! +msg.thief_escaped = Lopov je pobjegao s {0} zlata! +msg.snare_caught = Stalo je u zamku: {0}! +msg.converted = Inkvizitor je preobratio jedno tvoje stvorenje: {0}! msg.creature_died = Palo je tvoje stvorenje: {0}. msg.portal_claimed = Portal je tvoj! Privlači stvorenja. msg.flag_removed = Zastava napada uklonjena. Stvorenja se vraćaju. @@ -1090,12 +1094,20 @@ ability.drain.desc = liječi se za trećinu štete koju nanese. unit.giant = Div unit.fairy = Vila uhoda unit.battlemage = Bojni mag +unit.thief = Lopov +unit.monk = Redovnik +unit.ranger = Lovac +unit.inquisitor = Inkvizitor unit.ram = Ovan unit.catapult = Katapult msg.trap_wrecked = Junaci su uništili zamku: {0}. best.giant.text = Div je ono što se dogodi kad vitez tristo godina jede povrće. Spor, golem, a vrata smatra prijedlogom. | Zamke uništava samim tim što stoji pokraj njih. Odvratno ponašanje. Udri ga svime, najbolje izdaleka. best.fairy.text = Mali doušnik Reda: svjetleća mušica s krilima, poslana naprijed da pronađe tvoje zamke i svima ih oda. Kad jednom vidi zamku, junaci je razbiju. | Usto posipa junake ljekovitim prahom. Zgnječi je prvu. Dvaput, za svaki slučaj. best.battlemage.text = Mag u halji Reda koji zidove smatra osobnom uvredom. Ojačani zidovi pucaju pod njegovim vatrenim kuglama, a on o tome neprestano priča. | Krhak izbliza. Čelični zidovi najviše ga živciraju - dobro. +best.thief.text = Brzi prsti, još brže noge. Ne dolazi se boriti: ušulja se u tvoju riznicu, napuni vreću i otrči natrag do vrata. | Ubij ga prije nego pobjegne i zlato je opet tvoje - s kamatama. +best.monk.text = Godine posta i molitve učinile su ga gluhim za tvoju magiju: munja, kuga i mraz klize s njega kao kiša s krova. | I šake bole. Dočekaj ga čelikom, pandžama i zubima. +best.ranger.text = Šumar Reda koji puca izdaleka i ostavlja željezne zamke u tvojim hodnicima. Stvorenje koje stane u jednu ranjeno je i neko vrijeme zaglavljeno. | Zamke ostaju dok netko ne stane u njih. Bolje kobold nego tvoj ogr. +best.inquisitor.text = Krhak, ali su mu propovijedi opasne: svakih dvadeset sekundi nagovori jedno od tvojih najslabijih stvorenja - kobolda ili pauka - da prijeđe junacima. | Jaka stvorenja mu se samo smiju. Udari prvi. best.ram.text = Deblo sa željeznom kapom i krovom protiv strijela. Tvoja stvorenja ga ne zanimaju – tvoja vrata, zidovi i tornjevi da. | Zaustavi ga prije vrata ili nabavi nova vrata. best.catapult.text = Drvena ruka, kanta kamenja i vitez s previše slobodnog vremena. Gađa dalje od tvojih tornjeva i cilja ih prve. | Jurni na nj: izbliza ni muhi ne nanosi zlo. diff --git a/lang/hu.lang b/lang/hu.lang index ebb0243..c988d11 100644 --- a/lang/hu.lang +++ b/lang/hu.lang @@ -64,6 +64,10 @@ msg.gate_boss = A kapu omladozik! Megjelent a Kapuőr {0} védelmezővel! msg.gate_defenders = A kapu {0} védelmezőt idéz! msg.level_up = {0} elérte ezt a szintet: {1}. msg.hero_slain = Legyőzve: {0}! Zsákmány: {1} arany. +msg.thief_in_treasury = Egy tolvaj van a kincstáradban! +msg.thief_escaped = Egy tolvaj megszökött {0} arannyal! +msg.snare_caught = Csapdába lépett: {0}! +msg.converted = Az inkvizítor megtérítette egyik lényedet: {0}! msg.creature_died = Elesett: {0}. msg.portal_claimed = Tiéd a portál! Vonzza a lényeket. msg.flag_removed = Támadási zászló eltávolítva. A lényeid visszatérnek. @@ -1090,12 +1094,20 @@ ability.drain.desc = az okozott sebzés harmadával gyógyítja magát. unit.giant = Óriás unit.fairy = Tündérkém unit.battlemage = Harci mágus +unit.thief = Tolvaj +unit.monk = Szerzetes +unit.ranger = Vadőr +unit.inquisitor = Inkvizítor unit.ram = Faltörő kos unit.catapult = Katapult msg.trap_wrecked = A hősök tönkretettek egy csapdát: {0}. best.giant.text = Az óriás az, ami akkor lesz, ha egy lovag háromszáz évig megeszi a zöldséget. Lassú, hatalmas, és az ajtókat csak javaslatnak tekinti. | Pusztán azzal tönkreteszi a csapdákat, hogy melléjük áll. Visszataszító modor. Vágj hozzá mindent, lehetőleg messziről. best.fairy.text = A Rend kis besúgója: egy világító szúnyog szárnyakkal, akit előreküldenek, hogy megtalálja a csapdáidat, és mindenkinek elmondja. Ha egyszer meglátott egy csapdát, a hősök szétverik. | Ráadásul gyógyító port szór a hősökre. Csapd agyon elsőként. Kétszer, a biztonság kedvéért. best.battlemage.text = Mágus a Rend köntösében, aki a falakat személyes sértésnek veszi. A megerősített falak szétrobbannak a tűzgolyói alatt, és sosem hallgat el róla. | Közelről törékeny. Az acélfalak bosszantják a legjobban - helyes. +best.thief.text = Fürge ujjak, még fürgébb lábak. Nem harcolni jön: beoson a kincstáradba, megtölti a zsákját, és visszafut a kapuhoz. | Öld meg, mielőtt elszökik, és az arany újra a tiéd - kamatostul. +best.monk.text = Évnyi böjt és ima süketté tette a mágiádra: a villám, a pestis és a fagy úgy pereg le róla, mint eső a tetőről. | Az ököl is fáj. Fogadd acéllal, karmokkal és fogakkal. +best.ranger.text = A Rend erdőjárója, aki messziről lő, és vascsapdákat hagy a folyosóidon. Az a lény, amelyik belelép, megsebesül, és egy ideig beragad. | A csapdák ott maradnak, amíg valaki bele nem lép. Inkább egy kobold, mint az ogréd. +best.inquisitor.text = Törékeny, de a prédikációi veszélyesek: húszmásodpercenként rábeszéli egyik leggyengébb lényedet - egy koboldot vagy egy pókot -, hogy álljon a hősök oldalára. | Az erős lények csak kinevetik. Üss te először. best.ram.text = Egy vaskupakos fatörzs, nyilak ellen tetővel. A lényeid hidegen hagyják – az ajtóid, falaid és tornyaid nem. | Állítsd meg az ajtó előtt, vagy szerezz új ajtót. best.catapult.text = Egy fakar, egy vödör kő és egy lovag túl sok szabadidővel. Messzebbre lő a tornyaidnál, és először azokat veszi célba. | Rohamozd meg: közelről a légynek sem árt. diff --git a/lang/it.lang b/lang/it.lang index 6aa140c..ec9d426 100644 --- a/lang/it.lang +++ b/lang/it.lang @@ -64,6 +64,10 @@ msg.gate_boss = La porta si sgretola! Appare il Guardiano della Porta con {0} di msg.gate_defenders = La porta evoca {0} difensori! msg.level_up = {0} raggiunge il livello {1}. msg.hero_slain = {0} sconfitto! Bottino: {1} oro. +msg.thief_in_treasury = C'è un ladro nella tua tesoreria! +msg.thief_escaped = Un ladro è scappato con {0} oro! +msg.snare_caught = È finito in una tagliola: {0}! +msg.converted = L'inquisitore ha convertito una delle tue creature: {0}! msg.creature_died = È caduto in battaglia: {0}. msg.portal_claimed = Il portale è tuo! Attira le creature. msg.flag_removed = Bandiera d'attacco rimossa. Le creature tornano indietro. @@ -1082,12 +1086,20 @@ ability.drain.desc = si cura di un terzo del danno che infligge. unit.giant = Gigante unit.fairy = Fata spia unit.battlemage = Mago da battaglia +unit.thief = Ladro +unit.monk = Monaco +unit.ranger = Ranger +unit.inquisitor = Inquisitore unit.ram = Ariete unit.catapult = Catapulta msg.trap_wrecked = Gli eroi hanno distrutto una trappola: {0}. best.giant.text = Un gigante è ciò che succede quando un cavaliere mangia la verdura per trecento anni. Lento, enorme, e considera le porte un semplice suggerimento. | Distrugge le trappole solo stando loro accanto. Maniere rivoltanti. Colpiscilo con tutto, preferibilmente da lontano. best.fairy.text = La piccola spia dell'Ordine: un moscerino luminoso con le ali, mandato avanti a trovare le tue trappole e a dirlo a tutti. Appena ha visto una trappola, gli eroi la distruggono. | Sparge anche polvere curativa sugli eroi. Schiacciala per prima. Due volte, per sicurezza. best.battlemage.text = Un mago con la tonaca dell'Ordine che considera i muri un insulto personale. I muri rinforzati scoppiano sotto le sue palle di fuoco, e lui non smette mai di vantarsene. | Fragile da vicino. I muri d'acciaio lo irritano più di tutto - bene. +best.thief.text = Dita svelte, piedi ancora più svelti. Non viene per combattere: si infila nella tua tesoreria, riempie il sacco e corre di nuovo alla porta. | Uccidilo prima che scappi e l'oro torna tuo - con gli interessi. +best.monk.text = Anni di digiuno e preghiera lo hanno reso sordo alla tua magia: fulmine, peste e gelo gli scivolano addosso come pioggia su un tetto. | Anche i pugni fanno male. Accoglilo con acciaio, artigli e denti. +best.ranger.text = Un uomo dei boschi dell'Ordine che tira da lontano e lascia tagliole di ferro nei tuoi corridoi. La creatura che ci mette il piede resta ferita e bloccata per un po'. | Le tagliole restano finché qualcuno non ci finisce dentro. Meglio un coboldo che il tuo orco. +best.inquisitor.text = Fragile, ma le sue prediche sono pericolose: ogni venti secondi convince una delle tue creature più deboli - un coboldo o un ragno - a passare dalla parte degli eroi. | Le creature forti gli ridono in faccia. Colpisci per primo. best.ram.text = Un tronco con punta di ferro e un tetto contro le frecce. Delle tue creature non gli importa: solo di porte, muri e torri. | Fermalo prima che arrivi alla porta, o procurati una porta nuova. best.catapult.text = Un braccio di legno, un secchio di sassi e un cavaliere con troppo tempo libero. Tira più lontano delle tue torri e le punta per prime. | Caricala: da vicino non fa male a una mosca. diff --git a/lang/nl.lang b/lang/nl.lang index 1050c6f..6aed486 100644 --- a/lang/nl.lang +++ b/lang/nl.lang @@ -64,6 +64,10 @@ msg.gate_boss = De poort brokkelt af! De Poortwachter verschijnt met {0} verdedi msg.gate_defenders = De poort roept {0} verdedigers op! msg.level_up = {0} bereikt niveau {1}. msg.hero_slain = {0} verslagen! Buit: {1} goud. +msg.thief_in_treasury = Er zit een dief in je schatkamer! +msg.thief_escaped = Een dief is ontsnapt met {0} goud! +msg.snare_caught = In een klem getrapt: {0}! +msg.converted = De inquisiteur heeft een van je wezens bekeerd: {0}! msg.creature_died = Je {0} is gesneuveld. msg.portal_claimed = Het portaal is van jou! Het trekt wezens aan. msg.flag_removed = Aanvalsvlag verwijderd. Je wezens keren terug. @@ -1090,12 +1094,20 @@ ability.drain.desc = geneest zichzelf met een derde van de schade die hij toebre unit.giant = Reus unit.fairy = Feeënspion unit.battlemage = Strijdmagiër +unit.thief = Dief +unit.monk = Monnik +unit.ranger = Woudloper +unit.inquisitor = Inquisiteur unit.ram = Stormram unit.catapult = Katapult msg.trap_wrecked = De helden hebben een val vernield: {0}. best.giant.text = Een reus is wat er gebeurt als een ridder driehonderd jaar zijn groente opeet. Traag, enorm, en deuren beschouwt hij als een suggestie. | Hij vernielt vallen gewoon door ernaast te staan. Walgelijke manieren. Raak hem met alles wat je hebt, liefst van ver. best.fairy.text = De kleine verklikker van de Orde: een gloeiende mug met vleugels, vooruitgestuurd om je vallen te vinden en het iedereen te vertellen. Zodra ze een val heeft gezien, slaan de helden hem kapot. | Ze strooit ook geneesstof over de helden. Mep haar als eerste. Twee keer, voor de zekerheid. best.battlemage.text = Een magiër in het gewaad van de Orde die muren als een persoonlijke belediging opvat. Versterkte muren barsten onder zijn vuurballen, en hij blijft er maar over praten. | Breekbaar van dichtbij. Stalen muren ergeren hem het meest - mooi zo. +best.thief.text = Vlugge vingers, nog vluggere voeten. Hij komt niet om te vechten: hij sluipt je schatkamer in, vult zijn zak en rent terug naar de poort. | Dood hem voordat hij ontkomt en het goud is weer van jou - met rente. +best.monk.text = Jaren van vasten en bidden hebben hem doof gemaakt voor je magie: bliksem, pest en vorst glijden van hem af als regen van een dak. | Vuisten doen ook pijn. Ontvang hem met staal, klauwen en tanden. +best.ranger.text = Een woudloper van de Orde die van ver schiet en ijzeren klemmen in je gangen achterlaat. Een wezen dat erin trapt, raakt gewond en zit een tijdje vast. | Klemmen blijven liggen tot iemand erin trapt. Liever een kobold dan je oger. +best.inquisitor.text = Broos, maar zijn preken zijn gevaarlijk: elke twintig seconden praat hij een van je zwakste wezens - een kobold of een spin - over naar de kant van de helden. | Sterke wezens lachen hem gewoon uit. Sla als eerste toe. best.ram.text = Een boomstam met ijzeren kop en een dak tegen pijlen. Je wezens laten hem koud – je deuren, muren en torens niet. | Stop hem voor hij de deur bereikt, of zorg voor een nieuwe deur. best.catapult.text = Een houten arm, een emmer stenen en een ridder met te veel vrije tijd. Hij reikt verder dan je torens en mikt eerst op hen. | Storm erop af: van dichtbij doet hij geen vlieg kwaad. diff --git a/lang/no.lang b/lang/no.lang index 2d6e359..edda26a 100644 --- a/lang/no.lang +++ b/lang/no.lang @@ -64,6 +64,10 @@ msg.gate_boss = Porten smuldrer! Portvokteren dukker opp med {0} forsvarere! msg.gate_defenders = Porten tilkaller {0} forsvarere! msg.level_up = {0} når nivå {1}. msg.hero_slain = {0} beseiret! Bytte: {1} gull. +msg.thief_in_treasury = En tyv er i skattkammeret ditt! +msg.thief_escaped = En tyv slapp unna med {0} gull! +msg.snare_caught = Tråkket i en saks: {0}! +msg.converted = Inkvisitoren har omvendt et av vesenene dine: {0}! msg.creature_died = Din {0} har falt. msg.portal_claimed = Portalen er din! Den tiltrekker skapninger. msg.flag_removed = Angrepsflagget er fjernet. Skapningene dine vender tilbake. @@ -1089,12 +1093,20 @@ ability.drain.desc = leger seg selv med en tredjedel av skaden den gjør. unit.giant = Kjempe unit.fairy = Feespion unit.battlemage = Kampmagiker +unit.thief = Tyv +unit.monk = Munk +unit.ranger = Jeger +unit.inquisitor = Inkvisitor unit.ram = Rambukk unit.catapult = Katapult msg.trap_wrecked = Heltene ødela en felle: {0}. best.giant.text = En kjempe er det som skjer når en ridder spiser grønnsakene sine i tre hundre år. Treg, enorm, og den ser på dører som et forslag. | Den ødelegger feller bare ved å stå ved siden av dem. Ekle manerer. Treff den med alt, helst på avstand. best.fairy.text = Ordenens lille tyster: en glødende knott med vinger, sendt i forveien for å finne fellene dine og fortelle alle om dem. Når den har sett en felle, knuser heltene den. | Den drysser også legende støv på heltene. Smekk den først. To ganger, for sikkerhets skyld. best.battlemage.text = En magiker i Ordenens kappe som ser på vegger som en personlig fornærmelse. Forsterkede vegger brister under ildkulene hans, og han slutter aldri å snakke om det. | Skjør på nært hold. Stålvegger irriterer ham mest - bra. +best.thief.text = Raske fingre, enda raskere føtter. Han kommer ikke for å slåss: han sniker seg inn i skattkammeret ditt, fyller sekken og løper tilbake til porten. | Drep ham før han slipper unna, så er gullet ditt igjen - med renter. +best.monk.text = År med faste og bønn har gjort ham døv for magien din: lyn, pest og frost preller av ham som regn av et tak. | Never gjør også vondt. Møt ham med stål, klør og tenner. +best.ranger.text = En skogsmann fra Ordenen som skyter på avstand og legger ut jernsakser i gangene dine. Et vesen som tråkker i en, blir skadet og sitter fast en stund. | Saksene blir liggende til noen tråkker i dem. Heller en kobold enn trollet ditt. +best.inquisitor.text = Skrøpelig, men prekenene hans er farlige: hvert tjuende sekund snakker han et av de svakeste vesenene dine - en kobold eller en edderkopp - over til heltenes side. | Sterke vesener bare ler av ham. Slå til først. best.ram.text = En trestamme med jernhette og et tak mot piler. Skapningene dine bryr den seg ikke om – dørene, murene og tårnene dine derimot. | Stopp den før den når døra, eller skaff en ny dør. best.catapult.text = En trearm, en bøtte stein og en ridder med for mye fritid. Den rekker lenger enn tårnene dine og sikter på dem først. | Storm fram: på nært hold gjør den ikke en flue fortred. diff --git a/lang/pt.lang b/lang/pt.lang index 7722e06..aae7188 100644 --- a/lang/pt.lang +++ b/lang/pt.lang @@ -64,6 +64,10 @@ msg.gate_boss = O portão está a ruir! Surge o Guardião do Portão com {0} def msg.gate_defenders = O portão invoca {0} defensores! msg.level_up = {0} atinge o nível {1}. msg.hero_slain = {0} derrotado! Saque: {1} de ouro. +msg.thief_in_treasury = Há um ladrão na tua tesouraria! +msg.thief_escaped = Um ladrão fugiu com {0} de ouro! +msg.snare_caught = Caiu numa armadilha: {0}! +msg.converted = O inquisidor converteu uma das tuas criaturas: {0}! msg.creature_died = O teu {0} caiu. msg.portal_claimed = O portal é teu! Atrai criaturas. msg.flag_removed = Bandeira de ataque retirada. As tuas criaturas regressam. @@ -1090,12 +1094,20 @@ ability.drain.desc = cura-se num terço do dano que causa. unit.giant = Gigante unit.fairy = Fada Espiã unit.battlemage = Mago de Batalha +unit.thief = Ladrão +unit.monk = Monge +unit.ranger = Batedor +unit.inquisitor = Inquisidor unit.ram = Aríete unit.catapult = Catapulta msg.trap_wrecked = Os heróis destruíram uma armadilha: {0}. best.giant.text = Um gigante é o que acontece quando um cavaleiro come os legumes durante trezentos anos. Lento, enorme, e trata as portas como uma sugestão. | Destrói armadilhas só por estar ao lado delas. Maneiras repugnantes. Atira-lhe com tudo, de preferência de longe. best.fairy.text = A pequena informadora da Ordem: um mosquito luminoso com asas, mandado à frente para encontrar as tuas armadilhas e contar a toda a gente. Depois de ver uma armadilha, os heróis destroem-na. | Também polvilha pó curativo sobre os heróis. Esmaga-a primeiro. Duas vezes, para ter a certeza. best.battlemage.text = Um mago com as vestes da Ordem que acha as paredes um insulto pessoal. As paredes reforçadas rebentam com as bolas de fogo dele, e ele nunca se cala sobre isso. | Frágil de perto. As paredes de aço irritam-no mais do que tudo - ótimo. +best.thief.text = Dedos ligeiros, pés ainda mais ligeiros. Não vem para lutar: esgueira-se para a tua tesouraria, enche o saco e corre de volta para o portão. | Mata-o antes que fuja e o ouro volta a ser teu - com juros. +best.monk.text = Anos de jejum e oração tornaram-no surdo à tua magia: relâmpago, praga e gelo escorrem-lhe como chuva num telhado. | Os punhos também doem. Recebe-o com aço, garras e dentes. +best.ranger.text = Um homem dos bosques da Ordem que dispara de longe e deixa armadilhas de ferro nos teus corredores. A criatura que pisa uma fica ferida e presa durante um bocado. | As armadilhas ficam até alguém as pisar. Antes um kobold do que o teu ogre. +best.inquisitor.text = Frágil, mas os seus sermões são perigosos: a cada vinte segundos convence uma das tuas criaturas mais fracas - um kobold ou uma aranha - a juntar-se aos heróis. | As criaturas fortes riem-se dele. Ataca primeiro. best.ram.text = Um tronco com ponta de ferro e um telhado contra as flechas. As tuas criaturas não lhe interessam – só as tuas portas, muros e torres. | Trava-o antes de chegar à porta, ou arranja outra porta. best.catapult.text = Um braço de madeira, um balde de pedras e um cavaleiro com tempo a mais. Alcança mais longe que as tuas torres e aponta-lhes primeiro. | Carrega sobre ela: de perto não faz mal a uma mosca. diff --git a/lang/ro.lang b/lang/ro.lang index 868724b..d3931d2 100644 --- a/lang/ro.lang +++ b/lang/ro.lang @@ -64,6 +64,10 @@ msg.gate_boss = Poarta se năruie! Paznicul Porții apare cu {0} apărători! msg.gate_defenders = Poarta cheamă {0} apărători! msg.level_up = {0} ajunge la nivelul {1}. msg.hero_slain = {0} învins! Pradă: {1} aur. +msg.thief_in_treasury = Un hoț e în vistieria ta! +msg.thief_escaped = Un hoț a scăpat cu {0} aur! +msg.snare_caught = A călcat într-o capcană: {0}! +msg.converted = Inchizitorul ți-a convertit una dintre creaturi: {0}! msg.creature_died = {0} al tău a căzut. msg.portal_claimed = Portalul e al tău! Atrage creaturi. msg.flag_removed = Steagul de atac a fost scos. Creaturile tale se întorc. @@ -1090,12 +1094,20 @@ ability.drain.desc = se vindecă cu o treime din daunele pe care le provoacă. unit.giant = Uriaș unit.fairy = Zână Iscoadă unit.battlemage = Mag de Luptă +unit.thief = Hoț +unit.monk = Călugăr +unit.ranger = Pândar +unit.inquisitor = Inchizitor unit.ram = Berbec unit.catapult = Catapultă msg.trap_wrecked = Eroii au distrus o capcană: {0}. best.giant.text = Un uriaș e ce se întâmplă când un cavaler își mănâncă legumele trei sute de ani. Lent, enorm, iar ușile le tratează drept sugestii. | Distruge capcanele doar stând lângă ele. Maniere respingătoare. Lovește-l cu tot ce ai, de preferință de departe. best.fairy.text = Micul informator al Ordinului: un țânțar strălucitor cu aripi, trimis înainte să-ți găsească capcanele și să le spună tuturor. Odată ce a văzut o capcană, eroii o sparg. | Mai presară și praf vindecător peste eroi. Plesnește-o prima. De două ori, ca să fii sigur. best.battlemage.text = Un mag în veșmintele Ordinului care consideră zidurile o insultă personală. Zidurile întărite crapă sub mingile lui de foc și nu se mai oprește din vorbit despre asta. | Fragil de aproape. Zidurile de oțel îl enervează cel mai tare - bine. +best.thief.text = Degete iuți, picioare și mai iuți. Nu vine să lupte: se strecoară în vistieria ta, își umple sacul și fuge înapoi la poartă. | Omoară-l înainte să scape și aurul e din nou al tău - cu dobândă. +best.monk.text = Ani de post și rugăciune l-au făcut surd la magia ta: fulgerul, ciuma și gerul alunecă de pe el ca ploaia de pe acoperiș. | Și pumnii dor. Întâmpină-l cu oțel, gheare și dinți. +best.ranger.text = Un om al pădurii din Ordin care trage de departe și lasă capcane de fier pe coridoarele tale. Creatura care calcă într-una e rănită și rămâne prinsă o vreme. | Capcanele rămân până calcă cineva în ele. Mai bine un kobold decât căpcăunul tău. +best.inquisitor.text = Firav, dar predicile lui sunt periculoase: la fiecare douăzeci de secunde convinge una dintre cele mai slabe creaturi ale tale - un kobold sau un păianjen - să treacă de partea eroilor. | Creaturile puternice doar râd de el. Lovește primul. best.ram.text = Un trunchi cu vârf de fier și un acoperiș contra săgeților. Creaturile tale nu-l interesează – ușile, zidurile și turnurile da. | Oprește-l înainte de ușă sau fă-ți rost de alta. best.catapult.text = Un braț de lemn, o găleată de pietre și un cavaler cu prea mult timp liber. Bate mai departe decât turnurile tale și le țintește primele. | Năvălește peste ea: de aproape nu face rău nici unei muște. diff --git a/lang/ru.lang b/lang/ru.lang index bb6b881..4f684ec 100644 --- a/lang/ru.lang +++ b/lang/ru.lang @@ -64,6 +64,10 @@ msg.gate_boss = Врата рушатся! Появляется Страж вр msg.gate_defenders = Врата призывают {0} защитников! msg.level_up = {0}: достигнут уровень {1}. msg.hero_slain = Повержен: {0}! Добыча: {1} золота. +msg.thief_in_treasury = Вор в твоей сокровищнице! +msg.thief_escaped = Вор сбежал с {0} золота! +msg.snare_caught = Попал в капкан: {0}! +msg.converted = Инквизитор обратил одно из твоих существ: {0}! msg.creature_died = Пал твой боец: {0}. msg.portal_claimed = Портал твой! Он привлекает существ. msg.flag_removed = Флаг атаки убран. Существа возвращаются. @@ -1082,12 +1086,20 @@ ability.drain.desc = лечит себя на треть нанесённого unit.giant = Великан unit.fairy = Фея-шпион unit.battlemage = Боевой маг +unit.thief = Вор +unit.monk = Монах +unit.ranger = Следопыт +unit.inquisitor = Инквизитор unit.ram = Таран unit.catapult = Катапульта msg.trap_wrecked = Герои сломали ловушку: {0}. best.giant.text = Великан - это то, что выходит, когда рыцарь триста лет ест овощи. Медленный, огромный, а двери для него - лишь пожелание. | Ломает ловушки, просто стоя рядом. Отвратительные манеры. Бей всем, что есть, лучше издалека. best.fairy.text = Маленькая доносчица Ордена: светящаяся мошка с крылышками, которую шлют вперёд найти твои ловушки и всем разболтать. Стоит ей увидеть ловушку, как герои её ломают. | Ещё и посыпает героев целебной пыльцой. Прихлопни её первой. Дважды, для верности. best.battlemage.text = Маг в мантии Ордена, для которого стены - личное оскорбление. Укреплённые стены лопаются от его огненных шаров, и он без конца об этом болтает. | Вблизи хрупок. Больше всего его бесят стальные стены - и хорошо. +best.thief.text = Быстрые пальцы, ещё более быстрые ноги. Он пришёл не драться: прокрадывается в твою сокровищницу, набивает мешок и бежит обратно к вратам. | Убей его, пока он не ушёл, и золото снова твоё - с процентами. +best.monk.text = Годы постов и молитв сделали его глухим к твоей магии: молния, мор и мороз стекают с него, как дождь с крыши. | Кулаки тоже бьют больно. Встречай его сталью, когтями и зубами. +best.ranger.text = Лесничий Ордена, который стреляет издалека и расставляет железные капканы в твоих коридорах. Существо, наступившее в капкан, ранено и надолго застревает. | Капканы лежат, пока в них кто-нибудь не наступит. Лучше кобольд, чем твой огр. +best.inquisitor.text = Дряхлый, но его проповеди опасны: каждые двадцать секунд он уговаривает одно из твоих самых слабых существ - кобольда или паука - перейти к героям. | Сильные существа над ним только смеются. Бей первым. best.ram.text = Бревно с железным наконечником и крышей от стрел. Ваши существа ему безразличны — только двери, стены и башни. | Остановите его до двери или заведите новую дверь. best.catapult.text = Деревянный рычаг, ведро камней и рыцарь с избытком свободного времени. Бьёт дальше ваших башен и целится в них первыми. | Атакуйте вплотную: вблизи она и мухи не обидит. diff --git a/lang/sk.lang b/lang/sk.lang index 6f4414d..045f50d 100644 --- a/lang/sk.lang +++ b/lang/sk.lang @@ -64,6 +64,10 @@ msg.gate_boss = Brána sa rúca! Objavuje sa strážca brány s obrancami ({0})! msg.gate_defenders = Brána povoláva obrancov ({0})! msg.level_up = {0} dosahuje úroveň {1}. msg.hero_slain = Porazený: {0}! Korisť: {1} zlata. +msg.thief_in_treasury = V tvojej pokladnici je zlodej! +msg.thief_escaped = Zlodej ušiel s {0} zlata! +msg.snare_caught = Do pasce stúpil: {0}! +msg.converted = Inkvizítor obrátil jedného z tvojich tvorov: {0}! msg.creature_died = Padol tvoj tvor: {0}. msg.portal_claimed = Portál je tvoj! Priťahuje tvory. msg.flag_removed = Útočná vlajka odstránená. Tvoje tvory sa vracajú. @@ -1090,12 +1094,20 @@ ability.drain.desc = lieči sa o tretinu poškodenia, ktoré spôsobí. unit.giant = Obor unit.fairy = Víla špiónka unit.battlemage = Bojový mág +unit.thief = Zlodej +unit.monk = Mních +unit.ranger = Hraničiar +unit.inquisitor = Inkvizítor unit.ram = Baranidlo unit.catapult = Katapult msg.trap_wrecked = Hrdinovia zničili pascu: {0}. best.giant.text = Obor je to, čo sa stane, keď rytier tristo rokov je zeleninu. Pomalý, obrovský a dvere berie len ako návrh. | Pasce ničí už tým, že stojí vedľa nich. Odporné spôsoby. Bi ho všetkým, čo máš, najlepšie z diaľky. best.fairy.text = Malý udavač Rádu: žiariaci komár s krídlami, poslaný napred, aby našiel tvoje pasce a všetkým to vytáral. Len čo pascu uvidí, hrdinovia ju rozbijú. | Navyše sype na hrdinov liečivý prach. Plesni ju prvú. Dvakrát, pre istotu. best.battlemage.text = Mág v rúchu Rádu, ktorý považuje múry za osobnú urážku. Spevnené steny pod jeho ohnivými guľami praskajú a on o tom neprestane rozprávať. | Zblízka krehký. Najviac ho štvú oceľové steny - dobre. +best.thief.text = Rýchle prsty, ešte rýchlejšie nohy. Neprichádza bojovať: vkradne sa do tvojej pokladnice, naplní si vrece a uteká späť k bráne. | Zabi ho skôr, než ujde, a zlato je zase tvoje - aj s úrokmi. +best.monk.text = Roky pôstu a modlitieb ho urobili hluchým k tvojej mágii: blesk, mor aj mráz z neho stekajú ako dážď zo strechy. | Aj päste bolia. Priviť ho oceľou, pazúrmi a zubami. +best.ranger.text = Lesník Rádu, ktorý strieľa z diaľky a nastražuje v tvojich chodbách železné pasce. Tvor, ktorý do jednej stúpi, je zranený a chvíľu uviazne. | Pasce zostávajú, kým do nich niekto nestúpi. Radšej kobold než tvoj zlobor. +best.inquisitor.text = Krehký, ale jeho kázne sú nebezpečné: každých dvadsať sekúnd prehovorí jedného z tvojich najslabších tvorov - kobolda alebo pavúka -, aby prešiel k hrdinom. | Silní tvorovia sa mu len vysmejú. Udri prvý. best.ram.text = Kmeň so železnou hlavicou a strieškou proti šípom. Tvoje bytosti ho nezaujímajú – tvoje dvere, múry a veže áno. | Zastav ho pred dverami, alebo si zaobstaraj nové. best.catapult.text = Drevené rameno, vedro kameňov a rytier s priveľa voľným časom. Strieľa ďalej ako tvoje veže a mieri najprv na ne. | Vrhni sa naň: zblízka neublíži ani muche. diff --git a/lang/sr.lang b/lang/sr.lang index cdc7c32..6633133 100644 --- a/lang/sr.lang +++ b/lang/sr.lang @@ -64,6 +64,10 @@ msg.gate_boss = Капија се руши! Појављује се Чувар msg.gate_defenders = Капија призива браниоце: {0}! msg.level_up = {0} достиже ниво {1}. msg.hero_slain = Поражен: {0}! Плен: {1} злата. +msg.thief_in_treasury = Лопов је у твојој ризници! +msg.thief_escaped = Лопов је побегао са {0} злата! +msg.snare_caught = Стало је у замку: {0}! +msg.converted = Инквизитор је преобратио једно твоје створење: {0}! msg.creature_died = Пало је твоје створење: {0}. msg.portal_claimed = Портал је твој! Привлачи створења. msg.flag_removed = Застава напада уклоњена. Створења се враћају. @@ -1090,12 +1094,20 @@ ability.drain.desc = лечи се за трећину штете коју на unit.giant = Џин unit.fairy = Вила ухода unit.battlemage = Борбени маг +unit.thief = Лопов +unit.monk = Монах +unit.ranger = Ловац +unit.inquisitor = Инквизитор unit.ram = Ован unit.catapult = Катапулт msg.trap_wrecked = Хероји су уништили замку: {0}. best.giant.text = Џин је оно што се деси кад витез триста година једе поврће. Спор, огроман, а врата сматра предлогом. | Замке уништава самим тим што стоји поред њих. Одвратно понашање. Удари га свиме, најбоље издалека. best.fairy.text = Мали доушник Реда: светлећа мушица с крилима, послата напред да пронађе твоје замке и свима их ода. Кад једном види замку, хероји је разбију. | Уз то посипа хероје лековитим прахом. Згњечи њу прву. Двапут, за сваки случај. best.battlemage.text = Маг у одежди Реда који зидове сматра личном увредом. Ојачани зидови пуцају под његовим ватреним куглама, а он о томе непрестано прича. | Крхак изблиза. Челични зидови га највише нервирају - добро. +best.thief.text = Брзи прсти, још брже ноге. Не долази да се бори: ушуња се у твоју ризницу, напуни врећу и отрчи назад до капије. | Убиј га пре него што побегне и злато је опет твоје - с каматом. +best.monk.text = Године поста и молитве учиниле су га глувим за твоју магију: муња, куга и мраз клизе с њега као киша с крова. | И песнице боле. Дочекај га челиком, канџама и зубима. +best.ranger.text = Шумар Реда који гађа издалека и оставља гвоздене замке у твојим ходницима. Створење које стане у једну рањено је и неко време заглављено. | Замке остају док неко не стане у њих. Боље коболд него твој огр. +best.inquisitor.text = Крхак, али су му проповеди опасне: на сваких двадесет секунди наговори једно од твојих најслабијих створења - коболда или паука - да пређе херојима. | Јака створења му се само смеју. Удари први. best.ram.text = Дебло са гвозденом капом и кровом против стрела. Твоја створења га не занимају – твоја врата, зидови и куле да. | Заустави га пре врата или набави нова врата. best.catapult.text = Дрвена рука, канта камења и витез са превише слободног времена. Гађа даље од твојих кула и циља их прве. | Јуриш на њега: изблиза ни мушици не нашкоди. diff --git a/lang/sv.lang b/lang/sv.lang index 51f08cf..80aba6c 100644 --- a/lang/sv.lang +++ b/lang/sv.lang @@ -64,6 +64,10 @@ msg.gate_boss = Porten vacklar! Portväktaren dyker upp med {0} försvarare! msg.gate_defenders = Porten kallar på {0} försvarare! msg.level_up = {0} når nivå {1}. msg.hero_slain = {0} besegrad! Byte: {1} guld. +msg.thief_in_treasury = En tjuv är i din skattkammare! +msg.thief_escaped = En tjuv kom undan med {0} guld! +msg.snare_caught = Klev i en fälla: {0}! +msg.converted = Inkvisitorn har omvänt en av dina varelser: {0}! msg.creature_died = Din {0} har stupat. msg.portal_claimed = Portalen är din! Den lockar till sig varelser. msg.flag_removed = Anfallsflaggan borttagen. Dina varelser återvänder. @@ -1090,12 +1094,20 @@ ability.drain.desc = läker sig själv med en tredjedel av skadan den gör. unit.giant = Jätte unit.fairy = Älvspion unit.battlemage = Stridsmagiker +unit.thief = Tjuv +unit.monk = Munk +unit.ranger = Jägare +unit.inquisitor = Inkvisitor unit.ram = Murbräcka unit.catapult = Katapult msg.trap_wrecked = Hjältarna förstörde en fälla: {0}. best.giant.text = En jätte är vad som händer när en riddare äter sina grönsaker i trehundra år. Långsam, enorm, och den ser dörrar som ett förslag. | Den förstör fällor bara genom att stå bredvid dem. Motbjudande manér. Slå den med allt, helst på avstånd. best.fairy.text = Ordens lilla angivare: en glödande mygga med vingar, utskickad i förväg för att hitta dina fällor och skvallra för alla. När den väl har sett en fälla slår hjältarna sönder den. | Den strör också läkande stoft över hjältarna. Smäll till den först. Två gånger, för säkerhets skull. best.battlemage.text = En magiker i ordens kåpa som ser väggar som en personlig förolämpning. Förstärkta väggar spricker under hans eldklot, och han slutar aldrig prata om det. | Ömtålig på nära håll. Stålväggar retar honom mest - bra. +best.thief.text = Snabba fingrar, ännu snabbare fötter. Han kommer inte för att slåss: han smyger in i din skattkammare, fyller sin säck och springer tillbaka till porten. | Döda honom innan han kommer undan så är guldet ditt igen - med ränta. +best.monk.text = År av fasta och bön har gjort honom döv för din magi: blixt, pest och frost rinner av honom som regn från ett tak. | Nävar gör också ont. Möt honom med stål, klor och tänder. +best.ranger.text = En skogsman från orden som skjuter på avstånd och lägger ut järnfällor i dina gångar. En varelse som kliver i en blir skadad och fastnar en stund. | Fällorna ligger kvar tills någon kliver i dem. Hellre en kobold än din jätte. +best.inquisitor.text = Skröplig, men hans predikningar är farliga: var tjugonde sekund övertalar han en av dina svagaste varelser - en kobold eller en spindel - att gå över till hjältarna. | Starka varelser bara skrattar åt honom. Slå till först. best.ram.text = En trädstam med järnhätta och ett tak mot pilar. Dina varelser struntar den i – dina dörrar, murar och torn inte. | Stoppa den innan den når dörren, eller skaffa en ny dörr. best.catapult.text = En träarm, en hink stenar och en riddare med för mycket fritid. Den når längre än dina torn och siktar på dem först. | Storma fram: på nära håll gör den inte en fluga förnär. diff --git a/src/blocks.rs b/src/blocks.rs index c07c40f..f0e1a75 100644 --- a/src/blocks.rs +++ b/src/blocks.rs @@ -10,9 +10,9 @@ use serde::{Deserialize, Serialize}; pub const SIDES: [i32; 6] = [-1, 0, 1, 2, 3, 4]; // creature and hero kinds a block may name ("" = any) -pub const KINDS: [&str; 26] = [ +pub const KINDS: [&str; 30] = [ "Worker", "Kobold", "Spider", "Mage", "Ogre", "Jailer", "Priestess", "Chainbreaker", "Bat", "Gargoyle", "Owl", "Wyrm", "Cogling", "Revenant", "Knight", "Archer", "Priest", "Dwarf", "Paladin", "Giant", "Fairy", - "BattleMage", "Ram", "Catapult", "CaveBear", "Beetle", + "BattleMage", "Ram", "Catapult", "CaveBear", "Beetle", "Thief", "Monk", "Ranger", "Inquisitor", ]; // ground a Terrain block can make diff --git a/src/game.rs b/src/game.rs index 390376e..b395543 100644 --- a/src/game.rs +++ b/src/game.rs @@ -132,6 +132,11 @@ pub enum EK { CaveBear, // strong and shaggy, likes the mushroom garden Beetle, // a giant armoured beetle, likes the lair Trader, // a merchant visiting through the portal (traders.rs) + // heroes of the later waves (rogues.rs) + Thief, // fast, sneaks to a treasury, steals gold and runs off with it + Monk, // fists and faith: spells do not touch him + Ranger, // a bow from afar, lays snares in the dungeon's corridors + Inquisitor, // fragile; now and then turns one of the weakest creatures to the heroes' side } pub struct St { @@ -179,6 +184,10 @@ pub fn st(k: EK) -> St { EK::CaveBear => s("unit.cavebear", 420.0, 24.0, 1.0, 1.9, 1.4, 110, 0), EK::Beetle => s("unit.beetle", 300.0, 13.0, 1.0, 1.7, 1.1, 70, 0), EK::Trader => s("unit.trader", 200.0, 1.0, 1.0, 1.5, 2.0, 0, 0), + EK::Thief => s("unit.thief", 60.0, 6.0, 1.0, 3.1, 0.9, 50, 120), + EK::Monk => s("unit.monk", 150.0, 12.0, 1.0, 2.3, 0.7, 80, 180), + EK::Ranger => s("unit.ranger", 90.0, 11.0, 5.0, 2.2, 1.4, 80, 160), + EK::Inquisitor => s("unit.inquisitor", 70.0, 7.0, 3.5, 1.8, 1.6, 90, 250), } } @@ -629,6 +638,8 @@ pub struct Game { #[serde(default)] pub happenings: Option, // random events (free games and versus), see events.rs #[serde(default)] + pub snares: Vec, // tiles with a ranger's snare (rogues.rs) + #[serde(default)] pub guard_marks: Vec, // guard markers (shields) of the master being processed (orders.rs) #[serde(default)] pub attack_marks: Vec, // attack markers (swords) @@ -978,6 +989,7 @@ impl Game { bridgework: Default::default(), trading: Default::default(), happenings: None, + snares: Vec::new(), guard_marks: Vec::new(), attack_marks: Vec::new(), marks_t: 0.0, @@ -1778,6 +1790,7 @@ impl Game { self.update_contested(); self.update_units(dt); self.switch_to(first); // update_units worked master by master + self.update_snares(); self.update_towers(dt); self.update_reveals(dt); self.update_graves(dt); @@ -2263,6 +2276,12 @@ impl Game { if w >= 6 { pool.push((Giant, 1)); } + // the rogues of the later waves (in the campaign only from the later missions on) + for (k, from_wave, from_mission) in crate::rogues::ROGUES { + if w >= from_wave && self.mission.as_ref().map_or(true, |m| m.index >= from_mission) { + pool.push((k, 1)); + } + } // siege engines for the dungeon's doors, walls and towers if w >= 4 && self.traps.iter().any(|t| t.kind.door()) { pool.push((Ram, 1)); @@ -2754,6 +2773,7 @@ impl Game { EK::Priestess => 0xff3080ff, EK::Owl => 0xffffa060, EK::Wyrm => 0xff2080ff, + EK::Inquisitor => 0xff40d0ff, _ => 0xff70b0d0, }; // flyers shoot from the air @@ -2762,7 +2782,8 @@ impl Game { self.grow_last_fx(lv); use crate::particles::*; self.style_last_fx(match e.kind { - EK::Archer => ST_ARROW, + EK::Archer | EK::Ranger => ST_ARROW, + EK::Inquisitor => ST_HOLY, EK::Mage => ST_SHADOW, EK::Priest => ST_HOLY, EK::Priestess | EK::Wyrm | EK::BattleMage => ST_FIRE, @@ -2924,7 +2945,7 @@ impl Game { self.switch_to(me); } if hero { - let b = s.bounty as f32; + let b = s.bounty as f32 + if kind == EK::Thief { self.thief_loot(id) } else { 0.0 }; let got = self.add_gold(b); self.fx(5, x, y, 0.0, 0.0, 1.0, 0xff30d0ff); self.sfx(Sfx::HeroDeath, x, y); @@ -4631,6 +4652,10 @@ impl Game { if e.boss > 0 { self.boss_ability(e, dt); } + // the rogues' tricks: a thief who is busy stealing or running does nothing else + if self.rogue_ai(e, dt) { + return; + } if e.kind == EK::Fairy { // fairy dust: the heroes around are healed a little all the time for o in self.ents.iter_mut() { @@ -5681,7 +5706,7 @@ impl Game { self.ignite_at(wx, wy); let mut kills = Vec::new(); for (j, e) in self.ents.iter_mut().enumerate() { - if e.alive && !e.held && e.active_hero() && (e.x - wx).powi(2) + (e.y - wy).powi(2) < 2.6 { + if e.alive && !e.held && e.active_hero() && !crate::rogues::spell_proof(e) && (e.x - wx).powi(2) + (e.y - wy).powi(2) < 2.6 { e.hp -= 55.0; e.flash = 0.2; if e.hp <= 0.0 { diff --git a/src/gfx.rs b/src/gfx.rs index 1cc5b0a..460dfe6 100644 --- a/src/gfx.rs +++ b/src/gfx.rs @@ -1455,6 +1455,58 @@ fn sprite_rows(k: EK) -> [&'static str; 10] { "..kBkkBk..", "..kk..kk..", ], + // thief: a dark hood and mask, a dagger, a sack of gold on the back + EK::Thief => [ + "...kkkk...", + "..kddddk..", + "..kdfkfk.Y", + "..kddddkYy", + ".kdddddkYy", + "skdddddk..", + ".kdkdddk..", + "..kddddk..", + "..kdkkdk..", + "..kk..kk..", + ], + // monk: shaven head, an orange robe tied with a rope, bare fists + EK::Monk => [ + "...kkkk...", + "..kffffk..", + "..kfkfkk..", + "..kffffk..", + ".kooooook.", + "kfoooooofk", + ".kooyyook.", + ".kOooooOk.", + ".kOooooOk.", + "..kkkkkk..", + ], + // ranger: a green hood and cloak, a long bow, leather boots + EK::Ranger => [ + "...kkkk.b.", + "..kgGGgkkb", + "..kGfkfk.b", + "..kGfffk.b", + ".kGgggggkb", + ".kGgbbggkb", + ".kGggggk.b", + "..kBBBBk.b", + "..kBkkBkb.", + "..kk..kk..", + ], + // inquisitor: a tall red hat, white and red robes, a glowing holy book + EK::Inquisitor => [ + "...kRRk...", + "..kRrrRk..", + "..kRrrRk..", + "..kffffk..", + "..kfkfkk..", + ".kwwrrwwk.", + "kwkwrrwkek", + ".kwwrrwwkk", + ".kRwwwwRk.", + "..kkkkkk..", + ], EK::Priest => [ "....yy....", "...kkkk...", @@ -1739,7 +1791,7 @@ fn pal(ch: char) -> Option { }) } -pub const SPRITE_KINDS: [EK; 27] = [ +pub const SPRITE_KINDS: [EK; 31] = [ EK::Worker, EK::Kobold, EK::Spider, @@ -1767,6 +1819,10 @@ pub const SPRITE_KINDS: [EK; 27] = [ EK::CaveBear, EK::Beetle, EK::Trader, + EK::Thief, + EK::Monk, + EK::Ranger, + EK::Inquisitor, ]; // width of the sprite texture in pixels pub const SPRITE_TEX_W: f32 = (SPRITE_KINDS.len() * 12) as f32; @@ -1784,7 +1840,7 @@ pub fn gear_tier(level: u32) -> u32 { } fn is_hero_kind(k: EK) -> bool { - matches!(k, EK::Knight | EK::Archer | EK::Priest | EK::Dwarf | EK::Paladin | EK::Giant | EK::Fairy | EK::BattleMage) + matches!(k, EK::Knight | EK::Archer | EK::Priest | EK::Dwarf | EK::Paladin | EK::Giant | EK::Fairy | EK::BattleMage | EK::Thief | EK::Monk | EK::Ranger | EK::Inquisitor) } // Views of a sprite for eight directions (the others are mirrored): 0 front, 1 front diff --git a/src/main.rs b/src/main.rs index 0205acf..33b7e65 100644 --- a/src/main.rs +++ b/src/main.rs @@ -29,6 +29,7 @@ mod particles; mod props; mod research; mod rival; +mod rogues; mod render3d; mod rooms; mod save; diff --git a/src/menu/bestiary.rs b/src/menu/bestiary.rs index 022f3a8..b2a9e27 100644 --- a/src/menu/bestiary.rs +++ b/src/menu/bestiary.rs @@ -8,7 +8,7 @@ use crate::ui::{tool_cost_static, BLUE as BLUE_C, GREEN as GREEN_C, RED as RED_C pub const TABS: [&str; 4] = ["best.tab.creatures", "best.tab.humans", "best.tab.dungeon", "best.tab.ranks"]; const CREATURES: [EK; 16] = [EK::Worker, EK::Kobold, EK::Spider, EK::Mage, EK::Ogre, EK::Jailer, EK::Priestess, EK::Chainbreaker, EK::Cogling, EK::Revenant, EK::Bat, EK::Gargoyle, EK::Owl, EK::Wyrm, EK::CaveBear, EK::Beetle]; -const HUMANS: [EK; 10] = [EK::Knight, EK::Archer, EK::Priest, EK::Dwarf, EK::Fairy, EK::BattleMage, EK::Giant, EK::Paladin, EK::Ram, EK::Catapult]; +const HUMANS: [EK; 14] = [EK::Knight, EK::Archer, EK::Priest, EK::Dwarf, EK::Fairy, EK::Thief, EK::BattleMage, EK::Monk, EK::Giant, EK::Ranger, EK::Inquisitor, EK::Paladin, EK::Ram, EK::Catapult]; // buildings: indices into ui::TOOLS const BUILDINGS: [usize; 32] = [2, 3, 4, 5, 6, 12, 40, 13, 18, 21, 41, 42, 43, 44, 17, 47, 49, 19, 14, 15, 16, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]; diff --git a/src/mscript.rs b/src/mscript.rs index 470f08e..a5e0d3b 100644 --- a/src/mscript.rs +++ b/src/mscript.rs @@ -142,7 +142,15 @@ pub fn kind_by_name(name: &str) -> Option { 18 => EK::Paladin, 19 => EK::Giant, 20 => EK::Fairy, - _ => EK::BattleMage, + 21 => EK::BattleMage, + 22 => EK::Ram, + 23 => EK::Catapult, + 24 => EK::CaveBear, + 25 => EK::Beetle, + 26 => EK::Thief, + 27 => EK::Monk, + 28 => EK::Ranger, + _ => EK::Inquisitor, }) } diff --git a/src/render3d.rs b/src/render3d.rs index ceaddef..43b2624 100644 --- a/src/render3d.rs +++ b/src/render3d.rs @@ -2372,6 +2372,24 @@ fn draw_landmarks_solid(g: &Game, t: f32) { // soul core: an obsidian throne whose four curved spikes hold the crystal heart in chains let (cx, cy) = g.map.core; draw_throne(vec3(cx as f32 + 1.5, 0.0, cy as f32 + 1.5), t); + // a ranger's snares: iron jaws on the floor, open and waiting + for &i in &g.snares { + if !g.map.shown(i) { + continue; + } + let (x, y) = xy(i); + let c = vec3(x as f32 + 0.5, 0.0, y as f32 + 0.5); + let iron = Color::from_rgba(96, 92, 100, 255); + let dark = Color::from_rgba(40, 36, 42, 255); + draw_cube(c + vec3(0.0, 0.02, 0.0), vec3(0.34, 0.03, 0.34), None, dark); + for side in [-1.0f32, 1.0] { + draw_cube(c + vec3(side * 0.16, 0.06, 0.0), vec3(0.04, 0.08, 0.36), None, iron); + for k in 0..3 { + let z = -0.12 + k as f32 * 0.12; + draw_cube(c + vec3(side * 0.12, 0.11, z), vec3(0.03, 0.05, 0.03), None, Color::from_rgba(200, 200, 210, 255)); + } + } + } // the other masters' cores: the same throne (their hearts glow in their colours) for rv in g.rivals.iter().filter(|r| r.alive && g.map.shown(idx(r.core.0 + 1, r.core.1 + 1))) { let (rx, rz) = rv.centre(); diff --git a/src/rogues.rs b/src/rogues.rs new file mode 100644 index 0000000..6f11d4d --- /dev/null +++ b/src/rogues.rs @@ -0,0 +1,365 @@ +// The rogues of the later waves: the thief sneaks into a treasury and runs off with gold, the +// monk shrugs off spells, the ranger lays snares in the dungeon's corridors and the inquisitor +// now and then turns one of the weakest creatures (kobolds, spiders) to the heroes' side. + +use crate::game::*; +use crate::map::*; + +// (kind, first wave, first campaign mission (index)) - the wave pool takes them from then on +pub const ROGUES: [(EK, u32, usize); 4] = [(EK::Thief, 3, 4), (EK::Monk, 5, 8), (EK::Ranger, 7, 11), (EK::Inquisitor, 9, 15)]; + +// gold a thief can carry, and how fast he scoops it +pub const THIEF_BAG: i32 = 250; +const THIEF_GRAB: i32 = 25; +// a ranger's snares: one every SNARE_EVERY seconds, at most MAX_SNARES on the map +const SNARE_EVERY: f32 = 18.0; +const MAX_SNARES: usize = 30; +pub const SNARE_DAMAGE: f32 = 25.0; +pub const SNARE_STUN: f32 = 3.0; +// the inquisitor turns a weak creature every CONVERT_EVERY seconds, within CONVERT_RANGE tiles +pub const CONVERT_EVERY: f32 = 20.0; +const CONVERT_RANGE: f32 = 5.0; + +// spells do not touch a monk of the order +pub fn spell_proof(e: &Ent) -> bool { + e.hero && e.kind == EK::Monk +} + +// the creatures an inquisitor can turn: only the weakest +pub fn convertible(k: EK) -> bool { + matches!(k, EK::Kobold | EK::Spider) +} + +fn master_ground(t: &Tile) -> bool { + Owner::MASTER_SIDES.contains(&t.owner.side()) +} + +impl Game { + // true: the rogue did all he wanted this step (the usual hero AI is skipped) + pub(crate) fn rogue_ai(&mut self, e: &mut Ent, dt: f32) -> bool { + if !e.active_hero() { + return false; + } + match e.kind { + EK::Thief => self.thief_ai(e, dt), + EK::Ranger => { + self.lay_snare(e); + false + } + EK::Inquisitor => { + self.convert_creature(e); + false + } + _ => false, + } + } + + // ------------------------------------------------------------ thief + + fn thief_ai(&mut self, e: &mut Ent, dt: f32) -> bool { + let cur = e.tile(); + let full = e.carry >= THIEF_BAG; + // a full bag (or nothing left to steal): back to the gate and away + if full || (e.carry > 0 && !self.gold_to_steal(cur)) { + if !self.has_gate() { + return false; + } + let (gx, gy) = self.gate_center(); + if (e.x - gx).powi(2) + (e.y - gy).powi(2) < 2.0 * 2.0 { + e.alive = false; + self.fx(3, e.x, e.y, 0.0, 0.0, 0.7, 0xff505070); + self.tell_local("msg.thief_escaped", vec![e.carry.to_string()], Some(Sfx::Error)); + return true; + } + if e.path.is_empty() && e.repath <= 0.0 { + e.repath = 1.5; + if let Some(p) = self.map.path_to(cur, idx(gx as i32, gy as i32)) { + e.path = p; + } + } + self.step_path(e, dt); + return true; + } + // in a treasury with gold: scoop it up + let t = self.map.t[cur]; + if t.kind == Kind::Treasury && t.gold > 0 && master_ground(&t) { + e.path.clear(); + e.working = true; + if e.cd <= 0.0 { + e.cd = 0.5; + let want = THIEF_GRAB.min(THIEF_BAG - e.carry).min(t.gold); + let got = self.steal_gold(t.owner.side(), cur, want); + if got > 0 && e.carry == 0 && t.owner.side() == self.local_side { + self.tell_local("msg.thief_in_treasury", vec![], Some(Sfx::WaveAlarm)); + } + e.carry += got; + self.fx(5, e.x, e.y, 0.0, 0.0, 0.5, 0xff30d0ff); + } + return true; + } + // on the way to the nearest treasury with gold + if e.path.is_empty() && e.repath <= 0.0 { + e.repath = 2.0; + let cost = self.map.hero_cost(); + let found = self.map.search(cur, cost, |i| { + let t = &self.map.t[i]; + t.kind == Kind::Treasury && t.gold > 0 && master_ground(t) + }, true); + match found { + Some(p) => e.path = p, + None if e.carry > 0 => {} + None => return false, // nothing to steal: he fights like the others + } + } + if e.path.is_empty() { + return e.carry > 0; + } + self.step_path(e, dt); + true + } + + // is there a treasury with gold anywhere a thief could reach from tile i? + fn gold_to_steal(&self, i: usize) -> bool { + let cost = self.map.hero_cost(); + self.map.search(i, cost, |j| { + let t = &self.map.t[j]; + t.kind == Kind::Treasury && t.gold > 0 && master_ground(t) + }, true).is_some() + } + + // takes gold from the treasury tile i of the master on `side`; returns what was taken + fn steal_gold(&mut self, side: u8, i: usize, want: i32) -> i32 { + let me = self.me_side; + if side != me { + if !self.is_master(side) { + return 0; + } + self.switch_to(side); + } + let take = (want as f32).min(self.gold).floor().max(0.0) as i32; + self.gold -= take as f32; + let t = &mut self.map.t[i]; + t.gold = (t.gold - take).max(0); + if side != me { + self.switch_to(me); + } + take + } + + // a slain thief drops his loot: it goes to whoever slew him (with the bounty) + pub(crate) fn thief_loot(&self, id: u32) -> f32 { + self.ents.iter().find(|e| e.id == id).map_or(0.0, |e| e.carry.max(0) as f32) + } + + // ------------------------------------------------------------ ranger + + // a snare on the dungeon's ground under the ranger's feet, now and then + fn lay_snare(&mut self, e: &mut Ent) { + if e.skill_cd > 0.0 || self.snares.len() >= MAX_SNARES { + return; + } + let i = e.tile(); + let t = &self.map.t[i]; + if !t.walkable() || !master_ground(t) || t.bridge() || self.snares.contains(&i) || self.traps.iter().any(|tr| tr.tile == i) { + e.skill_cd = 2.0; + return; + } + self.snares.push(i); + e.skill_cd = SNARE_EVERY; + self.fx(6, e.x, e.y, 0.0, 0.0, 0.4, 0xff3a5a7a); + } + + // the shared step: a creature that steps into a snare is caught (hurt and stuck for a while) + pub(crate) fn update_snares(&mut self) { + if self.snares.is_empty() { + return; + } + let mut k = 0; + while k < self.snares.len() { + let i = self.snares[k]; + if !self.map.t[i].walkable() { + self.snares.swap_remove(k); + continue; + } + let caught = self.ents.iter().position(|e| { + e.alive && !e.held && !e.hero && !e.chained && e.captive == 0 && !flies(e.kind) && Owner::MASTER_SIDES.contains(&e.side) && e.tile() == i + }); + let Some(j) = caught else { + k += 1; + continue; + }; + self.snares.swap_remove(k); + let e = &mut self.ents[j]; + e.stun = e.stun.max(SNARE_STUN); + e.hp -= SNARE_DAMAGE; + e.flash = 0.2; + let (x, y, side, kind, dead) = (e.x, e.y, e.side, e.kind, e.hp <= 0.0); + self.fx(2, x, y, 0.0, 0.0, 0.4, 0xff4040ff); + self.sfx(Sfx::MeleeHit, x, y); + if side == self.local_side { + self.tell_local("msg.snare_caught", vec![format!("@{}", st(kind).name)], None); + } + if dead { + self.kill(j); + } + } + } + + // ------------------------------------------------------------ inquisitor + + // turns the nearest weak creature in sight to the heroes' side + fn convert_creature(&mut self, e: &mut Ent) { + if e.skill_cd > 0.0 { + return; + } + e.skill_cd = 1.0; + let target = self + .ents + .iter() + .enumerate() + .filter(|(_, o)| o.alive && !o.held && !o.hero && !o.chained && o.captive == 0 && convertible(o.kind) && Owner::MASTER_SIDES.contains(&o.side)) + .map(|(j, o)| (j, (o.x - e.x).powi(2) + (o.y - e.y).powi(2))) + .filter(|&(j, d2)| d2 < CONVERT_RANGE * CONVERT_RANGE && self.los(e.x, e.y, self.ents[j].x, self.ents[j].y)) + .min_by(|a, b| a.1.partial_cmp(&b.1).unwrap_or(std::cmp::Ordering::Equal)) + .map(|(j, _)| j); + let Some(j) = target else { return }; + e.skill_cd = CONVERT_EVERY; + let goal = e.target; + let (side, kind, id, x, y) = { + let o = &self.ents[j]; + (o.side, o.kind, o.id, o.x, o.y) + }; + self.release_all(id); + let o = &mut self.ents[j]; + o.hero = true; + o.side = 1; + o.job = Job::None; + o.path.clear(); + o.home = None; + o.bed = None; + o.guard = false; + o.target = goal; + o.waypoint = None; + o.flash = 0.4; + self.shot(e.x, e.y, 0.6, x, y, 0.45, 0.35, 0xff40d0ff); + self.style_last_fx(crate::particles::ST_HOLY); + self.fx(4, x, y, 0.0, 0.0, 0.9, 0xffffeecc); + self.sfx(Sfx::Capture, x, y); + if side == self.local_side { + self.tell_local("msg.converted", vec![format!("@{}", st(kind).name)], Some(Sfx::WaveAlarm)); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + // a free game with an open dungeon around the core and no waves + fn open_game() -> Game { + let mut g = Game::new(5, 96, 96); + g.gate_on = false; + let (cx, cy) = g.map.core; + for y in cy - 8..cy + 10 { + for x in cx - 8..cx + 10 { + let t = &mut g.map.t[idx(x, y)]; + if t.kind != Kind::Core { + t.kind = Kind::Floor; + t.owner = Owner::Player; + } + } + } + g.ents.clear(); + g.recount(); + g + } + + fn hero(g: &mut Game, k: EK, x: f32, y: f32) -> u32 { + let id = g.spawn(k, true, x, y, 1); + if let Some(e) = g.ents.iter_mut().find(|e| e.id == id) { + e.job = Job::None; + } + id + } + + #[test] + fn a_thief_steals_from_the_treasury() { + let mut g = open_game(); + let (cx, cy) = g.map.core; + g.build_rect(0, cx + 4, cy + 4, cx + 6, cy + 6); + g.gold = 3000.0; + g.sync_treasury(); + let gold0 = g.gold; + let id = hero(&mut g, EK::Thief, cx as f32 - 5.5, cy as f32 + 5.5); + let mut carried = 0; + for _ in 0..(60 * 20) { + g.state = 0; // no creatures in the test: it would count as over + g.update(0.05); + carried = g.ents.iter().find(|e| e.id == id).map_or(carried, |e| e.carry); + if carried >= THIEF_BAG { + break; + } + } + assert!(carried > 0, "the thief took gold"); + assert!(g.gold < gold0, "the master lost it: {} -> {}", gold0, g.gold); + } + + #[test] + fn monks_shrug_off_spells() { + let mut g = open_game(); + let (cx, cy) = g.map.core; + let monk = hero(&mut g, EK::Monk, cx as f32 + 6.5, cy as f32 + 6.5); + let knight = hero(&mut g, EK::Knight, cx as f32 + 6.5, cy as f32 + 7.0); + g.mana = 400.0; + g.lightning(cx as f32 + 6.5, cy as f32 + 6.7); + let hp = |g: &Game, id: u32| g.ents.iter().find(|e| e.id == id).map_or(0.0, |e| e.hp); + assert_eq!(hp(&g, monk), st(EK::Monk).hp, "the monk is untouched"); + assert!(hp(&g, knight) < st(EK::Knight).hp, "the knight is not"); + } + + #[test] + fn a_rangers_snare_catches_a_creature() { + let mut g = open_game(); + let (cx, cy) = g.map.core; + let r = hero(&mut g, EK::Ranger, cx as f32 + 6.5, cy as f32 + 6.5); + let mut e = g.ents.iter().find(|e| e.id == r).unwrap().clone(); + e.skill_cd = 0.0; + g.lay_snare(&mut e); + let i = idx(cx + 6, cy + 6); + assert!(g.snares.contains(&i)); + g.ents.retain(|e| e.id != r); + let k = g.spawn(EK::Ogre, false, cx as f32 + 6.5, cy as f32 + 6.5, 1); + g.update_snares(); + let o = g.ents.iter().find(|e| e.id == k).unwrap(); + assert!(o.stun > 0.0 && o.hp < st(EK::Ogre).hp, "caught"); + assert!(g.snares.is_empty(), "a snare works once"); + } + + #[test] + fn the_inquisitor_turns_only_weak_creatures() { + let mut g = open_game(); + let (cx, cy) = g.map.core; + let ogre = g.spawn(EK::Ogre, false, cx as f32 + 5.5, cy as f32 + 6.0, 1); + let kobold = g.spawn(EK::Kobold, false, cx as f32 + 6.5, cy as f32 + 7.5, 1); + let q = hero(&mut g, EK::Inquisitor, cx as f32 + 6.5, cy as f32 + 5.5); + let mut e = g.ents.iter().find(|e| e.id == q).unwrap().clone(); + e.skill_cd = 0.0; + g.convert_creature(&mut e); + let get = |g: &Game, id: u32| g.ents.iter().find(|e| e.id == id).unwrap().clone(); + assert!(get(&g, kobold).hero, "the kobold now fights for the heroes"); + assert!(!get(&g, ogre).hero, "an ogre is too strong to be turned"); + assert_eq!(e.skill_cd, CONVERT_EVERY); + // nothing else to turn: the ogre stays + e.skill_cd = 0.0; + g.convert_creature(&mut e); + assert!(!get(&g, ogre).hero); + } + + #[test] + fn rogues_join_the_later_waves() { + for (k, wave, mission) in ROGUES { + assert!(wave >= 3 && mission >= 4, "{:?} comes late", k); + } + assert!(ROGUES.iter().any(|r| r.0 == EK::Inquisitor && r.1 == 9)); + } +} diff --git a/src/scenes.rs b/src/scenes.rs index 42115e8..c2d7b05 100644 --- a/src/scenes.rs +++ b/src/scenes.rs @@ -243,3 +243,24 @@ fn export_grove_scene() { run(&mut g, 1.0); save("mushroom-grove", &mut g, x as f32 + 0.5, y as f32 + 0.5, 12.0, 0.0, false); } + +// the rogues of the later waves in a dungeon: thief, monk, ranger, inquisitor and a snare +#[test] +#[ignore] +fn export_rogues_scene() { + std::fs::create_dir_all("/tmp/scenes").unwrap(); + let mut g = Game::new(11, 80, 64); + let (cx, cy) = g.map.core; + open(&mut g, cx - 9, cy - 8, cx + 11, cy + 9); + g.place_all_torches(); + for (k, kind) in [EK::Thief, EK::Monk, EK::Ranger, EK::Inquisitor].into_iter().enumerate() { + let id = g.spawn(kind, true, cx as f32 + 4.5 + k as f32 * 1.2, cy as f32 + 5.5, 3); + if let Some(e) = g.ents.iter_mut().find(|e| e.id == id) { + e.guard = true; + e.home = Some((e.x, e.y)); + } + } + g.snares.push(idx(cx + 5, cy + 3)); + g.snares.push(idx(cx + 7, cy + 3)); + save("rogues", &mut g, cx as f32 + 6.5, cy as f32 + 4.5, 8.0, 0.0, false); +} diff --git a/src/spells.rs b/src/spells.rs index 7cca226..56f1f49 100644 --- a/src/spells.rs +++ b/src/spells.rs @@ -74,7 +74,7 @@ impl Spell { } fn foe(e: &Ent) -> bool { - e.alive && !e.held && e.captive == 0 && !e.chained && e.side() != 0 + e.alive && !e.held && e.captive == 0 && !e.chained && e.side() != 0 && !crate::rogues::spell_proof(e) } fn own(e: &Ent) -> bool {