485 Commits

Author SHA1 Message Date
darknight ae3530ad30 Merge pull request 'Migrate to Godot 4' (#1) from feature/godot-migration into main
Build Puzzle Quest / Validate GDScript (push) Successful in 25s
Build Puzzle Quest / Lint GDScript (push) Successful in 26s
Build Puzzle Quest / Export Windows (push) Successful in 6m19s
Build Puzzle Quest / Export Linux (push) Successful in 6m58s
Build Puzzle Quest / Export Android (push) Successful in 7m19s
Reviewed-on: #1
2026-05-17 21:32:25 +02:00
Vaillant Jeremy d7956ecdb4 chore(assets): re-import prop textures for ETC2/ASTC
Build Puzzle Quest / Validate GDScript (push) Successful in 27s
Build Puzzle Quest / Validate GDScript (pull_request) Successful in 37s
Build Puzzle Quest / Export Linux (push) Failing after 0s
Build Puzzle Quest / Export Windows (push) Failing after 0s
Build Puzzle Quest / Export Android (push) Failing after 0s
Build Puzzle Quest / Lint GDScript (push) Successful in 50s
Build Puzzle Quest / Lint GDScript (pull_request) Successful in 48s
Build Puzzle Quest / Export Linux (pull_request) Successful in 6m3s
Build Puzzle Quest / Export Windows (pull_request) Successful in 6m24s
Build Puzzle Quest / Export Android (pull_request) Successful in 7m8s
Adds the etc2 dest path + "etc2_astc" import format to every prop
texture sidecar. Generated by `godot --headless --import` after
flipping rendering/textures/vram_compression/import_etc2_astc to
true in project.godot (commit 46ab28f). Without these sidecars,
re-running --import on a clean checkout would regenerate them
anyway, but committing keeps imported_formats deterministic and
avoids spurious diffs on every CI / dev machine.

39 .import files touched, all under assets/props/. No texture
binaries changed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:19:05 +02:00
Vaillant Jeremy 4f9fa60fa0 ci(android): explicit apksigner step after Godot export
Build Puzzle Quest / Lint GDScript (push) Successful in 29s
Build Puzzle Quest / Validate GDScript (push) Successful in 35s
Build Puzzle Quest / Validate GDScript (pull_request) Successful in 39s
Build Puzzle Quest / Lint GDScript (pull_request) Successful in 23s
Build Puzzle Quest / Export Linux (push) Successful in 6m32s
Build Puzzle Quest / Export Windows (push) Successful in 6m44s
Build Puzzle Quest / Export Android (push) Successful in 7m41s
Build Puzzle Quest / Export Windows (pull_request) Successful in 5m30s
Build Puzzle Quest / Export Linux (pull_request) Successful in 6m10s
Build Puzzle Quest / Export Android (pull_request) Successful in 6m48s
Godot 4.6 produces an unsigned APK in headless mode on this
runner — verified by apksigner: "DOES NOT VERIFY, Missing
META-INF/MANIFEST.MF". The internal sign step seems to bail
silently (likely because the apksigner subprocess can't locate
java without inheriting JAVA_HOME). The export step still
reports success.

Sign the APK ourselves after the export with the same debug
keystore the workflow provisions. Idempotent if Godot ever
starts signing again; mandatory until then.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 20:59:33 +02:00
Vaillant Jeremy 46ab28f76f fix(android): enable ETC2/ASTC import + use versioned editor settings
Build Puzzle Quest / Validate GDScript (push) Successful in 25s
Build Puzzle Quest / Lint GDScript (push) Successful in 26s
Build Puzzle Quest / Lint GDScript (pull_request) Successful in 40s
Build Puzzle Quest / Validate GDScript (pull_request) Successful in 48s
Build Puzzle Quest / Export Linux (push) Successful in 6m18s
Build Puzzle Quest / Export Windows (push) Successful in 5m43s
Build Puzzle Quest / Export Android (push) Successful in 8m44s
Build Puzzle Quest / Export Linux (pull_request) Successful in 7m0s
Build Puzzle Quest / Export Windows (pull_request) Successful in 6m58s
Build Puzzle Quest / Export Android (pull_request) Successful in 5m34s
Two fixes that finally land the Android export. Verified locally
with godot 4.6.2-arch + downloaded 4.6 templates + Android SDK.

- project.godot: add
  rendering/textures/vram_compression/import_etc2_astc=true.
  Without it Godot refuses the Android export with "La plateforme
  cible nécessite une compression de texture « ETC2/ASTC »". In
  headless mode this surfaces as an *empty* configuration-errors
  block, which is what kept us stuck in CI.

- workflow: write Godot editor settings to
  editor_settings-${GODOT_VERSION}.tres (i.e. -4.6.tres on 4.6),
  not -4.tres. Godot 4.5+ uses a minor-version-suffixed settings
  file; the major-only name is ignored by 4.6, so our injected
  android_sdk_path / java_sdk_path / debug_keystore never reached
  the export plugin.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 20:35:58 +02:00
Vaillant Jeremy 918328c42a fix(android): set explicit package/unique_name for export
Build Puzzle Quest / Lint GDScript (push) Successful in 30s
Build Puzzle Quest / Validate GDScript (push) Successful in 32s
Build Puzzle Quest / Validate GDScript (pull_request) Successful in 37s
Build Puzzle Quest / Lint GDScript (pull_request) Successful in 19s
Build Puzzle Quest / Export Windows (push) Successful in 5m4s
Build Puzzle Quest / Export Android (push) Failing after 7m32s
Build Puzzle Quest / Export Linux (push) Successful in 8m21s
Build Puzzle Quest / Export Linux (pull_request) Successful in 4m35s
Build Puzzle Quest / Export Windows (pull_request) Successful in 4m34s
Build Puzzle Quest / Export Android (pull_request) Failing after 5m16s
The Android export preset relied on Godot's $genname placeholder
("org.godotengine.$genname"). With the project name "Puzzle
Quest" containing a space, Godot 4 refuses the headless export
with:

  The project name does not meet the requirement for the package
  name format and will be updated to "puzzlequest". Please
  explicitly specify the package name if needed.

Pin both Android presets (AndroidTesting, AndroidDebug) to
com.devcrea.puzzlequest — clean, follows reverse-DNS, matches
the DevCrea organization.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 20:06:40 +02:00
Vaillant Jeremy fbc2b9247a ci: comment macOS, empty Windows icon path, fix Android keystore preset
Build Puzzle Quest / Validate GDScript (push) Successful in 43s
Build Puzzle Quest / Lint GDScript (push) Successful in 32s
Build Puzzle Quest / Export Windows (pull_request) Has been skipped
Build Puzzle Quest / Export Linux (push) Failing after 0s
Build Puzzle Quest / Export Windows (push) Failing after 1s
Build Puzzle Quest / Export Android (push) Failing after 0s
Build Puzzle Quest / Validate GDScript (pull_request) Successful in 25s
Build Puzzle Quest / Lint GDScript (pull_request) Successful in 26s
Build Puzzle Quest / Export Linux (pull_request) Successful in 4m9s
Build Puzzle Quest / Export Android (pull_request) Failing after 5m2s
Three follow-ups from run #12:

- export-desktop: comment out the macOS matrix entry. The preset
  is still missing in export_presets.cfg; the entry can be
  uncommented once the macOS preset is added in the Godot editor.

- export Windows: `application/icon` referenced
  res://releases/windows/project.ico, which has never been in the
  repo (releases/windows/ holds only .keep). Godot rejected the
  export with "Invalid icon path". Cleared the field in both
  WindowsDebug and WindowsTesting presets — Godot falls back to
  its built-in icon.

- export-android: Godot validation requires all three of
  keystore/debug{,_user,_password} to be set together (or all
  empty). The keystore step only patched keystore/debug and left
  the other two empty, triggering
  "Either Debug Keystore, Debug User AND Debug Password must be
  configured OR none of them". Patch all three now.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 19:39:42 +02:00
Vaillant Jeremy 4e159b1065 ci: fix lint venv, drop artifact cache, fix Android sdkmanager pipe
Build Puzzle Quest / Lint GDScript (push) Successful in 33s
Build Puzzle Quest / Validate GDScript (pull_request) Successful in 33s
Build Puzzle Quest / Validate GDScript (push) Successful in 42s
Build Puzzle Quest / Lint GDScript (pull_request) Successful in 25s
Build Puzzle Quest / Export macOS (pull_request) Failing after 4m55s
Build Puzzle Quest / Export Linux (pull_request) Successful in 7m3s
Build Puzzle Quest / Export Windows (pull_request) Failing after 6m53s
Build Puzzle Quest / Export Android (pull_request) Failing after 6m16s
Build Puzzle Quest / Export macOS (push) Failing after 6m27s
Build Puzzle Quest / Export Linux (push) Successful in 6m44s
Build Puzzle Quest / Export Windows (push) Failing after 4m48s
Build Puzzle Quest / Export Android (push) Failing after 4m23s
Three follow-up fixes from the first non-container run (#10):

- lint: Ubuntu 24.04 / Python 3.12 enforces PEP 668, so
  `pip install --user` exits with externally-managed-environment.
  Install gdtoolkit into a throwaway venv at /tmp/gdlint-venv
  instead.

- exports: drop the .godot/ artifact cache shared between
  `validate` and the export jobs. Gitea's artifact service returns
  404 on actions/download-artifact@v3 (v3 protocol incomplete on
  this server). Each export job now runs its own
  `godot --headless --import` before exporting — costs ~30s but
  avoids the failing cross-job artifact dependency.

- export-android: `yes | sdkmanager --licenses` returned 141
  (SIGPIPE) under `set -o pipefail` because sdkmanager closes
  stdin after accepting all licenses while `yes` keeps writing.
  Feed a finite `printf 'y\n%.0s' {1..50}` instead.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 19:26:06 +02:00
Vaillant Jeremy db2460b9ee ci: drop container: for Godot jobs, install via composite action
Build Puzzle Quest / Lint GDScript (push) Failing after 15s
Build Puzzle Quest / Lint GDScript (pull_request) Failing after 16s
Build Puzzle Quest / Validate GDScript (push) Successful in 47s
Build Puzzle Quest / Validate GDScript (pull_request) Successful in 50s
Build Puzzle Quest / Export Linux (push) Failing after 6m5s
Build Puzzle Quest / Export macOS (push) Failing after 7m5s
Build Puzzle Quest / Export Windows (push) Failing after 7m14s
Build Puzzle Quest / Export Android (push) Failing after 5m45s
Build Puzzle Quest / Export Linux (pull_request) Failing after 7m10s
Build Puzzle Quest / Export macOS (pull_request) Failing after 7m24s
Build Puzzle Quest / Export Windows (pull_request) Failing after 4m7s
Build Puzzle Quest / Export Android (pull_request) Failing after 3m3s
The first Gitea Actions runs failed at actions/checkout@v4 because
barichello/godot-ci:4.6 ships without Node.js, which the JS-based
checkout action requires. Rather than chase a Godot CI image that
bundles Node, drop the container: blocks entirely: the default
catthehacker/ubuntu:act-latest runner image already has Node /
Python / git / JDK, and Godot is installed per-job from the
official GitHub release.

Pulled the install logic into a local composite action at
.gitea/actions/setup-godot/ to avoid duplicating 15 lines of wget +
unzip across the three Godot-using jobs. Inputs:
  - version  (default 4.6)
  - templates (default false — export jobs flip to true)

Other tweaks:
- export-android now puts $ANDROID_HOME under $GITHUB_WORKSPACE so
  no sudo is needed; editor_settings-4.tres interpolates that path.
- export-android writes the keystore under /tmp instead of /root
  (catthehacker runners don't run as root).

README updated: jobs table reflects the new "Tooling installed by the
job" column, prerequisites no longer mention the Docker image, and
known-issue #1 is closed out with the dated fix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 18:30:57 +02:00
Vaillant Jeremy 734b5931e9 docs(ci): record first-run failures + URL prefix fix
Adds a "Known issues from first runs" section to the workflow
README capturing what broke on 2026-05-17:

- Container jobs (validate, export-*) fail at actions/checkout@v4
  with `node: not found` because barichello/godot-ci:4.6 has no Node.
  Workflow fix pending.
- The earlier `actions/checkout` URL-prefix problem (Gitea behind
  YunoHost at /gitea/) is now resolved server-side by moving Gitea
  to the root; the note records this for future reference.
- Default-branch mismatch (Gitea = main, CLAUDE.md says dev).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 18:22:16 +02:00
Vaillant Jeremy 2d8ca9dfbb ci: trigger workflow on feature/godot-migration too
Build Puzzle Quest / Lint GDScript (push) Failing after 28s
Build Puzzle Quest / Export Linux (push) Has been cancelled
Build Puzzle Quest / Export macOS (push) Has been cancelled
Build Puzzle Quest / Export Windows (push) Has been cancelled
Build Puzzle Quest / Export Android (push) Has been cancelled
Build Puzzle Quest / Validate GDScript (push) Has been cancelled
Build Puzzle Quest / Lint GDScript (pull_request) Failing after 21s
Build Puzzle Quest / Export macOS (pull_request) Has been skipped
Build Puzzle Quest / Export Windows (pull_request) Has been skipped
Build Puzzle Quest / Validate GDScript (pull_request) Failing after 4m14s
Build Puzzle Quest / Export Linux (pull_request) Has been skipped
Build Puzzle Quest / Export Android (pull_request) Has been skipped
Temporary addition so the workflow can run before the branch is
merged into dev. Remove this branch from the push: list once dev
has the workflow.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 16:38:19 +02:00
Vaillant Jeremy 238fccef95 Fix gdlint findings in Global / Database / Levels
- Global.gd: move @onready var animation below the regular vars
  (gdlint class-definitions-order expects onready vars after
  public/private vars).
- Database.gd::DB: move the three _*_PROPS constants above the vars
  (constants come before vars in a class body).
- Levels.gd:_search_button_to_use: drop the elif after a branch
  that returns (no-elif-return).
- Levels.gd:_gyroscope_changed_{down,up}: continuation lines of the
  multi-line return mixed two tabs + three spaces; normalised to
  pure tabs.

No semantic change: @onready is property-level so source ordering
doesn't affect init; elif after a return is equivalent to if; the
continuation indent is cosmetic.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 14:48:20 +02:00
Vaillant Jeremy e883d662f2 Add gdlint job + gdlintrc to Gitea CI
Lints scripts/, db/, scenes/ via gdtoolkit==4.* on ubuntu-latest
(Python, no Godot needed), in parallel with the validate job.
addons/ (third-party LOD plugin) and developers/ (sandbox) are
left out. Non-blocking for now: the export jobs still only need
validate, so a lint regression won't break builds while the
Godot-3 leftover code is being cleaned up.

gdlintrc bumps max-line-length from 100 to 140 because Godot
$-style node paths and typed signatures routinely push past 100
without that being a real readability problem.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 14:48:13 +02:00
Vaillant Jeremy 410c135870 Replace Drone CI with Gitea Actions workflow
Drone server is gone; CI now lives in .gitea/workflows/build.yml.
Three jobs: GDScript validation (godot --headless --import + error
grep), desktop matrix (Windows / Linux / macOS), and Android (JDK 17
+ SDK installed at runtime, keystore from ANDROID_KEYSTORE_BASE64
secret or generated). Build only — Butler / itch.io deploy not wired.

Notes in .gitea/workflows/README.md cover the Godot-4 pre-reqs
(macOS preset to add, Linux/X11Debug likely renamed on first 4.x
save, Docker image tag) and how to plug Butler back in later.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 12:36:34 +02:00
Vaillant Jeremy d61a0ffcb0 Add developers/.gdignore; let Godot 4 canonicalise saved scenes
The developers/aurelien sandbox scenes still reference legacy non-LOD
mesh paths (sm_book.mesh, sm_candlestick.mesh, ...) that don't exist
anymore — the production scenes were migrated to *_lod0/1/2.mesh.
Godot's full-project file scanner reads every .tscn at editor open
and emits 'Cannot open file' errors for each broken ext_resource,
even for scenes that the game never loads.

Mark developers/ as out-of-scope for Godot's filesystem walker with
a .gdignore at its root. The .import / .uid sidecars Godot had
generated for files inside (CheckLightmap.exr.import,
CheckLightmap.gd.uid) are auto-removed by the editor since they are
now orphaned metadata — only the source files (.tscn, .gd, .exr,
.lmbake) remain. Re-enabling the sandbox later just means deleting
the .gdignore; Godot will regenerate the sidecars.

The other diffs in this commit are Godot 4 canonicalising whatever
.tscn / .tres files were touched in the editor session that ran the
LightmapGI bake attempt: ext_resource uid= attributes added, format
bumped 2 -> 3, property order normalised. No behavioural change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 22:24:19 +02:00
Vaillant Jeremy 6146d84b87 Fix Levels.gd type inference + Database integer-division warning + brighten scenes
- scenes/levels/Levels.gd: replace 'var level := Global.database
  .level_by_index(...)' with explicit 'var level: LevelEntry = ...'.
  Global.database is typed RefCounted so the parser can't see DB's
  return types through the walrus operator. Two callsites.
- scripts/Database.gd: annotate the two 'range(data.size() / W)'
  loops with @warning_ignore('integer_division'). The division is
  intentional (row count = bytes / row width); Godot 4 warns by
  default in case the slash was a typo.
- env: ambient_light_energy 0.4 -> 1.0 in WarCraft.tscn, Home.tscn
  and env_warcraft.tres. 0.4 left the floor pitch-black; 1.0 is a
  compromise between the original 1.55 (oversaturated) and this.
  Re-baking the lightmap in the editor is still the right fix —
  this commit just keeps the scene playable in the meantime.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 22:02:59 +02:00
Vaillant Jeremy c17769246f Replace M* table-wrapper classes with typed Resources; add type hints
Two related cleanups from the best-practice audit:

Task 3 — typed Resources instead of MBase / MScene / MLevel / MSetting

The old model classes wrapped the godot_db_manager Table API: each row
read went through table.get_data_at_row_idx(int), Cell.get_data(),
and 'as int' / 'as String' casts that don't actually parse anything
in Godot 4. m_value, m_lock, m_label, ... members shadowed the cell
indirection. Setters round-tripped through table.edit_data() +
Global.database.save_db(). That's a lot of plumbing for what is, in
the end, three flat tables of static strings.

Introduce three @export-typed Resources:
  db/scene_entry.gd     class_name SceneEntry
  db/level_entry.gd     class_name LevelEntry
  db/settings_data.gd   class_name SettingsData

Rewrite scripts/Database.gd so Database.DB holds:
  settings: SettingsData
  levels:   Array[LevelEntry]
  scenes:   Array[SceneEntry]

Build them once at startup from ahog.json, and serialise back to the
same JSON shape on save() so existing progress files keep working.
LevelEntry carries its own object_to_find / object_finding / reset
methods (talking to Global.database for cross-table lookups), and
SceneEntry carries its own mesh_path / audio_sound. Per-scene
dissolve state (value, tick_reference, dissolved) lives on
SceneEntry as non-exported runtime fields.

Delete db/MBase.gd / db/MScene.gd / db/MLevel.gd / db/MSetting.gd.

Update consumers:
- scripts/Setting.gd: read/write Global.database.settings directly,
  call Global.database.save() after each setter.
- scenes/levels/Levels.gd: iterate Global.database.scenes_for_level(
  current_scene_int) instead of mscene.new(i) for every row; scene
  state reads (scene.lock, scene.mesh, scene.counter, ...) replace
  scene.lock() / scene.mesh() / scene.counter() method calls; runtime
  dissolve state lives on the SceneEntry instance instead of mutable
  m_value / m_tick_reference members on MScene; 'dissolved' flag
  replaces set_mesh(null) signalling.
- scenes/UI/choose_scenes/ChooseScene.gd: iterate Global.database
  .levels; level.name / level.thumb property access in place of
  level.name() / level.thumbnail(). configure_reset() loses its
  redundant index argument (LevelEntry knows its own index).
- scripts/event.gd: _on_reset_level signature now takes LevelEntry,
  reset path drops index forwarding.

Task 2 — type hints across the remaining scripts

scripts/Global.gd, scenes/Main.gd, scenes/UI/ending/Ending.gd,
scenes/UI/loading/Loading.gd, scenes/UI/settings/Settings.gd: add
typed parameters and -> return annotations. current_scene_int is now
'int = -1' (sentinel) so callers don't fall into Variant comparisons;
event.gd:_on_reset_level resets it to -1 instead of null.
Settings.gd no longer wraps button_pressed in int() before passing to
the now-typed bool setters.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 21:58:11 +02:00
Vaillant Jeremy 60d9f614ee Replace Event + GlobalAnimation autoloads with class_name + static funcs
Two of the five autoloads were stateless helper bundles, not the
persistent application-wide systems that the Godot 4 best-practice
guide reserves autoload slots for. Convert them to plain classes with
all-static methods so they no longer need a Node living under /root.

- scripts/Animation.gd -> scripts/game_animation.gd (renamed:
  conflict with the built-in Animation class; the autoload sidestepped
  it by being called GlobalAnimation). class_name GameAnimation,
  every helper static. The dissolve tween now captures its target
  material in a lambda closure, eliminating the current_material
  member that the autoload kept as shared mutable state.
- scripts/Event.gd -> scripts/event.gd, class_name Event, every
  handler static. Added Event.level_pressed(name) -> Callable for the
  one place ChooseScene needed dynamic lookup of a per-level handler
  (replaces the old _build_method('_on_' + name + '_pressed') +
  Callable(autoload, string) reflection trick with an explicit match).

Updated call sites:
- scripts/Global.gd: animation.connect('animation_started',
  Callable(Event, '...')) -> animation.animation_started.connect(
  Event._loading_is_started). Same for animation_finished.
- scenes/levels/Levels.gd: GlobalAnimation.* -> GameAnimation.*;
  Quit/TextureButton.connect('pressed', Callable(Event, '...')) ->
  pressed.connect(Event._on_main_scene_pressed).
- scenes/UI/choose_scenes/ChooseScene.gd: per-level button connects
  go through Event.level_pressed(); reset button's bound callable now
  reads Event._on_reset_level.bind(...); cleanup no longer relies on
  is_connected with an unbound Callable (which would never match a
  bound one anyway) -- iterates reset.pressed.get_connections()
  instead. Drop the now-dead _build_method helper.

Also: organise scripts/ by promoting the one-shot migration helpers
(migrate_shaders, migrate_misc, resave_scenes, devisualize_shaders,
find_visualshaders) into scripts/migration/. They are not part of
the runtime and should not be browsable next to the autoloads.

Autoload count goes 5 -> 3 (Loading, Global, Setting remain --
Setting will move to a Resource in a later refactor).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 21:50:00 +02:00
Vaillant Jeremy ca67fc6ec3 Convert all VisualShaders to plain Shaders; clean editor noise
Godot 4 emits two unavoidable warnings every time it reconstructs a
Godot-3-authored VisualShader graph: 'graph_offset property is
deprecated' (the editor's pan position, removed in 4.x) and
'connect_nodes_forced: Index p_from_port = 1 is out of bounds'
(node-graph ports that no longer line up). The compiled GLSL inside
each ShaderMaterial is correct; only the graph reconstruction is
broken.

scripts/devisualize_shaders.gd walks every .material, .tres, and
.mesh under res:// and replaces ShaderMaterial.shader from
VisualShader to a plain Shader carrying the same .code. 15 materials
converted (font outline, dissolve, color tints, book/candle/godet/
growler/parchment/rock-floor/stool/table). Godot now loads the
compiled shader directly with no graph reconstruction → both
warnings gone, rendering identical.

Also:
- scripts/resave_scenes.gd: load + re-save every .tscn so inline
  ArrayMesh sub-resources (notably WarCraft.tscn::17, the baked
  floor) move from Godot-3 PoolByteArray to Godot-4 PackedByteArray
  surface format. Silences 'Mesh uses old surface format'.
- scripts/find_visualshaders.gd: companion audit tool that lists
  every Resource still backed by a VisualShader. Useful if new
  legacy materials get added.
- Drop the now-orphan inline VisualShader / ShaderMaterial sub-
  resources (id 1..17) from Summary.tscn. The PanelWood lost its
  screen-blend tint material; a plain Panel renders fine and the
  effect can be re-authored as a hand-written shader if wanted.
- Add releases/.gdignore and tighten .gitignore so Godot stops
  warning 'Detected another project.godot at res://releases'. The
  releases/ directory has its own placeholder project.godot which
  Godot would otherwise flag at every editor open.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 21:42:28 +02:00
Vaillant Jeremy 81e6ceb003 Silence Godot 4 editor warnings (debugger)
Address every warning that surfaced in the running game's debugger:

- Drop deprecated 'graph_offset = Vector2(...)' lines from the three
  in-tree VisualShader resources (red.tres, green.tres,
  Summary.tscn). The property is editor-only graph pan, ignored at
  runtime but warns at load.
- Add android/.gdignore so Godot stops scanning the build template
  copies of red.tres/green.tres (which still had graph_offset). Tighten
  .gitignore to keep tracking the .gdignore marker only.
- Drop the broken 'nodes/fragment/connections = ...' line from the
  inline VisualShader in Summary.tscn — connections referenced
  out-of-bounds ports (e.g. port 1 on a 1-output node). The
  pre-compiled 'code = ...' string is kept so rendering is unaffected.
- Drop the orphaned 'ext_resource WarCraft.lmbake' from WarCraft.tscn:
  the LightmapGI node no longer references it but Godot still loaded
  the (Godot-3-format) blob from the ext_resource declaration alone,
  triggering '(p_data.size() % 4) != 0'.
- Animation tracks: SlideReset (Template.tscn), BorderAnim
  (Loading.tscn), and ObjectFindAll (ListObjects.tscn) each had a
  bezier track with empty PackedFloat32Array keys, which
  AnimationMixer rejects in Godot 4. Drop the empty x track in each
  (the y track held the actual motion).
- Re-save 57 .mesh files via scripts/migrate_misc.gd so the surface
  format is the current Godot 4 variant. sm_stackgold.mesh in
  particular triggered the deprecation warning every load.

GDScript: rename function parameters and locals that shadowed
Node.name / Node.value in:
- db/MScene.gd (set_lock, set_mesh, set_tick_reference, set_value)
- scripts/Setting.gd untouched (no shadow, false positive earlier)
- scenes/UI/choose_scenes/ChooseScene.gd (_load_scene, _build_path,
  _build_method)
- scenes/levels/Levels.gd (_create_animation_slide,
  _create_animation_warning, _add_animation_to_player,
  _create_button_info, _node_object_list)

lod plugin: Godot 4 added 'lod_bias' as a native property on
VisualInstance3D, which collided with the plugin's 'lod_bias' member
across all five lod_*.gd files. Rename to 'lod_distance_bias' so the
scripts parse again. Also drop Light3D.shadow_color writes in
lod_omni_light.gd and lod_spot_light.gd — that property was removed
in Godot 4, so the related shadow_value computation became dead code.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 21:28:22 +02:00
Vaillant Jeremy 601bc649dd Center menu button labels: clear stale Main.tscn overrides
Summary.tscn was correctly set up (Label anchored to full button rect,
horizontal/vertical_alignment = 1). But Main.tscn — which instances
Summary.tscn as UI_summary — had per-Label overrides that reset the
anchors back to 0 and shrunk the Label rect to 1x23 px (legacy from
Godot 3 where margin-based positioning was the default), making the
text render in the top-left 1 px corner.

Drop the layout_mode=0 / anchor_right=0 / anchor_bottom=0 / offset_*
overrides on each ButtonPuzzle/Setting/Credits/Quit Label so they
inherit Summary.tscn's full-rect anchors and the centered alignment
becomes visible.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 21:08:54 +02:00
Vaillant Jeremy 5148599e33 Fix Summary.tscn vertical separator: stretch_mode 2 -> 1
In Godot 3 the TextureRect stretch_mode enum included a deprecated
"Scale on Expand" at value 0, so Tile=2. Godot 4 dropped that value
and shifted everything down: Tile is now 1. The convert-3to4 tool
does not remap enum values, so the separator at the right edge of
the menu kept Godot 3's Tile=2, which Godot 4 reads as Keep — the
texture rendered once at natural size at the top instead of tiling
down the full menu height.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 20:57:38 +02:00
Vaillant Jeremy 6f3f8b8f64 Wire up UI in Godot 4: fonts, translations, layout, fog, shadow
Discovered while playtesting the migrated build. Each fix has a
specific Godot-3-to-4 cause that the --convert-3to4 tool did not catch.

Fonts:
- Replace 4 .tres font wrappers (MKX_Base, kirsty_base/medium/title)
  with FontVariation pointing at the .otf/.ttf source. Godot 3
  DynamicFont with size= and font_data= is invalid in Godot 4 (those
  properties don't exist on FontFile).
- Apply size 46 via theme_override_font_sizes/font_size on the 5
  Labels that used kirsty_title.tres (LabelLoading + 4 in Summary).
- Drop the broken VisualShader text_outline.material from the 4
  Labels in Summary — Index p_from_port errors in Godot 4 meant
  COLOR was never written, so text rendered invisible.
- Migrate VisualShader nodes inside text_outline.material (compressed
  asset; updated by the inspect/migrate scripts).

Translations:
- Move project.godot section from [locale] (Godot 3) to
  [internationalization] with locale/translations=... (Godot 4). The
  old section was silently ignored so tr() returned the raw msgid.
- Adjust Setting.translate_int_to_locale to return "en"/"fr" to
  match what the .po files declare (was "en_GB"/"fr_FR", which Godot
  3 fell back from automatically but Godot 4 does not).

Label alignment (Godot 3 names not auto-renamed):
- align -> horizontal_alignment, valign -> vertical_alignment across
  9 .tscn files.

Background / Loading / ChooseScene layout:
- Rewrite Background.tscn from a VisualShader-textured Panel to a
  plain TextureRect (the visual shader connection ports went out of
  bounds in Godot 4, leaving the panel grey on scene reload).
- Set layout_mode=1 + anchors_preset=15 on BackgroundPicture
  instances in Main.tscn and Loading.tscn — Godot 4 inheritance no
  longer applies the .tscn-root's anchors to an instanced child
  unless layout_mode is set to Anchors mode explicitly.
- Replace scroll_horizontal_enabled (Godot 3) with
  horizontal_scroll_mode/vertical_scroll_mode (Godot 4) on
  ChooseScene's ScrollContainer.
- Add theme_override_styles/panel = StyleBoxEmpty on the
  ScrollContainer (Godot 4 ScrollContainer ships a default dark
  panel style that Godot 3 did not).
- Hide BackgroundTile in Template.tscn — it points at
  UI-level-btn-shadow.png (228x228, 83% opaque black) which used to
  render at natural size in Godot 3 but is stretched to fill the
  456px rect in Godot 4, leaving a big black square below each
  thumbnail. The proper drop-shadow needs a shader or 9-patch.
- TextureRect.expand=true (Godot 3) -> expand_mode=1 (Godot 4) on
  ThumbnailLevel and TopPart's content rects.

Lighting:
- background_mode 3 (which used to mean Sky in Godot 3) -> 2 (Sky in
  Godot 4; 3 is now Canvas, producing a black background).
- background_sky -> sky, background_energy -> background_energy_multiplier,
  fog_color -> fog_light_color, fog_height_min -> fog_height; drop
  fog_height_enabled / fog_height_max / fog_height_curve /
  dof_blur_far_distance (no longer exist).
- Add fog_mode = 1 so Godot 4 uses fog_depth_* instead of the new
  default fog_density-based exponential fog (which rendered as a
  thick white cloud).
- ambient_light_energy 1.55 -> 0.4 — the new pipeline interprets
  the value much more strongly so 1.55 produced a saturated pink scene.
- Remove the light_data = ExtResource(41) reference to
  WarCraft.lmbake — Godot 3 baked lightmap binary format is
  incompatible with Godot 4. Re-bake in editor when ready.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 20:55:47 +02:00
Vaillant Jeremy 21176546eb Add dagger PBR textures, font import sidecars, migrate_shaders uid
- assets/props/dagger/dagger_Dagger_{BC,NM}.png + dagger_dagger_{E,ORM}.png:
  complete PBR texture set for the dagger prop.
- assets/fonts/MKX Title.ttf.import + kirsty/*.otf.import: Godot 4 import
  metadata sidecars for fonts whose source files were already tracked.
- scripts/migrate_shaders.gd.uid: UID sidecar missed in the previous
  migration commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 19:44:56 +02:00
Vaillant Jeremy 4d5db7bb61 Make Main, Settings, ChooseScene, and gameplay run in Godot 4.6
Catch-all commit for everything the --convert-3to4 tool missed during a
manual playtest of the game. All errors raised by clicking through Main
-> Puzzles -> level were fixed.

GDScript:
- PackedScene.instance() -> instantiate() (ChooseScene.gd)
- String(x) constructor doesn't exist -> str(x) (MBase, MScene,
  MLevel, Animation, Levels)
- 'x as int/String/bool' doesn't parse strings -> explicit
  int()/str()/bool(int()) (MScene, MLevel, MSetting)
- BaseButton.pressed (property) -> button_pressed; set_pressed() ->
  direct assignment (Settings.gd)
- AnimationPlayer.add_animation() removed -> go through
  AnimationLibrary (Levels.gd)
- PhysicsDirectSpaceState3D.intersect_ray(from, to, ...) ->
  PhysicsRayQueryParameters3D.create() (Levels.gd)
- @export with type-hint-in-comment ('# (String, ...)') -> explicit
  @export_enum (candle.gd)
- Get effective material with get_active_material() instead of
  get_surface_override_material(), with null guard (Levels.gd)
- get_node() -> get_node_or_null() so missing items from ahog.json
  (e.g. sm_super_dager in Home) don't crash (Levels.gd)

Scenes/resources:
- Remove 14 Tween nodes from WarCraft.tscn — Tween is no longer a
  Node in Godot 4. Rewrite Animation.start_dissolve to use
  create_tween().tween_method().
- Rename property material/N -> surface_material_override/N in every
  .tscn (10 files) — Godot 3 -> 4 rename that --convert-3to4 missed.
  Without this, MeshInstance3D.get_active_material(0) returned the
  glTF-imported StandardMaterial3D instead of the project's custom
  dissolve ShaderMaterial.

Shaders:
- One-shot scripts/migrate_shaders.gd walks every .material under
  assets/ and fixes Godot 3 -> 4 shader code in-place. Fixed 17
  materials: depth_draw_alpha_prepass -> depth_prepass_alpha,
  hint_color -> source_color, NORMALMAP -> NORMAL_MAP.

Result: Main, Settings, ChooseScene, and the WarCraft level all run
without script or shader errors. Remaining noise is non-blocking
(visual_shader graph in text_outline.material, baked lightmap binary
format from Godot 3, and empty animation tracks).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 19:40:03 +02:00
Vaillant Jeremy 770434482d Fix Setting.gd Vector2/Window API, re-import all assets for Godot 4
- apply_resolution: Vector2 strings -> Vector2i(int, int); use
  Window.content_scale_size instead of removed
  Viewport.set_size_2d_override variants.
- Re-import 162 assets to Godot 4 format (.godot/imported/ now,
  .stex -> .ctex, FontFile, CompressedTexture2D, etc.).
- Add .uid sidecars Godot 4 generates next to every script.
- Ignore .godot/ cache and android/ template directories.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 19:26:10 +02:00
Vaillant Jeremy ec906117bb Replace godot_db_manager plugin with native DB, port lod plugin
godot_db_manager was incompatible with Godot 4 (used WindowDialog, Tabs,
PopupPanel which were all removed). Replace with a minimal Database.gd
that parses the same ahog.json format and exposes the same surface API
(get_table_by_name, get_data_at_row_idx, edit_data, save_db, etc.) used
by the M* model classes — no changes needed in MBase/MScene/MLevel/MSetting.

Also port the lod plugin: fix class_name syntax (Godot 4 uses @icon
separately from class_name extends) and Particles -> GPUParticles3D.

Rewrite Global.gd async scene loading: the convert-3to4 tool mapped
load_interactive -> load_threaded_request but those have different APIs
(stage count, poll vs. status enum). Reimplement using the new
load_threaded_get_status / load_threaded_get pair.

Clean project.godot: drop the old _global_script_classes table (Godot 4
uses inline class_name declarations), remove gddb_* autoloads, and
remove the godot_db_manager entry from editor_plugins.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 19:21:09 +02:00
Vaillant Jeremy 01ea3af253 Run godot --convert-3to4 (automated conversion)
Apply Godot 4.6 automated conversion: renames Spatial.translate->position,
margin_*->offset_*, tool->@tool, .empty()->.is_empty(), DynamicFont->FontFile,
onready->@onready, export()->@export, and many more.

127 files changed by the tool. Manual fixes still required for:
 - godot_db_manager plugin (incompatible APIs: WindowDialog, Tabs, etc.)
 - lod plugin (Spatial -> Node3D renames)
 - ResourceLoader.load_interactive removed -> load_threaded_request
 - OS.set_window_fullscreen removed -> DisplayServer
 - Viewport.set_size_override removed

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 19:18:27 +02:00
Vaillant Jeremy efa35a444a Migrate to Godot 3.5 LTS
Open project with Godot 3.5.3 to update project.godot to the new
config format (adds physical_scancode field to InputEventKey).
Intermediate step before --convert-3to4 to Godot 4.x.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 19:16:24 +02:00
Vaillant jeremy 1b09871881 Remove volume 2021-08-01 14:48:46 +02:00
Vaillant jeremy 71cce49de9 Add missing volume entry 2021-08-01 14:41:26 +02:00
Vaillant jeremy 7f143ea725 Push only if bin has changed 2021-08-01 14:38:54 +02:00
Vaillant jeremy 1d0c8ac2f2 Ignore .keep files 2021-08-01 14:36:16 +02:00
Vaillant jeremy 842ed4bb98 Replace environment name with string directly 2021-08-01 14:33:35 +02:00
Vaillant jeremy bee1de6a3e Ignore signed apk 2021-08-01 14:18:15 +02:00
Vaillant jeremy 50fc89a9e8 Fix path volumes 2021-08-01 14:09:19 +02:00
Vaillant jeremy d3b540a31f Change image docker for android CI 2021-08-01 13:58:17 +02:00
Vaillant jeremy 53925fe8be Change name export 2021-08-01 13:55:54 +02:00
Vaillant jeremy f1ea980ab1 Add BDD & exclude folder testing scenes 2021-08-01 13:50:37 +02:00
Vaillant jeremy 9f81936398 Configure new export 2021-08-01 13:37:49 +02:00
Vaillant jeremy c8c8c492cd Add 2 pipes (Android/Linux) 2021-08-01 13:37:31 +02:00
Vaillant jeremy b61a3079cb Use direct value instead env secret 2021-08-01 13:23:39 +02:00
Vaillant jeremy 6fe916593c Remove echo command 2021-08-01 13:19:37 +02:00
Vaillant jeremy 6f5bb1c925 FUCK 6 !! 2021-08-01 13:18:01 +02:00
Vaillant jeremy 9a91c406b8 FUCK 5 !! 2021-08-01 13:15:11 +02:00
Vaillant jeremy d76b00e235 FUCK 4 !! 2021-08-01 13:14:36 +02:00
Vaillant jeremy 1f2b24ffba FUCK 3 !! 2021-08-01 13:13:37 +02:00
Vaillant jeremy 2400ce791f FUCK 2 !! 2021-08-01 13:13:08 +02:00
Vaillant jeremy fd384bec25 FUCK !! 2021-08-01 13:12:18 +02:00
Vaillant jeremy 242e2a57ae Try export api key 2021-08-01 13:11:26 +02:00
Vaillant jeremy 8f1c210c9a Revert var env ... 2021-08-01 13:00:11 +02:00