Editor texts (EN/DE), whole-campaign play and briefings for editor missions

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard ZinkandClaude Opus 5.5 committed 2026-11-05 17:15:20 +01:00
1 parent 30dd8441b9
commit 985c34759d
6 files changed
+705 -14

No files matched your search

+315
View File
@@ -1012,3 +1012,318 @@ ov.summary = {0} Kreaturen - Lohn {1} Gold pro Zahltag - Laune {2}%
ov.none = Noch keine Kreaturen. Baue ein Quartier und einen Pilzgarten und nimm ein Portal ein. ov.none = Noch keine Kreaturen. Baue ein Quartier und einen Pilzgarten und nimm ein Portal ein.
ov.hint = St., Laune, Lohn, Tätigkeit, Leben - Klick: hingehen ov.hint = St., Laune, Lohn, Tätigkeit, Leben - Klick: hingehen
set.voice = Krummfingers Stimme set.voice = Krummfingers Stimme
# ---- campaign editor, block scripts, demo campaign
menu.back_editor = Zurück zum Editor
ed.campaign = Kampagneneditor
ed.name = Name
ed.author = Autor
ed.language = Sprache
ed.play = Spielen
ed.new = Neu
ed.open = Öffnen
ed.save_file = Als Datei
ed.save_server = Online speichern
ed.close = Schließen
ed.published = Veröffentlicht
ed.add_mission = + Mission
ed.new_campaign = Neue Kampagne
ed.card_scripts = {0} Trigger
ed.card_problems = {0} Probleme
ed.graph_hint = Klick auf eine Karte bearbeitet sie. Karten ziehen verschiebt sie, vom Punkt auf eine Karte ziehen verbindet Missionen (gold: weiter, blau: Abzweig). Rechte Maustaste verschiebt die Ansicht.
ed.open_file = Datei öffnen
ed.open_demo = Demo öffnen
ed.template = Eine Mission der Kampagne als Kopie
ed.template_add = Hinzufügen
ed.own_campaigns = Meine Kampagnen (online)
ed.public_campaigns = Veröffentlichte Kampagnen
ed.none = keine
ed.cancel = Abbrechen
ed.back_graph = < Kampagne
ed.test = Testspiel
ed.tab_general = Allgemein
ed.tab_goals = Ziele
ed.tab_map = Karte
ed.tab_scripts = Skripte
ed.title = Titel
ed.briefing = Briefing
ed.gold = Startgold
ed.time_limit = Zeitlimit
ed.waves = Heldenwellen
ed.wave_limit = Wellen
ed.endless = endlos
ed.first_wave = Erste Welle
ed.goals = Ziele
ed.goals_hint = Die Mission ist gewonnen, wenn alle Ziele erreicht sind (oder ein Skript "Gewinnen" ruft).
ed.add_goal = + Ziel
ed.next_mission = Nächste Mission
ed.branches = Abzweige
ed.branches_hint = Wird zuerst ein anderes Ziel erreicht, geht die Kampagne mit einer anderen Mission weiter.
ed.add_branch = + Abzweig
ed.goal.killall = Alle Helden besiegen
ed.goal.shards = Splitter holen
ed.goal.heart = Tor zerstören
ed.goal.towers = Rittertürme schleifen
ed.goal.rivals = Rivalen besiegen
ed.goal.loot = Gold erbeuten
ed.goal.survive = Wellen überstehen
ed.goal.springs = Manaquellen nehmen
ed.goal.freed = Kreaturen befreien
ed.map_random = Zufallskarte
ed.map_fixed = Gemalte Karte
ed.map_is_random = Zufallskarte
ed.map_is_fixed = Gemalte Karte
ed.map_random_hint = Wird für jeden Durchgang der Kampagne neu gewürfelt und bleibt im Durchgang gleich.
ed.map_fixed_hint = Im Karteneditor gemalt; sie ändert sich nie.
ed.map_width = Breite
ed.map_height = Höhe
ed.map_seed = Seed
ed.rivers = Flüsse
ed.lava_rivers = Lavaflüsse
ed.forts = Ritterfestungen
ed.rivals = Rivalen-Meister
ed.difficulty = Schwierigkeit
ed.portals = Portale
ed.edit_map = Karte bearbeiten
ed.make_random = Zur Zufallskarte machen
ed.paint_map = Karte erzeugen und malen
ed.zones_list = Zonen ({0}): {1}
ed.special_scripts = Sonderskripte
ed.script_start = Start (einmal)
ed.script_victory = Siegprüfung (jede Sekunde)
ed.script_defeat = Niederlageprüfung (jede Sekunde)
ed.script_tick = Takt (jede Sekunde)
ed.blocks_count = {0} Blöcke
ed.blocks_problems = {0} Blöcke, {1} Probleme
ed.edit_blocks = Bearbeiten
ed.triggers = Trigger
ed.triggers_hint = Ein Trigger führt seine Blöcke aus, sobald seine Bedingung erfüllt ist. Zonen werden im Karteneditor gezeichnet.
ed.add_trigger = + Trigger
ed.once = einmal
ed.enabled = aktiv
ed.edit_trigger_blocks = Blöcke ({0})
ed.pick_zone = - Zone -
ed.pick_var = - Variable -
ed.pick_trigger = - Trigger -
ed.any_kind = jede Art
ed.any_room = jeder Raum
ed.any_spell = jeder Zauber
ed.every = alle
ed.after = nach
ed.repeat = wiederholen
ed.unit_name = Name
ed.towers_dungeon = Türme des Kerkers
ed.towers_knights = Türme der Ritter
ed.no_settings = (nichts einzustellen)
ed.side.player = Spieler
ed.side.heroes = Helden
ed.side.mossgrim = Mossgrim
ed.side.nightwell = Lady Nightwell
ed.side.rival3 = Rivale 3
ed.side.any = alle
ed.trig.zone_enter = Zone betreten
ed.trig.zone_leave = Zone verlassen
ed.trig.line_cross = Linie überquert
ed.trig.zone_claimed = Zone erobert
ed.trig.zone_dug = In Zone gegraben
ed.trig.zone_count = Einheiten in Zone
ed.trig.timer = Timer
ed.trig.unit_dies = Einheit fällt
ed.trig.tower_falls = Turm fällt
ed.trig.value = Wert erreicht
ed.trig.room_built = Raum gebaut
ed.trig.spell_cast = Zauber gewirkt
ed.trig.slap = Kreatur geschlagen
ed.trig.research = Forschung fertig
ed.value.gold = Gold
ed.value.mana = Mana
ed.value.creatures = Kreaturen
ed.value.heroes = Helden
ed.value.var = Variable
ed.map_done = Fertig
ed.cat.terrain = Boden
ed.cat.rooms = Räume
ed.cat.places = Orte
ed.cat.units = Einheiten
ed.cat.towers = Türme
ed.cat.traps = Fallen
ed.cat.forts = Festungen
ed.cat.zones = Zonen
ed.cat.erase = Löschen
ed.terrain.floor = Boden
ed.terrain.earth = Erde
ed.terrain.reinforced = Befestigte Wand
ed.terrain.rock = Fels
ed.terrain.water = Wasser
ed.terrain.lava = Lava
ed.terrain.bridge = Brücke
ed.terrain.lavabridge = Lavabrücke
ed.terrain.gold = Goldader
ed.terrain.silver = Silberader
ed.terrain.ruby = Rubinader
ed.terrain.diamond = Diamantader
ed.terrain.steel = Stahlwand
ed.place.core = Seelenkern
ed.place.portal = Portal
ed.place.gate = Heldentor
ed.place.spring = Manaquelle
ed.place.shard = Kernsplitter
ed.place.chest = Runentruhe
ed.place.chained = Angekettete Kreatur
ed.tower.arrow = Pfeilturm
ed.tower.cannon = Kanonenturm
ed.tower.magic = Magieturm
ed.tower.rune = Runenschmiedeturm
ed.trap.spikes = Stachelgrube
ed.trap.poison = Giftwolke
ed.trap.fire = Feuerstrahl
ed.trap.roller = Steinwalze
ed.trap.alarm = Alarm
ed.trap.mine = Runenmine
ed.trap.frost = Frostglut
ed.trap.wooddoor = Holztür
ed.trap.irondoor = Eisentür
ed.trap.magicdoor = Magietür
ed.fort = Ritterfestung
ed.fort_shard = Festung mit Splitter
ed.owner = Besitzer
ed.side = Seite
ed.unit_kind = Art
ed.level = Stufe
ed.zone_shape = Form einer neuen Zone
ed.zone_new_name = Name einer neuen Zone
ed.zones = Zonen
ed.shape.rect = Rechteck
ed.shape.circle = Kreis
ed.shape.tiles = Kacheln
ed.shape.line = Linie
ed.brush = Pinsel
ed.rect = Rechteck
ed.fill = Füllen
ed.mirror0 = Kein Spiegeln
ed.mirror1 = Spiegeln links/rechts
ed.mirror2 = Spiegeln oben/unten
ed.mirror3 = Spiegeln beides
ed.undo = Rückgängig
ed.redo = Wiederholen
ed.map_info = {0}x{1}, {2} Einheiten, {3} Türme
ed.map_hint = Links: malen/setzen, rechts: Ansicht schieben, Mitte: drehen, Rad: Zoom, WASD/QE, Strg+Z/Y
ed.back = < Zurück
ed.delete = Löschen
ed.paste = Einfügen
ed.copy = Kopieren
ed.search = Suchen...
ed.no_problems = Keine Probleme
ed.problems = {0} Probleme (rot)
ed.blocks_hint = Blöcke ins Skript ziehen. Am Griff verschieben, hierher zurückziehen löscht sie.
ed.empty_script = Leer: Blöcke von links hierher ziehen.
ed.drop_here = Blöcke hier ablegen
ed.trigger_script = Trigger: {0}
ed.saved_server = Online gespeichert.
ed.loaded = Kampagne geladen.
ed.no_server = Keine Verbindung zum Server.
ed.busy = Der Server ist noch beschäftigt, gleich noch einmal versuchen.
ed.save_first = Die Kampagne zuerst online speichern.
ed.debug_title = Skripte (Test)
blk.cat.say = Sprechen
blk.cat.units = Einheiten
blk.cat.world = Welt
blk.cat.logic = Logik
blk.cat.vars = Variablen
blk.cat.mission = Mission
blk.message = Nachricht
blk.objective = Auftrag
blk.hint = Krummfinger sagt
blk.spawn = Erscheinen
blk.wave = Heldenwelle
blk.kill = Entfernen
blk.terrain = Boden ändern
blk.reveal = Aufdecken
blk.camera = Zeigen
blk.gold = Gold +
blk.mana = Mana +
blk.if = Wenn
blk.repeat = Wiederhole
blk.trigger = Trigger schalten
blk.setvar = Setze
blk.addvar = Ändere
blk.win = Mission gewinnen
blk.lose = Mission verlieren
blk.else = sonst
blk.help.message = Zeigt eine Nachricht. {name} im Text zeigt den Wert einer Variable.
blk.help.objective = Setzt den Auftrag, den der Spieler sieht.
blk.help.hint = Krummfinger kommentiert etwas, mit Ton.
blk.help.spawn = Einheiten erscheinen: wie viele, welche Art, Stufe, Seite und wo (Kern, bei der auslösenden Einheit oder in einer Zone). Mit Namen kann ein "Einheit fällt"-Trigger genau auf diese Einheit warten.
blk.help.wave = Schickt sofort Heldenwellen.
blk.help.kill = Entfernt alle Einheiten einer Seite in einer Zone.
blk.help.terrain = Macht den Boden einer Zone zu Boden, Erde, Fels, Wasser, Lava oder Gold.
blk.help.reveal = Hebt den Nebel über einer Zone.
blk.help.camera = Bewegt die Kamera zu einer Zone.
blk.help.gold = Gibt (oder nimmt) Gold.
blk.help.mana = Gibt (oder nimmt) Mana.
blk.help.if = Führt die Blöcke darin nur aus, wenn die Bedingung gilt, sonst die unter "sonst".
blk.help.repeat = Führt die Blöcke darin mehrmals aus.
blk.help.trigger = Schaltet einen Trigger ein (er darf erneut auslösen) oder aus.
blk.help.setvar = Setzt eine Variable (eine Zahl, die sich die Mission merkt).
blk.help.addvar = Zählt eine Zahl zu einer Variable dazu (negativ: zieht ab).
blk.help.win = Die Mission ist gewonnen.
blk.help.lose = Die Mission ist verloren.
blk.v.num = Zahl
blk.v.var = Variable
blk.v.gold = Gold
blk.v.mana = Mana
blk.v.time = Gespielte Sekunden
blk.v.creatures = Anzahl
blk.v.inzone = Anzahl
blk.v.random = Zufall
blk.v.math = Rechnung
blk.v.cmp = Vergleich
blk.v.and = und
blk.v.or = oder
blk.v.not = nicht
blk.v.bool = Ja/Nein
blk.v.eventkind = Auslöser ist ein
blk.w_at = bei
blk.w_by = um
blk.w_in = in
blk.w_level = Stufe
blk.w_name = Name
blk.w_times = mal
blk.w_to = auf
blk.and = und
blk.or = oder
blk.not = nicht
blk.yes = ja
blk.no = nein
blk.on = an
blk.off = aus
blk.place_core = dem Kern
blk.place_event = der auslösenden Einheit
blk.place_zone = Zone {0}
demo.name = Demo: alle Trigger
demo.branch = Reich genug für einen Umweg
demo.m1.title = Die Probe der Trigger
demo.m1.story = Ein kleiner Ritterposten östlich deines Herzens, ein Tresor, eine Höhle, ein Tunnel und eine Grenzlinie.\n\nJeder Trigger des Editors löst hier irgendwo aus: Betritt die Höhle, grabe den Tunnel, erobere den Tresor, schlag eine Kreatur, wirk einen Zauber, bau einen Hort, erforsche etwas und brich den Posten.
demo.start = Willkommen zur Probe, Meister. Jeder deiner Schritte wird von einem Trigger beobachtet. Meistens auch von mir.
demo.objective = Schleife die Rittertürme - oder besiege acht Ritter.
demo.win = Acht Ritter erledigt. Die Probe ist bestanden!
demo.lose = Zehn Minuten ohne eine einzige Kreatur? Das ist kein Kerker, das ist ein Keller.
demo.tick = Zwei Minuten gespielt. Der Uhr-Trigger hat viermal gezählt.
demo.den = Die Höhle ist offen. Ein verschlafener Oger kriecht heraus, um zu sehen, wer stört.
demo.den_leave = Jemand hat die Höhle wieder verlassen. Der Oger bleibt.
demo.border = Ritter überqueren die Grenzlinie!
demo.vault = Der Tresor gehört dir: 500 Gold klimpern in die Schatzkammer.
demo.tunnel = Der Tunnel ist gegraben. Irgendetwas darunter seufzt erleichtert.
demo.crowd = Vier oder mehr Ritter sammeln sich auf dem Feld!
demo.wave = Verstärkung! Zwei Bogenschützinnen marschieren aufs Feld.
demo.kills = Besiegte Ritter: {kills}
demo.captain = Der Hauptmann ist gefallen. Sein Mana gehört dir.
demo.tower = Ein Ritterturm fällt - und lässt etwas Gold fallen.
demo.rich = 8000 Gold. Du darfst dich jetzt wohlhabend nennen.
demo.lair = Ein Hort! Kreaturen brauchen Betten, auch böse.
demo.slap = Autsch. Der Schlag-Trigger hat es bemerkt. Die Kreatur auch.
demo.research = Forschung fertig. Ein wenig Gold für die Gelehrten.
demo.m2.title = Neu gewürfelt
demo.m2.story = Diese Karte wird für jeden Durchgang der Kampagne neu gewürfelt. Besiege alle Helden.
demo.m2.start = Eine Zufallskarte. Selbst ich habe sie noch nie gesehen.
demo.m2.wave = Zwei Minuten sind um: Die Helden kommen.
+315
View File
@@ -1013,3 +1013,318 @@ ov.summary = {0} creatures - wages {1} gold per payday - mood {2}%
ov.none = No creatures yet. Build a lair and a mushroom garden and claim a portal. ov.none = No creatures yet. Build a lair and a mushroom garden and claim a portal.
ov.hint = Lv, mood, wage, job, health - click: go there ov.hint = Lv, mood, wage, job, health - click: go there
set.voice = Crookfinger's voice set.voice = Crookfinger's voice
# ---- campaign editor, block scripts, demo campaign
menu.back_editor = Back to the editor
ed.campaign = Campaign editor
ed.name = Name
ed.author = Author
ed.language = Language
ed.play = Play
ed.new = New
ed.open = Open
ed.save_file = Save file
ed.save_server = Save online
ed.close = Close
ed.published = Published
ed.add_mission = + Mission
ed.new_campaign = New campaign
ed.card_scripts = {0} triggers
ed.card_problems = {0} problems
ed.graph_hint = Click a card to edit it. Drag a card to move it, drag from a dot to a card to link missions (gold: next, blue: branch). Right mouse button moves the view.
ed.open_file = Open a file
ed.open_demo = Open the demo
ed.template = A mission of the campaign as a copy
ed.template_add = Add
ed.own_campaigns = My campaigns (online)
ed.public_campaigns = Published campaigns
ed.none = none
ed.cancel = Cancel
ed.back_graph = < Campaign
ed.test = Test play
ed.tab_general = General
ed.tab_goals = Goals
ed.tab_map = Map
ed.tab_scripts = Scripts
ed.title = Title
ed.briefing = Briefing
ed.gold = Starting gold
ed.time_limit = Time limit
ed.waves = Hero waves
ed.wave_limit = Waves
ed.endless = endless
ed.first_wave = First wave
ed.goals = Goals
ed.goals_hint = The mission is won when all goals are reached (or a script calls Win).
ed.add_goal = + Goal
ed.next_mission = Next mission
ed.branches = Branches
ed.branches_hint = Reach another goal first and the campaign goes on with another mission.
ed.add_branch = + Branch
ed.goal.killall = Defeat all heroes
ed.goal.shards = Take the shards
ed.goal.heart = Destroy the gate
ed.goal.towers = Raze the knight towers
ed.goal.rivals = Defeat the rivals
ed.goal.loot = Loot gold
ed.goal.survive = Survive waves
ed.goal.springs = Claim mana springs
ed.goal.freed = Free creatures
ed.map_random = Random map
ed.map_fixed = Painted map
ed.map_is_random = Random map
ed.map_is_fixed = Painted map
ed.map_random_hint = Rolled anew for every run of the campaign, the same for the whole run.
ed.map_fixed_hint = Painted in the map editor; it never changes.
ed.map_width = Width
ed.map_height = Height
ed.map_seed = Seed
ed.rivers = Rivers
ed.lava_rivers = Lava rivers
ed.forts = Knight fortresses
ed.rivals = Rival masters
ed.difficulty = Difficulty
ed.portals = Portals
ed.edit_map = Edit the map
ed.make_random = Make it a random map
ed.paint_map = Generate and paint the map
ed.zones_list = Zones ({0}): {1}
ed.special_scripts = Special scripts
ed.script_start = Start (once)
ed.script_victory = Victory check (every second)
ed.script_defeat = Defeat check (every second)
ed.script_tick = Clock (every second)
ed.blocks_count = {0} blocks
ed.blocks_problems = {0} blocks, {1} problems
ed.edit_blocks = Edit
ed.triggers = Triggers
ed.triggers_hint = A trigger runs its blocks when its condition is met. Zones are drawn in the map editor.
ed.add_trigger = + Trigger
ed.once = once
ed.enabled = active
ed.edit_trigger_blocks = Blocks ({0})
ed.pick_zone = - zone -
ed.pick_var = - variable -
ed.pick_trigger = - trigger -
ed.any_kind = any kind
ed.any_room = any room
ed.any_spell = any spell
ed.every = every
ed.after = after
ed.repeat = repeat
ed.unit_name = Name
ed.towers_dungeon = the dungeon's towers
ed.towers_knights = the knights' towers
ed.no_settings = (nothing to set)
ed.side.player = Player
ed.side.heroes = Heroes
ed.side.mossgrim = Mossgrim
ed.side.nightwell = Lady Nightwell
ed.side.rival3 = Rival 3
ed.side.any = anyone
ed.trig.zone_enter = Zone entered
ed.trig.zone_leave = Zone left
ed.trig.line_cross = Line crossed
ed.trig.zone_claimed = Zone claimed
ed.trig.zone_dug = Dug in the zone
ed.trig.zone_count = Units in the zone
ed.trig.timer = Timer
ed.trig.unit_dies = A unit falls
ed.trig.tower_falls = A tower falls
ed.trig.value = A value is reached
ed.trig.room_built = Room built
ed.trig.spell_cast = Spell cast
ed.trig.slap = Creature slapped
ed.trig.research = Research done
ed.value.gold = Gold
ed.value.mana = Mana
ed.value.creatures = Creatures
ed.value.heroes = Heroes
ed.value.var = Variable
ed.map_done = Done
ed.cat.terrain = Ground
ed.cat.rooms = Rooms
ed.cat.places = Places
ed.cat.units = Units
ed.cat.towers = Towers
ed.cat.traps = Traps
ed.cat.forts = Forts
ed.cat.zones = Zones
ed.cat.erase = Erase
ed.terrain.floor = Floor
ed.terrain.earth = Earth
ed.terrain.reinforced = Reinforced wall
ed.terrain.rock = Rock
ed.terrain.water = Water
ed.terrain.lava = Lava
ed.terrain.bridge = Bridge
ed.terrain.lavabridge = Lava bridge
ed.terrain.gold = Gold vein
ed.terrain.silver = Silver vein
ed.terrain.ruby = Ruby vein
ed.terrain.diamond = Diamond vein
ed.terrain.steel = Steel wall
ed.place.core = Soul core
ed.place.portal = Portal
ed.place.gate = Hero gate
ed.place.spring = Mana spring
ed.place.shard = Core shard
ed.place.chest = Rune chest
ed.place.chained = Chained creature
ed.tower.arrow = Arrow tower
ed.tower.cannon = Cannon tower
ed.tower.magic = Magic tower
ed.tower.rune = Rune forge tower
ed.trap.spikes = Spike pit
ed.trap.poison = Poison cloud
ed.trap.fire = Fire jet
ed.trap.roller = Stone roller
ed.trap.alarm = Alarm
ed.trap.mine = Rune mine
ed.trap.frost = Frost glow
ed.trap.wooddoor = Wooden door
ed.trap.irondoor = Iron door
ed.trap.magicdoor = Magic door
ed.fort = Knight fortress
ed.fort_shard = Fortress with shard
ed.owner = Owner
ed.side = Side
ed.unit_kind = Kind
ed.level = Level
ed.zone_shape = Shape of a new zone
ed.zone_new_name = Name of a new zone
ed.zones = Zones
ed.shape.rect = Rectangle
ed.shape.circle = Circle
ed.shape.tiles = Tiles
ed.shape.line = Line
ed.brush = Brush
ed.rect = Rectangle
ed.fill = Fill
ed.mirror0 = No mirror
ed.mirror1 = Mirror left/right
ed.mirror2 = Mirror top/bottom
ed.mirror3 = Mirror both
ed.undo = Undo
ed.redo = Redo
ed.map_info = {0}x{1}, {2} units, {3} towers
ed.map_hint = Left: paint/place, right: move view, middle: turn, wheel: zoom, WASD/QE, Ctrl+Z/Y
ed.back = < Back
ed.delete = Delete
ed.paste = Paste
ed.copy = Copy
ed.search = Search...
ed.no_problems = No problems
ed.problems = {0} problems (red)
ed.blocks_hint = Drag blocks into the script. Move them by their grip, drop them here to delete them.
ed.empty_script = Empty: drag blocks from the left in here.
ed.drop_here = drop blocks here
ed.trigger_script = Trigger: {0}
ed.saved_server = Saved online.
ed.loaded = Campaign loaded.
ed.no_server = No connection to the server.
ed.busy = The server is still busy, try again in a moment.
ed.save_first = Save the campaign online first.
ed.debug_title = Scripts (test)
blk.cat.say = Speak
blk.cat.units = Units
blk.cat.world = World
blk.cat.logic = Logic
blk.cat.vars = Variables
blk.cat.mission = Mission
blk.message = Message
blk.objective = Objective
blk.hint = Crookfinger says
blk.spawn = Spawn
blk.wave = Hero wave
blk.kill = Remove
blk.terrain = Change ground
blk.reveal = Reveal
blk.camera = Show
blk.gold = Gold +
blk.mana = Mana +
blk.if = If
blk.repeat = Repeat
blk.trigger = Switch trigger
blk.setvar = Set
blk.addvar = Change
blk.win = Win the mission
blk.lose = Lose the mission
blk.else = else
blk.help.message = Shows a message. {name} in the text shows the value of a variable.
blk.help.objective = Sets the objective shown to the player.
blk.help.hint = Crookfinger comments on something, with a sound.
blk.help.spawn = Units appear: how many, which kind, level, side and where (core, where the trigger unit is, or in a zone). With a name, a "unit falls" trigger can wait for exactly this unit.
blk.help.wave = Sends hero waves at once.
blk.help.kill = Removes all units of a side in a zone.
blk.help.terrain = Turns the ground of a zone into floor, earth, rock, water, lava or gold.
blk.help.reveal = Lifts the fog of war over a zone.
blk.help.camera = Moves the camera to a zone.
blk.help.gold = Gives (or takes) gold.
blk.help.mana = Gives (or takes) mana.
blk.help.if = Runs the blocks inside only if the condition holds, otherwise the ones under "else".
blk.help.repeat = Runs the blocks inside several times.
blk.help.trigger = Switches a trigger on (it may fire again) or off.
blk.help.setvar = Sets a variable (a number the mission remembers).
blk.help.addvar = Adds a number to a variable (negative: subtracts).
blk.help.win = The mission is won.
blk.help.lose = The mission is lost.
blk.v.num = Number
blk.v.var = Variable
blk.v.gold = Gold
blk.v.mana = Mana
blk.v.time = Seconds played
blk.v.creatures = Count
blk.v.inzone = Count
blk.v.random = Random
blk.v.math = Calculation
blk.v.cmp = Comparison
blk.v.and = and
blk.v.or = or
blk.v.not = not
blk.v.bool = Yes/no
blk.v.eventkind = Trigger unit is a
blk.w_at = at
blk.w_by = by
blk.w_in = in
blk.w_level = level
blk.w_name = name
blk.w_times = times
blk.w_to = to
blk.and = and
blk.or = or
blk.not = not
blk.yes = yes
blk.no = no
blk.on = on
blk.off = off
blk.place_core = the core
blk.place_event = the trigger unit
blk.place_zone = zone {0}
demo.name = Demo: every trigger
demo.branch = Rich enough for a detour
demo.m1.title = The Trial of Triggers
demo.m1.story = A small knight outpost east of your heart, a vault, a den, a tunnel and a border line.\n\nEvery trigger of the editor fires somewhere here: walk into the den, dig the tunnel, claim the vault, slap a creature, cast a spell, build a lair, research something and break the outpost.
demo.start = Welcome to the trial, master. Every move of yours is watched by a trigger. Mostly by me, too.
demo.objective = Raze the knight towers - or defeat eight knights.
demo.win = Eight knights down. The trial is passed!
demo.lose = Ten minutes without a single creature? That is no dungeon, that is a cellar.
demo.tick = Two minutes of play. The clock trigger has counted four times.
demo.den = The den is open. A sleepy ogre crawls out to see who disturbs it.
demo.den_leave = Someone left the den again. The ogre stays.
demo.border = Knights cross the border line!
demo.vault = The vault is yours: 500 gold rattle into the treasury.
demo.tunnel = The tunnel is dug. Something below it sighs with relief.
demo.crowd = Four or more knights gather on the field!
demo.wave = Reinforcements! Two archers march onto the field.
demo.kills = Knights defeated: {kills}
demo.captain = The captain has fallen. His mana is yours.
demo.tower = A knight tower falls - and drops some gold.
demo.rich = 8000 gold. You may now call yourself well-off.
demo.lair = A lair! Creatures need beds, even evil ones.
demo.slap = Ouch. The slap trigger noticed. So did the creature.
demo.research = Research done. A little gold for the scholars.
demo.m2.title = Rolled Anew
demo.m2.story = This map is rolled anew for every run of the campaign. Defeat every hero.
demo.m2.start = A random map. Even I have never seen it before.
demo.m2.wave = Two minutes are over: the heroes come.
+9 -7
View File
@@ -43,6 +43,7 @@ pub enum EdAction {
None, None,
Close, Close,
Test(usize), Test(usize),
Play, // the whole campaign from its first mission, following the branches
SaveFile, SaveFile,
OpenFile, OpenFile,
ServerSave, ServerSave,
@@ -280,31 +281,32 @@ impl Editor {
self.doc.language = langs[k].0.clone(); self.doc.language = langs[k].0.clone();
} }
// buttons on the right // buttons on the right
let labels = [tr("ed.new"), tr("ed.open"), tr("ed.save_file"), tr("ed.save_server"), tr("ed.close")]; let labels = [tr("ed.play"), tr("ed.new"), tr("ed.open"), tr("ed.save_file"), tr("ed.save_server"), tr("ed.close")];
let bw = labels.iter().map(|l| gfx.measure(l, S())).fold(0.0, f32::max) + CW() * 2.0; let bw = labels.iter().map(|l| gfx.measure(l, S())).fold(0.0, f32::max) + CW() * 2.0;
let mut bx = w - CW() - bw; let mut bx = w - CW() - bw;
for k in (0..labels.len()).rev() { for k in (0..labels.len()).rev() {
let r = Rect::new(bx, CH() * 0.6, bw, CH() * 1.7); let r = Rect::new(bx, CH() * 0.6, bw, CH() * 1.7);
if im.button(gfx, r, &labels[k]) { if im.button(gfx, r, &labels[k]) {
match k { match k {
0 => { 0 => act = EdAction::Play,
1 => {
self.doc = CampaignDoc { name: tr("ed.new_campaign"), language: crate::i18n::language(), ..CampaignDoc::default() }; self.doc = CampaignDoc { name: tr("ed.new_campaign"), language: crate::i18n::language(), ..CampaignDoc::default() };
self.doc.add_mission(); self.doc.add_mission();
self.server_id = None; self.server_id = None;
} }
1 => { 2 => {
self.open_dialog = true; self.open_dialog = true;
act = EdAction::ServerRefresh; act = EdAction::ServerRefresh;
} }
2 => act = EdAction::SaveFile, 3 => act = EdAction::SaveFile,
3 => act = EdAction::ServerSave, 4 => act = EdAction::ServerSave,
_ => act = EdAction::Close, _ => act = EdAction::Close,
} }
} }
bx -= bw + CW() * 0.5; bx -= bw + CW() * 0.5;
} }
let mut publ = self.published; let mut publ = self.published;
if self.server_id.is_some() && im.toggle(gfx, w - CW() * 2.0 - bw * 3.0, CH() * 3.1, &tr("ed.published"), &mut publ) { if self.server_id.is_some() && im.toggle(gfx, w - CW() * 2.0 - bw * 3.5, CH() * 3.1, &tr("ed.published"), &mut publ) {
self.published = publ; self.published = publ;
act = EdAction::Publish(publ); act = EdAction::Publish(publ);
} }
@@ -748,7 +750,7 @@ impl Editor {
(tr("ed.lava_rivers"), m.gen.lava.to_string(), 4), (tr("ed.lava_rivers"), m.gen.lava.to_string(), 4),
(tr("ed.forts"), m.gen.forts.to_string(), 5), (tr("ed.forts"), m.gen.forts.to_string(), 5),
(tr("ed.rivals"), m.gen.rivals.to_string(), 6), (tr("ed.rivals"), m.gen.rivals.to_string(), 6),
(tr("ed.difficulty"), tr(["diff.easy", "diff.medium", "diff.hard"][m.gen.difficulty.min(2) as usize]), 7), (tr("ed.difficulty"), tr(["diff.0", "diff.1", "diff.2"][m.gen.difficulty.min(2) as usize]), 7),
(tr("ed.portals"), m.portals.to_string(), 8), (tr("ed.portals"), m.portals.to_string(), 8),
]; ];
if fixed { if fixed {
+2 -2
View File
@@ -88,7 +88,7 @@ pub fn demo_campaign() -> CampaignDoc {
let mut m = MissionDoc { let mut m = MissionDoc {
key: "demo1".into(), key: "demo1".into(),
title: tr("demo.m1.title"), title: tr("demo.m1.title"),
story: tr("demo.m1.story"), story: tr("demo.m1.story").replace("\\n", "\n"),
size: (80, 64), size: (80, 64),
seed: 4242, seed: 4242,
gold: 4000.0, gold: 4000.0,
@@ -181,7 +181,7 @@ pub fn demo_campaign() -> CampaignDoc {
let mut m2 = MissionDoc { let mut m2 = MissionDoc {
key: "demo2".into(), key: "demo2".into(),
title: tr("demo.m2.title"), title: tr("demo.m2.title"),
story: tr("demo.m2.story"), story: tr("demo.m2.story").replace("\\n", "\n"),
size: (72, 64), size: (72, 64),
seed: 77, seed: 77,
gold: 3000.0, gold: 3000.0,
+31 -4
View File
@@ -196,6 +196,12 @@ fn sanitize_campaign_key(value: &str) -> String {
value.trim().chars().filter(|c| c.is_ascii_alphanumeric() || *c == '_' || *c == '-').take(48).collect() value.trim().chars().filter(|c| c.is_ascii_alphanumeric() || *c == '_' || *c == '-').take(48).collect()
} }
// the briefing of an editor mission (None: it has no text)
fn briefing_of(doc: &campaign_doc::CampaignDoc, i: usize) -> Option<(String, String)> {
let m = doc.missions.get(i)?;
(!m.story.trim().is_empty()).then(|| (m.title.clone(), m.story.clone()))
}
// a mission of an editor campaign (its map is painted, or rolled from the run's seed) // a mission of an editor campaign (its map is painted, or rolled from the run's seed)
fn custom_mission_game(doc: &campaign_doc::CampaignDoc, i: usize, run_seed: u32) -> (Game, Cam) { fn custom_mission_game(doc: &campaign_doc::CampaignDoc, i: usize, run_seed: u32) -> (Game, Cam) {
let g = campaign::start_editor_mission(&doc.missions[i], i, run_seed); let g = campaign::start_editor_mission(&doc.missions[i], i, run_seed);
@@ -438,9 +444,11 @@ struct App {
frame_hist: [f32; FRAME_HIST], frame_hist: [f32; FRAME_HIST],
frame_hist_pos: usize, frame_hist_pos: usize,
editor: Option<editor::Editor>, // the campaign editor (takes the whole frame while open) editor: Option<editor::Editor>, // the campaign editor (takes the whole frame while open)
editor_testing: bool, // a mission of the editor is being played editor_testing: bool, // the editor waits while one of its missions is played
editor_test_only: bool, // only that mission (test play); else the campaign goes on
editor_public_pending: bool, // the public campaign list still has to be fetched editor_public_pending: bool, // the public campaign list still has to be fetched
editor_loading: Option<String>, // server id of the own campaign being loaded editor_loading: Option<String>, // server id of the own campaign being loaded
pending_briefing: Option<(String, String)>, // an editor mission began: show its briefing
custom_campaign: Option<campaign_doc::CampaignDoc>, custom_campaign: Option<campaign_doc::CampaignDoc>,
custom_progress: Option<campaign_doc::CampaignProgress>, custom_progress: Option<campaign_doc::CampaignProgress>,
custom_mission_index: Option<usize>, custom_mission_index: Option<usize>,
@@ -652,7 +660,7 @@ async fn main() {
let seed = (miniquad::date::now() * 1000.0) as u32 | 1; let seed = (miniquad::date::now() * 1000.0) as u32 | 1;
// behind the title menu: the endless bridge battle // behind the title menu: the endless bridge battle
let (game, cam) = Game::new_demo(seed); let (game, cam) = Game::new_demo(seed);
let mut app = App { game, cam, settings, seed, status: None, recorded: false, client: MatchClient::new(), ws_id: 0, match_mode: false, coop: 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_public_pending: false, editor_loading: None }; let mut app = App { game, cam, settings, seed, status: None, recorded: false, client: MatchClient::new(), ws_id: 0, match_mode: false, coop: 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(); 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); 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, minimap_drag: false, tlast: None, touch_world: false, inspect: None };
@@ -684,6 +692,16 @@ async fn main() {
app.editor = Some(editor::Editor::new(menu.campaign_doc.clone())); app.editor = Some(editor::Editor::new(menu.campaign_doc.clone()));
menu.page = Some(Page::Title); menu.page = Some(Page::Title);
} }
// an editor mission began: its briefing first
if let Some(b) = app.pending_briefing.take() {
menu.custom_briefing = b;
menu.page = Some(Page::CustomBriefing);
menu.scroll_lines(-1000);
}
// a played editor campaign is over: back into the editor
if menu.page == Some(Page::CampaignEditor) && app.editor_testing {
back_to_editor(&mut app, &mut menu, &mut r3d);
}
if app.editor.is_some() && !app.editor_testing { if app.editor.is_some() && !app.editor_testing {
editor_frame(&mut app, &mut menu, &mut cloud, &mut r3d, &gfx, &mut ui, dt, now); editor_frame(&mut app, &mut menu, &mut cloud, &mut r3d, &gfx, &mut ui, dt, now);
next_frame().await; next_frame().await;
@@ -1311,6 +1329,7 @@ async fn main() {
let _ = mission_doc; let _ = mission_doc;
let progress = campaign_doc::CampaignProgress::for_doc(&menu.campaign_doc); let progress = campaign_doc::CampaignProgress::for_doc(&menu.campaign_doc);
(app.game, app.cam) = custom_mission_game(&menu.campaign_doc, i, progress.run_seed); (app.game, app.cam) = custom_mission_game(&menu.campaign_doc, i, progress.run_seed);
app.pending_briefing = briefing_of(&menu.campaign_doc, i);
apply_game_settings(&mut app.game, &app.settings); apply_game_settings(&mut app.game, &app.settings);
app.game.coop = false; app.game.coop = false;
app.coop = false; app.coop = false;
@@ -1391,7 +1410,7 @@ async fn main() {
app.coop = false; app.coop = false;
} }
// end of a mission: next mission (won) or try again (lost) // end of a mission: next mission (won) or try again (lost)
UiAction::EndNext | UiAction::EndCampaign if app.editor_testing => back_to_editor(&mut app, &mut menu, &mut r3d), UiAction::EndNext | UiAction::EndCampaign if app.editor_testing && app.editor_test_only => back_to_editor(&mut app, &mut menu, &mut r3d),
UiAction::EndNext => { UiAction::EndNext => {
if app.custom_campaign.is_some() { if app.custom_campaign.is_some() {
let campaign = app.custom_campaign.clone(); let campaign = app.custom_campaign.clone();
@@ -1401,6 +1420,7 @@ async fn main() {
if let Some(campaign) = campaign { if let Some(campaign) = campaign {
if next < campaign.missions.len() { if next < campaign.missions.len() {
(app.game, app.cam) = custom_mission_game(&campaign, next, progress.as_ref().map_or(1, |p| p.run_seed)); (app.game, app.cam) = custom_mission_game(&campaign, next, progress.as_ref().map_or(1, |p| p.run_seed));
app.pending_briefing = briefing_of(&campaign, next);
apply_game_settings(&mut app.game, &app.settings); apply_game_settings(&mut app.game, &app.settings);
app.game.coop = false; app.game.coop = false;
app.coop = false; app.coop = false;
@@ -1424,6 +1444,7 @@ async fn main() {
} else if let (Some(campaign), Some(i)) = (campaign, app.custom_mission_index) { } else if let (Some(campaign), Some(i)) = (campaign, app.custom_mission_index) {
if i < campaign.missions.len() { if i < campaign.missions.len() {
(app.game, app.cam) = custom_mission_game(&campaign, i, progress.as_ref().map_or(1, |p| p.run_seed)); (app.game, app.cam) = custom_mission_game(&campaign, i, progress.as_ref().map_or(1, |p| p.run_seed));
app.pending_briefing = briefing_of(&campaign, i);
apply_game_settings(&mut app.game, &app.settings); apply_game_settings(&mut app.game, &app.settings);
app.game.coop = false; app.game.coop = false;
app.coop = false; app.coop = false;
@@ -1841,9 +1862,14 @@ fn editor_frame(app: &mut App, menu: &mut Menu, cloud: &mut Cloud, r3d: &mut R3d
menu.page = Some(Page::Title); menu.page = Some(Page::Title);
return; // the editor is gone return; // the editor is gone
} }
editor::EdAction::Test(i) => { editor::EdAction::Test(_) | editor::EdAction::Play => {
let (i, only) = match act {
editor::EdAction::Test(i) => (i, true),
_ => (0, false),
};
let progress = campaign_doc::CampaignProgress::for_doc(&ed.doc); let progress = campaign_doc::CampaignProgress::for_doc(&ed.doc);
(app.game, app.cam) = custom_mission_game(&ed.doc, i, progress.run_seed); (app.game, app.cam) = custom_mission_game(&ed.doc, i, progress.run_seed);
app.pending_briefing = briefing_of(&ed.doc, i);
apply_game_settings(&mut app.game, &app.settings); apply_game_settings(&mut app.game, &app.settings);
app.game.coop = false; app.game.coop = false;
app.coop = false; app.coop = false;
@@ -1853,6 +1879,7 @@ fn editor_frame(app: &mut App, menu: &mut Menu, cloud: &mut Cloud, r3d: &mut R3d
app.custom_mission_index = Some(i); app.custom_mission_index = Some(i);
app.custom_next_index = None; app.custom_next_index = None;
app.editor_testing = true; app.editor_testing = true;
app.editor_test_only = only;
menu.editor_test = true; menu.editor_test = true;
menu.page = None; menu.page = None;
ui.log.clear(); ui.log.clear();
+33 -1
View File
@@ -28,6 +28,7 @@ pub enum Page {
Campaign, // list of the campaign missions Campaign, // list of the campaign missions
CampaignEditor, // editable shareable .dccamp campaign file CampaignEditor, // editable shareable .dccamp campaign file
Briefing { mission: usize, ingame: bool }, // story and goals of a mission Briefing { mission: usize, ingame: bool }, // story and goals of a mission
CustomBriefing, // title and briefing of an editor mission
Login, // login to the savegame service (before the title) Login, // login to the savegame service (before the title)
Account, // password, logout, users (admin) Account, // password, logout, users (admin)
Match { from_title: bool }, // multiplayer lobby and match status Match { from_title: bool }, // multiplayer lobby and match status
@@ -415,6 +416,7 @@ pub struct Menu {
pub coop_mission: usize, // co-op campaign mission selected on the Match page pub coop_mission: usize, // co-op campaign mission selected on the Match page
pub in_match: bool, // a match is being played; the pause menu changes its shape pub in_match: bool, // a match is being played; the pause menu changes its shape
pub editor_test: bool, // a mission of the editor is being tested: back to the editor pub editor_test: bool, // a mission of the editor is being tested: back to the editor
pub custom_briefing: (String, String), // title and text of an editor mission's briefing
pub campaign_doc: CampaignDoc, pub campaign_doc: CampaignDoc,
pub campaign_selected: usize, pub campaign_selected: usize,
pub campaign_pending: bool, pub campaign_pending: bool,
@@ -451,6 +453,7 @@ impl Menu {
coop_mission: crate::campaign::coop_mission_indexes().first().copied().unwrap_or(0), coop_mission: crate::campaign::coop_mission_indexes().first().copied().unwrap_or(0),
in_match: false, in_match: false,
editor_test: false, editor_test: false,
custom_briefing: (String::new(), String::new()),
campaign_doc: CampaignDoc::default(), campaign_doc: CampaignDoc::default(),
campaign_selected: 0, campaign_selected: 0,
campaign_pending: false, campaign_pending: false,
@@ -489,6 +492,7 @@ impl Menu {
Some(Page::Bestiary { from_title: false, .. }) => Some(Page::Pause), Some(Page::Bestiary { from_title: false, .. }) => Some(Page::Pause),
Some(Page::Briefing { ingame: true, .. }) => Some(Page::Pause), Some(Page::Briefing { ingame: true, .. }) => Some(Page::Pause),
Some(Page::Briefing { ingame: false, .. }) => Some(Page::Campaign), Some(Page::Briefing { ingame: false, .. }) => Some(Page::Campaign),
Some(Page::CustomBriefing) => None,
Some(Page::Pause) => None, Some(Page::Pause) => None,
Some(Page::Title) => Some(Page::Title), Some(Page::Title) => Some(Page::Title),
None => Some(Page::Pause), None => Some(Page::Pause),
@@ -865,6 +869,7 @@ impl Menu {
Page::Account => self.draw_account(gfx, cloud), Page::Account => self.draw_account(gfx, cloud),
Page::Match { .. } => self.draw_match(gfx, cloud), Page::Match { .. } => self.draw_match(gfx, cloud),
Page::Briefing { mission, ingame } => self.draw_briefing(gfx, mission, ingame), Page::Briefing { mission, ingame } => self.draw_briefing(gfx, mission, ingame),
Page::CustomBriefing => self.draw_custom_briefing(gfx),
Page::Bestiary { tab, sel, level, .. } => self.draw_bestiary(gfx, tab, sel, level), Page::Bestiary { tab, sel, level, .. } => self.draw_bestiary(gfx, tab, sel, level),
Page::KeyCapture { action, .. } => { Page::KeyCapture { action, .. } => {
self.draw_settings(gfx, settings, 5); self.draw_settings(gfx, settings, 5);
@@ -1632,10 +1637,37 @@ impl Menu {
} }
// scrolling on pages with lists (mouse wheel) // scrolling on pages with lists (mouse wheel)
// the briefing of an editor mission: its text (scrolls) and a button to begin
fn draw_custom_briefing(&mut self, gfx: &Gfx) {
let (sw, sh) = (sw(), sh());
let cols = ((sw / CW()) as i32 - 2).min(64);
let rows = ((sh / CH()) as i32 - 2).min(28);
let x = grid_center(sw, cols as f32 * CW()).max(0.0);
let y = grid_center_y(sh, rows as f32 * CH()).max(0.0);
let (title, story) = self.custom_briefing.clone();
gfx.window_titled(x, y, cols, rows, S(), true, FRAME_HI, Color::new(0.05, 0.03, 0.04, 0.97), &title, FRAME_HI);
let maxc = (cols - 6) as usize;
let mut lines: Vec<String> = Vec::new();
for p in story.split('\n') {
lines.extend(wrap(p, maxc));
if wrap(p, maxc).is_empty() {
lines.push(String::new());
}
}
self.rows_visible = (rows as usize).saturating_sub(7).max(1);
self.scroll = self.scroll.min(lines.len().saturating_sub(self.rows_visible));
for (k, l) in lines.iter().skip(self.scroll).take(self.rows_visible).enumerate() {
gfx.text(l, x + CW() * 3.0, y + CH() * (2.0 + k as f32), S(), TXT);
}
let label = tr("camp.start");
let w = gfx.measure(&label, S()) + CW() * 6.0;
self.column(gfx, x + (cols as f32 * CW() - w) * 0.5, y + (rows - 4) as f32 * CH(), w, &[(Btn::Resume, label)]);
}
pub fn scrollable(&self) -> bool { pub fn scrollable(&self) -> bool {
matches!( matches!(
self.page, self.page,
Some(Page::Saves { .. }) | Some(Page::Campaign) | Some(Page::CampaignEditor) | Some(Page::Briefing { .. }) | Some(Page::Settings { tab: 5, .. }) | Some(Page::Match { .. }) | Some(Page::Account) Some(Page::Saves { .. }) | Some(Page::Campaign) | Some(Page::CampaignEditor) | Some(Page::Briefing { .. }) | Some(Page::CustomBriefing) | Some(Page::Settings { tab: 5, .. }) | Some(Page::Match { .. }) | Some(Page::Account)
) )
} }