Skip to content

Editor improvements: creature levels, help window, wave portal editing and more - #22

Open
Upabjojr wants to merge 6 commits into
tomluchowski:shaders-improvementfrom
Upabjojr:split/editor-improvements
Open

Editor improvements: creature levels, help window, wave portal editing and more#22
Upabjojr wants to merge 6 commits into
tomluchowski:shaders-improvementfrom
Upabjojr:split/editor-improvements

Conversation

@Upabjojr

@Upabjojr Upabjojr commented Aug 1, 2026

Copy link
Copy Markdown

Six commits improving the map editor:

  • Choose the level of placed creatures: L / shift-L raise and lower the level the editor gives to creatures (shown in the status bar); applies to creatures spawned from then on and to whatever the hand is holding.
  • Shift-C walks the creature classes backwards.
  • A help window listing the editor's keys, and the level being edited shown in the UI.
  • Data-driven menus are emptied before being filled, so re-entering the editor does not duplicate their entries.
  • The debug drawer is left to the render manager that owns it.
  • Wave portals are editable: the editor can change what a wave portal sends.

Note for merge order: trivial adjacent-lines conflicts with the user-data-folder PR (ODServer.cpp) and the cross-platform PR (EditorMode.cpp).


Split out of #16 so each topic can be reviewed on its own. Merging all of the split PRs reproduces the tree of #16 exactly.

🤖 Generated with Claude Code

Upabjojr and others added 6 commits August 1, 2026 10:23
The level file format has carried a creature's level since forever, and the game
reads it back, but the editor always wrote 1: it spawned every creature straight
from its definition and offered no way to say otherwise. Levelling a creature in
a map meant editing the file by hand.

L now raises the level the editor gives to creatures, shift L lowers it, both
wrapping around the thirty levels a creature can have, and the status bar shows
it next to the class the way it already shows the fullness, the seat and the
class themselves.

The level applies to the creatures spawned from then on, and also to whatever
the hand is holding when it changes, which is what makes it possible to change a
creature that is already placed: pick it up, set the level, drop it. Only the
server knows what a hand holds, so the client sends the level and lets the server
decide what it lands on. An empty hand is not a mistake, it just means the editor
is setting the level of the creatures to come.

Placing a creature also heals it. Levelling raises the maximum HP without
healing, which is what levelling up in a game should do but not what an author
placing a level 20 hero means, and the difference would have been saved into the
map as a wounded creature.

The status bar field is 20 pixels wider so that the longest class name and a two
digit level still fit within it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
(cherry picked from commit efd537c)
C cycles forward through the creature definitions and wraps around, so reaching
the class just before the current one means pressing it as many times as there
are classes. Shift C now steps back the same way shift L lowers the level.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
(cherry picked from commit 4202bd7)
…iting

Shift Y walks the seats backwards, the way shift C and shift L already walk the
creature classes and the creature levels, so GameMap gains previousSeatId next
to nextSeatId.

None of that is discoverable. The status bar names the key next to each thing it
shows, which is how anyone finds T, Y, C and L in the first place, but there is
nowhere it could say that holding shift reverses them, and nothing at all
mentions the camera keys or the point of view hotkeys. Help then Controls now
opens a window listing all of them, grouped by what they act on. The Help menu
had one entry, About, which is not connected to anything.

The editor also never said which level it was editing. A new level is given a
name in the dialog that creates it and then never shown again, and loading one
from the recently used list gives no confirmation of what was opened. The name
now sits under the menu bar. It is read every frame rather than once, because
the client only learns it when the server sends the level over, which happens
after the editor is on screen, and it changes again on saving under a new name.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
(cherry picked from commit 9b79128)
Entering the editor a second time in one session kills the game:

    CEGUI::AlreadyExistsException ... Failed to add Element named: Adventurer
    to element at: EDITORGUI/Menubar/Creatures/PopupMenu4 since an Element with
    that name is already attached.

EditorMode is built anew every time the editor is entered, and its constructor
fills the Creatures menu with one item per creature definition, the recently
used files menu and the Seats menu. The window it fills them into belongs to the
Gui and lives as long as the game does, so the second visit finds all of them
already there. CEGUI refuses a second child of the same name by throwing, and
nothing catches that before it reaches main().

Two of those three menus already had a function to empty them, used when their
contents change while the editor is running, but it was never called on the way
in. The creature list had none, so it moves out of the constructor into the same
install and uninstall pair as the others, and all three are now emptied before
being filled. GameMode has the same kind of list, of the seats in the game, and
already removes it in its destructor, which is why only the editor is affected.

Emptying detaches the old items without destroying them, which is what the
existing functions do: one of them is called from the click handler of an item
it is removing, and destroying a window in the middle of dispatching its own
event would not end well.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
(cherry picked from commit 8ec6c20)
Entering the editor a second time now segfaults on its first frame, reading
address 0x10 inside DebugDrawer::build() called from EditorMode::onFrameStarted.

RenderManager makes the debug drawer along with the scene, in createScene(),
which the ODFrameListener constructor calls once for the whole run of the game,
and destroys it in its own destructor. EditorMode's destructor deleted it too,
every time the editor was left. Ogre::Singleton clears its instance pointer as
it goes, so the second editor session found nothing there and drew through it
anyway: getSingleton() returned a null reference and build() read its manual
object, which sits at offset 16 of a DebugDrawer, from address 0x10.

The editor still clears the drawer of what it left behind, which is its own, and
checks first, since at shutdown the render manager may already have taken it.

This was hiding behind the exception fixed in the previous commit, which killed
the game earlier in the same sequence, while EditorMode was still being built.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
(cherry picked from commit 893df06)
The waves of a wave portal could only be written by hand in the level file.
They are now edited from the editor: point at a portal, press P, and a window
shows the turns between waves, the strategy, the attack range and the target
teams, along with the list of waves and the creatures of each of them.

A client is never told about the rooms of a map, only about what its tiles look
like, and the waves are not part of what a room sends anyway. So the editor
names the portal to the server by one of its tiles and asks for the waves; the
server answers with them, and sends back what the player applied. The level is
saved from the server side, so that is where the change has to land.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
(cherry picked from commit a548707)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant